Merge branch 'release-4-5-patches'
authorCarsten Kutzner <ckutzne@gwdg.de>
Tue, 4 Jan 2011 17:31:50 +0000 (18:31 +0100)
committerCarsten Kutzner <ckutzne@gwdg.de>
Tue, 4 Jan 2011 17:31:50 +0000 (18:31 +0100)
2789 files changed:
CMakeLists.txt
README
admin/.cvsignore [deleted file]
cmake/FindGMock.cmake [new file with mode: 0644]
cmake/FindGTest.cmake [new file with mode: 0644]
cmake/ThreadMPI.cmake
include/.cvsignore [deleted file]
include/CMakeLists.txt [deleted file]
include/Makefile.am [deleted file]
include/centerofmass.h [deleted file]
include/gmx_statistics.h [deleted file]
include/gmx_wallcycle.h [deleted file]
include/gmxfio.h [deleted file]
include/indexutil.h [deleted file]
include/mdrun.h [deleted file]
include/mpelogging.h [deleted file]
include/names.h [deleted file]
include/nbsearch.h [deleted file]
include/physics.h [deleted file]
include/poscalc.h [deleted file]
include/position.h [deleted file]
include/selection.h [deleted file]
include/selmethod.h [deleted file]
include/selparam.h [deleted file]
include/selvalue.h [deleted file]
include/string2.h [deleted file]
include/thread_mpi/CMakeLists.txt [deleted file]
include/thread_mpi/Makefile.am [deleted file]
include/thread_mpi/atomic/CMakeLists.txt [deleted file]
include/thread_mpi/atomic/Makefile.am [deleted file]
include/trajana.h [deleted file]
include/types/.cvsignore [deleted file]
include/types/Makefile.am [deleted file]
include/types/enums.h [deleted file]
include/types/inputrec.h [deleted file]
include/vec.h [deleted file]
man/.cvsignore [deleted file]
man/man1/.cvsignore [deleted file]
scripts/.cvsignore [deleted file]
scripts/.gitignore [new file with mode: 0644]
share/.cvsignore [deleted file]
share/html/.cvsignore [deleted file]
share/html/images/.cvsignore [deleted file]
share/html/online/.cvsignore [deleted file]
share/template/.cvsignore [deleted file]
share/template/.gitignore [new file with mode: 0644]
share/top/.cvsignore [deleted file]
share/top/gurgle.dat
share/tutor/.cvsignore [deleted file]
share/tutor/gmxdemo/.cvsignore [deleted file]
share/tutor/methanol/.cvsignore [deleted file]
share/tutor/mixed/.cvsignore [deleted file]
share/tutor/nmr1/.cvsignore [deleted file]
share/tutor/nmr2/.cvsignore [deleted file]
share/tutor/speptide/.cvsignore [deleted file]
share/tutor/water/.cvsignore [deleted file]
src/.cvsignore [deleted file]
src/CMakeLists.txt
src/config.h.cmakein
src/contrib/.cvsignore [deleted file]
src/gmxlib/.cvsignore [deleted file]
src/gmxlib/.gitignore [deleted file]
src/gmxlib/CMakeLists.txt [deleted file]
src/gmxlib/Makefile.am [deleted file]
src/gmxlib/gmx_blas/.gitignore [deleted file]
src/gmxlib/gmx_blas/Makefile.am [deleted file]
src/gmxlib/gmx_lapack/Makefile.am [deleted file]
src/gmxlib/libgmx.pc.cmakein [deleted file]
src/gmxlib/libgmx.pc.in [deleted file]
src/gmxlib/mvdata.c [deleted file]
src/gmxlib/names.c [deleted file]
src/gmxlib/network.c [deleted file]
src/gmxlib/nonbonded/Makefile.am [deleted file]
src/gmxlib/nonbonded/nb_kernel_x86_64_sse/.gitignore [deleted file]
src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/.gitignore [deleted file]
src/gmxlib/selection/.cvsignore [deleted file]
src/gmxlib/selection/.gitignore [deleted file]
src/gmxlib/selection/Makefile.am [deleted file]
src/gmxlib/selection/compiler.c [deleted file]
src/gmxlib/selection/evaluate.c [deleted file]
src/gmxlib/selection/evaluate.h [deleted file]
src/gmxlib/selection/keywords.h [deleted file]
src/gmxlib/selection/mempool.c [deleted file]
src/gmxlib/selection/mempool.h [deleted file]
src/gmxlib/selection/params.c [deleted file]
src/gmxlib/selection/parser.c [deleted file]
src/gmxlib/selection/parser.h [deleted file]
src/gmxlib/selection/parser.y [deleted file]
src/gmxlib/selection/parsetree.c [deleted file]
src/gmxlib/selection/parsetree.h [deleted file]
src/gmxlib/selection/regenerate_parser.sh [deleted file]
src/gmxlib/selection/scanner.c [deleted file]
src/gmxlib/selection/scanner.h [deleted file]
src/gmxlib/selection/scanner.l [deleted file]
src/gmxlib/selection/scanner_flex.h [deleted file]
src/gmxlib/selection/scanner_internal.c [deleted file]
src/gmxlib/selection/scanner_internal.h [deleted file]
src/gmxlib/selection/selcollection.h [deleted file]
src/gmxlib/selection/selection.c [deleted file]
src/gmxlib/selection/selelem.c [deleted file]
src/gmxlib/selection/selelem.h [deleted file]
src/gmxlib/selection/selhelp.c [deleted file]
src/gmxlib/selection/selhelp.h [deleted file]
src/gmxlib/selection/selmethod.c [deleted file]
src/gmxlib/selection/selvalue.c [deleted file]
src/gmxlib/selection/sm_compare.c [deleted file]
src/gmxlib/selection/sm_distance.c [deleted file]
src/gmxlib/selection/sm_insolidangle.c [deleted file]
src/gmxlib/selection/sm_keywords.c [deleted file]
src/gmxlib/selection/sm_merge.c [deleted file]
src/gmxlib/selection/sm_permute.c [deleted file]
src/gmxlib/selection/sm_position.c [deleted file]
src/gmxlib/selection/sm_same.c [deleted file]
src/gmxlib/selection/sm_simple.c [deleted file]
src/gmxlib/selection/symrec.c [deleted file]
src/gmxlib/selection/symrec.h [deleted file]
src/gmxlib/selection/test_selection.c [deleted file]
src/gmxlib/statistics/.gitignore [deleted file]
src/gmxlib/statistics/Makefile.am [deleted file]
src/gmxlib/statistics/gmx_statistics.c [deleted file]
src/gmxlib/string2.c [deleted file]
src/gmxlib/thread_mpi/Makefile.am [deleted file]
src/gmxlib/tpxio.c [deleted file]
src/gmxlib/trajana/.cvsignore [deleted file]
src/gmxlib/trajana/.gitignore [deleted file]
src/gmxlib/trajana/Makefile.am [deleted file]
src/gmxlib/trajana/centerofmass.c [deleted file]
src/gmxlib/trajana/indexutil.c [deleted file]
src/gmxlib/trajana/nbsearch.c [deleted file]
src/gmxlib/trajana/poscalc.c [deleted file]
src/gmxlib/trajana/position.c [deleted file]
src/gmxlib/trajana/trajana.c [deleted file]
src/gmxlib/txtdump.c [deleted file]
src/gmxlib/version.c.cmakein [deleted file]
src/gromacs/CMakeLists.txt [new file with mode: 0644]
src/gromacs/analysisdata.h [new file with mode: 0644]
src/gromacs/analysisdata/CMakeLists.txt [new file with mode: 0644]
src/gromacs/analysisdata/abstractdata-impl.h [new file with mode: 0644]
src/gromacs/analysisdata/abstractdata.cpp [new file with mode: 0644]
src/gromacs/analysisdata/abstractdata.h [new file with mode: 0644]
src/gromacs/analysisdata/analysisdata-impl.h [new file with mode: 0644]
src/gromacs/analysisdata/analysisdata.cpp [new file with mode: 0644]
src/gromacs/analysisdata/analysisdata.h [new file with mode: 0644]
src/gromacs/analysisdata/arraydata.cpp [new file with mode: 0644]
src/gromacs/analysisdata/arraydata.h [new file with mode: 0644]
src/gromacs/analysisdata/datamodule.h [new file with mode: 0644]
src/gromacs/analysisdata/dataproxy.cpp [new file with mode: 0644]
src/gromacs/analysisdata/dataproxy.h [new file with mode: 0644]
src/gromacs/analysisdata/modules/CMakeLists.txt [new file with mode: 0644]
src/gromacs/analysisdata/modules/average.cpp [new file with mode: 0644]
src/gromacs/analysisdata/modules/average.h [new file with mode: 0644]
src/gromacs/analysisdata/modules/displacement-impl.h [new file with mode: 0644]
src/gromacs/analysisdata/modules/displacement.cpp [new file with mode: 0644]
src/gromacs/analysisdata/modules/displacement.h [new file with mode: 0644]
src/gromacs/analysisdata/modules/histogram.cpp [new file with mode: 0644]
src/gromacs/analysisdata/modules/histogram.h [new file with mode: 0644]
src/gromacs/analysisdata/modules/plot-impl.h [new file with mode: 0644]
src/gromacs/analysisdata/modules/plot.cpp [new file with mode: 0644]
src/gromacs/analysisdata/modules/plot.h [new file with mode: 0644]
src/gromacs/basicmath.h [new file with mode: 0644]
src/gromacs/errorreporting.h [new file with mode: 0644]
src/gromacs/errorreporting/CMakeLists.txt [new file with mode: 0644]
src/gromacs/errorreporting/abstracterrorreporter.h [new file with mode: 0644]
src/gromacs/errorreporting/emptyerrorreporter.h [new file with mode: 0644]
src/gromacs/errorreporting/errorcontext.h [new file with mode: 0644]
src/gromacs/errorreporting/reporters.cpp [new file with mode: 0644]
src/gromacs/errorreporting/standarderrorreporter-impl.h [new file with mode: 0644]
src/gromacs/errorreporting/standarderrorreporter.h [new file with mode: 0644]
src/gromacs/fatalerror.h [new file with mode: 0644]
src/gromacs/fatalerror/CMakeLists.txt [new file with mode: 0644]
src/gromacs/fatalerror/fatalerror.cpp [new file with mode: 0644]
src/gromacs/fatalerror/fatalerror.h [new file with mode: 0644]
src/gromacs/genversion.sh [moved from src/gmxlib/genversion.sh with 100% similarity]
src/gromacs/gmxlib/3dview.c [moved from src/gmxlib/3dview.c with 100% similarity]
src/gromacs/gmxlib/CMakeLists.txt [new file with mode: 0644]
src/gromacs/gmxlib/atomprop.c [moved from src/gmxlib/atomprop.c with 100% similarity]
src/gromacs/gmxlib/bfunc.h [moved from src/gmxlib/bfunc.h with 100% similarity]
src/gromacs/gmxlib/bondfree.c [moved from src/gmxlib/bondfree.c with 100% similarity]
src/gromacs/gmxlib/calcgrid.c [moved from src/gmxlib/calcgrid.c with 100% similarity]
src/gromacs/gmxlib/calch.c [moved from src/gmxlib/calch.c with 100% similarity]
src/gromacs/gmxlib/chargegroup.c [moved from src/gmxlib/chargegroup.c with 100% similarity]
src/gromacs/gmxlib/checkpoint.c [moved from src/gmxlib/checkpoint.c with 100% similarity]
src/gromacs/gmxlib/cinvsqrtdata.c [moved from src/gmxlib/cinvsqrtdata.c with 100% similarity]
src/gromacs/gmxlib/confio.c [moved from src/gmxlib/confio.c with 100% similarity]
src/gromacs/gmxlib/copyrite.c [moved from src/gmxlib/copyrite.c with 100% similarity]
src/gromacs/gmxlib/crecipdata.c [moved from src/gmxlib/crecipdata.c with 100% similarity]
src/gromacs/gmxlib/debugb.h [moved from src/gmxlib/debugb.h with 100% similarity]
src/gromacs/gmxlib/dihres.c [moved from src/gmxlib/dihres.c with 100% similarity]
src/gromacs/gmxlib/disre.c [moved from src/gmxlib/disre.c with 100% similarity]
src/gromacs/gmxlib/dlb.h [moved from src/gmxlib/dlb.h with 100% similarity]
src/gromacs/gmxlib/do_fit.c [moved from src/gmxlib/do_fit.c with 100% similarity]
src/gromacs/gmxlib/enxio.c [moved from src/gmxlib/enxio.c with 100% similarity]
src/gromacs/gmxlib/ewald_util.c [moved from src/gmxlib/ewald_util.c with 100% similarity]
src/gromacs/gmxlib/ffscanf.c [moved from src/gmxlib/ffscanf.c with 100% similarity]
src/gromacs/gmxlib/filenm.c [moved from src/gmxlib/filenm.c with 100% similarity]
src/gromacs/gmxlib/futil.c [moved from src/gmxlib/futil.c with 100% similarity]
src/gromacs/gmxlib/futil_test.c [moved from src/gmxlib/futil_test.c with 100% similarity]
src/gromacs/gmxlib/gbutil.c [moved from src/gmxlib/gbutil.c with 100% similarity]
src/gromacs/gmxlib/gmx_arpack.c [moved from src/gmxlib/gmx_arpack.c with 100% similarity]
src/gromacs/gmxlib/gmx_blas/blas_copyright [moved from src/gmxlib/gmx_blas/blas_copyright with 100% similarity]
src/gromacs/gmxlib/gmx_blas/dasum.c [moved from src/gmxlib/gmx_blas/dasum.c with 100% similarity]
src/gromacs/gmxlib/gmx_blas/daxpy.c [moved from src/gmxlib/gmx_blas/daxpy.c with 100% similarity]
src/gromacs/gmxlib/gmx_blas/dcopy.c [moved from src/gmxlib/gmx_blas/dcopy.c with 100% similarity]
src/gromacs/gmxlib/gmx_blas/ddot.c [moved from src/gmxlib/gmx_blas/ddot.c with 100% similarity]
src/gromacs/gmxlib/gmx_blas/dgemm.c [moved from src/gmxlib/gmx_blas/dgemm.c with 100% similarity]
src/gromacs/gmxlib/gmx_blas/dgemv.c [moved from src/gmxlib/gmx_blas/dgemv.c with 100% similarity]
src/gromacs/gmxlib/gmx_blas/dger.c [moved from src/gmxlib/gmx_blas/dger.c with 100% similarity]
src/gromacs/gmxlib/gmx_blas/dnrm2.c [moved from src/gmxlib/gmx_blas/dnrm2.c with 100% similarity]
src/gromacs/gmxlib/gmx_blas/drot.c [moved from src/gmxlib/gmx_blas/drot.c with 100% similarity]
src/gromacs/gmxlib/gmx_blas/dscal.c [moved from src/gmxlib/gmx_blas/dscal.c with 100% similarity]
src/gromacs/gmxlib/gmx_blas/dswap.c [moved from src/gmxlib/gmx_blas/dswap.c with 100% similarity]
src/gromacs/gmxlib/gmx_blas/dsymv.c [moved from src/gmxlib/gmx_blas/dsymv.c with 100% similarity]
src/gromacs/gmxlib/gmx_blas/dsyr2.c [moved from src/gmxlib/gmx_blas/dsyr2.c with 100% similarity]
src/gromacs/gmxlib/gmx_blas/dsyr2k.c [moved from src/gmxlib/gmx_blas/dsyr2k.c with 100% similarity]
src/gromacs/gmxlib/gmx_blas/dtrmm.c [moved from src/gmxlib/gmx_blas/dtrmm.c with 100% similarity]
src/gromacs/gmxlib/gmx_blas/dtrmv.c [moved from src/gmxlib/gmx_blas/dtrmv.c with 100% similarity]
src/gromacs/gmxlib/gmx_blas/dtrsm.c [moved from src/gmxlib/gmx_blas/dtrsm.c with 100% similarity]
src/gromacs/gmxlib/gmx_blas/idamax.c [moved from src/gmxlib/gmx_blas/idamax.c with 100% similarity]
src/gromacs/gmxlib/gmx_blas/isamax.c [moved from src/gmxlib/gmx_blas/isamax.c with 100% similarity]
src/gromacs/gmxlib/gmx_blas/sasum.c [moved from src/gmxlib/gmx_blas/sasum.c with 100% similarity]
src/gromacs/gmxlib/gmx_blas/saxpy.c [moved from src/gmxlib/gmx_blas/saxpy.c with 100% similarity]
src/gromacs/gmxlib/gmx_blas/scopy.c [moved from src/gmxlib/gmx_blas/scopy.c with 100% similarity]
src/gromacs/gmxlib/gmx_blas/sdot.c [moved from src/gmxlib/gmx_blas/sdot.c with 100% similarity]
src/gromacs/gmxlib/gmx_blas/sgemm.c [moved from src/gmxlib/gmx_blas/sgemm.c with 100% similarity]
src/gromacs/gmxlib/gmx_blas/sgemv.c [moved from src/gmxlib/gmx_blas/sgemv.c with 100% similarity]
src/gromacs/gmxlib/gmx_blas/sger.c [moved from src/gmxlib/gmx_blas/sger.c with 100% similarity]
src/gromacs/gmxlib/gmx_blas/snrm2.c [moved from src/gmxlib/gmx_blas/snrm2.c with 100% similarity]
src/gromacs/gmxlib/gmx_blas/srot.c [moved from src/gmxlib/gmx_blas/srot.c with 100% similarity]
src/gromacs/gmxlib/gmx_blas/sscal.c [moved from src/gmxlib/gmx_blas/sscal.c with 100% similarity]
src/gromacs/gmxlib/gmx_blas/sswap.c [moved from src/gmxlib/gmx_blas/sswap.c with 100% similarity]
src/gromacs/gmxlib/gmx_blas/ssymv.c [moved from src/gmxlib/gmx_blas/ssymv.c with 100% similarity]
src/gromacs/gmxlib/gmx_blas/ssyr2.c [moved from src/gmxlib/gmx_blas/ssyr2.c with 100% similarity]
src/gromacs/gmxlib/gmx_blas/ssyr2k.c [moved from src/gmxlib/gmx_blas/ssyr2k.c with 100% similarity]
src/gromacs/gmxlib/gmx_blas/strmm.c [moved from src/gmxlib/gmx_blas/strmm.c with 100% similarity]
src/gromacs/gmxlib/gmx_blas/strmv.c [moved from src/gmxlib/gmx_blas/strmv.c with 100% similarity]
src/gromacs/gmxlib/gmx_blas/strsm.c [moved from src/gmxlib/gmx_blas/strsm.c with 100% similarity]
src/gromacs/gmxlib/gmx_cyclecounter.c [moved from src/gmxlib/gmx_cyclecounter.c with 100% similarity]
src/gromacs/gmxlib/gmx_fatal.c [moved from src/gmxlib/gmx_fatal.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dbdsdc.c [moved from src/gmxlib/gmx_lapack/dbdsdc.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dbdsqr.c [moved from src/gmxlib/gmx_lapack/dbdsqr.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dgebd2.c [moved from src/gmxlib/gmx_lapack/dgebd2.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dgebrd.c [moved from src/gmxlib/gmx_lapack/dgebrd.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dgelq2.c [moved from src/gmxlib/gmx_lapack/dgelq2.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dgelqf.c [moved from src/gmxlib/gmx_lapack/dgelqf.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dgeqr2.c [moved from src/gmxlib/gmx_lapack/dgeqr2.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dgeqrf.c [moved from src/gmxlib/gmx_lapack/dgeqrf.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dgesdd.c [moved from src/gmxlib/gmx_lapack/dgesdd.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dgetf2.c [moved from src/gmxlib/gmx_lapack/dgetf2.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dgetrf.c [moved from src/gmxlib/gmx_lapack/dgetrf.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dgetri.c [moved from src/gmxlib/gmx_lapack/dgetri.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dgetrs.c [moved from src/gmxlib/gmx_lapack/dgetrs.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dlabrd.c [moved from src/gmxlib/gmx_lapack/dlabrd.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dlacpy.c [moved from src/gmxlib/gmx_lapack/dlacpy.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dlae2.c [moved from src/gmxlib/gmx_lapack/dlae2.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dlaebz.c [moved from src/gmxlib/gmx_lapack/dlaebz.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dlaed6.c [moved from src/gmxlib/gmx_lapack/dlaed6.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dlaev2.c [moved from src/gmxlib/gmx_lapack/dlaev2.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dlagtf.c [moved from src/gmxlib/gmx_lapack/dlagtf.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dlagts.c [moved from src/gmxlib/gmx_lapack/dlagts.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dlamrg.c [moved from src/gmxlib/gmx_lapack/dlamrg.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dlange.c [moved from src/gmxlib/gmx_lapack/dlange.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dlanst.c [moved from src/gmxlib/gmx_lapack/dlanst.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dlansy.c [moved from src/gmxlib/gmx_lapack/dlansy.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dlapy2.c [moved from src/gmxlib/gmx_lapack/dlapy2.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dlar1vx.c [moved from src/gmxlib/gmx_lapack/dlar1vx.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dlarf.c [moved from src/gmxlib/gmx_lapack/dlarf.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dlarfb.c [moved from src/gmxlib/gmx_lapack/dlarfb.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dlarfg.c [moved from src/gmxlib/gmx_lapack/dlarfg.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dlarft.c [moved from src/gmxlib/gmx_lapack/dlarft.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dlarnv.c [moved from src/gmxlib/gmx_lapack/dlarnv.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dlarrbx.c [moved from src/gmxlib/gmx_lapack/dlarrbx.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dlarrex.c [moved from src/gmxlib/gmx_lapack/dlarrex.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dlarrfx.c [moved from src/gmxlib/gmx_lapack/dlarrfx.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dlarrvx.c [moved from src/gmxlib/gmx_lapack/dlarrvx.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dlartg.c [moved from src/gmxlib/gmx_lapack/dlartg.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dlaruv.c [moved from src/gmxlib/gmx_lapack/dlaruv.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dlas2.c [moved from src/gmxlib/gmx_lapack/dlas2.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dlascl.c [moved from src/gmxlib/gmx_lapack/dlascl.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dlasd0.c [moved from src/gmxlib/gmx_lapack/dlasd0.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dlasd1.c [moved from src/gmxlib/gmx_lapack/dlasd1.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dlasd2.c [moved from src/gmxlib/gmx_lapack/dlasd2.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dlasd3.c [moved from src/gmxlib/gmx_lapack/dlasd3.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dlasd4.c [moved from src/gmxlib/gmx_lapack/dlasd4.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dlasd5.c [moved from src/gmxlib/gmx_lapack/dlasd5.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dlasd6.c [moved from src/gmxlib/gmx_lapack/dlasd6.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dlasd7.c [moved from src/gmxlib/gmx_lapack/dlasd7.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dlasd8.c [moved from src/gmxlib/gmx_lapack/dlasd8.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dlasda.c [moved from src/gmxlib/gmx_lapack/dlasda.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dlasdq.c [moved from src/gmxlib/gmx_lapack/dlasdq.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dlasdt.c [moved from src/gmxlib/gmx_lapack/dlasdt.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dlaset.c [moved from src/gmxlib/gmx_lapack/dlaset.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dlasq1.c [moved from src/gmxlib/gmx_lapack/dlasq1.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dlasq2.c [moved from src/gmxlib/gmx_lapack/dlasq2.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dlasq3.c [moved from src/gmxlib/gmx_lapack/dlasq3.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dlasq4.c [moved from src/gmxlib/gmx_lapack/dlasq4.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dlasq5.c [moved from src/gmxlib/gmx_lapack/dlasq5.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dlasq6.c [moved from src/gmxlib/gmx_lapack/dlasq6.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dlasr.c [moved from src/gmxlib/gmx_lapack/dlasr.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dlasrt.c [moved from src/gmxlib/gmx_lapack/dlasrt.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dlasrt2.c [moved from src/gmxlib/gmx_lapack/dlasrt2.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dlassq.c [moved from src/gmxlib/gmx_lapack/dlassq.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dlasv2.c [moved from src/gmxlib/gmx_lapack/dlasv2.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dlaswp.c [moved from src/gmxlib/gmx_lapack/dlaswp.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dlatrd.c [moved from src/gmxlib/gmx_lapack/dlatrd.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dorg2r.c [moved from src/gmxlib/gmx_lapack/dorg2r.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dorgbr.c [moved from src/gmxlib/gmx_lapack/dorgbr.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dorgl2.c [moved from src/gmxlib/gmx_lapack/dorgl2.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dorglq.c [moved from src/gmxlib/gmx_lapack/dorglq.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dorgqr.c [moved from src/gmxlib/gmx_lapack/dorgqr.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dorm2l.c [moved from src/gmxlib/gmx_lapack/dorm2l.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dorm2r.c [moved from src/gmxlib/gmx_lapack/dorm2r.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dormbr.c [moved from src/gmxlib/gmx_lapack/dormbr.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dorml2.c [moved from src/gmxlib/gmx_lapack/dorml2.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dormlq.c [moved from src/gmxlib/gmx_lapack/dormlq.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dormql.c [moved from src/gmxlib/gmx_lapack/dormql.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dormqr.c [moved from src/gmxlib/gmx_lapack/dormqr.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dormtr.c [moved from src/gmxlib/gmx_lapack/dormtr.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dstebz.c [moved from src/gmxlib/gmx_lapack/dstebz.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dstegr.c [moved from src/gmxlib/gmx_lapack/dstegr.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dstein.c [moved from src/gmxlib/gmx_lapack/dstein.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dsteqr.c [moved from src/gmxlib/gmx_lapack/dsteqr.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dsterf.c [moved from src/gmxlib/gmx_lapack/dsterf.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dstevr.c [moved from src/gmxlib/gmx_lapack/dstevr.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dsyevr.c [moved from src/gmxlib/gmx_lapack/dsyevr.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dsytd2.c [moved from src/gmxlib/gmx_lapack/dsytd2.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dsytrd.c [moved from src/gmxlib/gmx_lapack/dsytrd.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dtrti2.c [moved from src/gmxlib/gmx_lapack/dtrti2.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/dtrtri.c [moved from src/gmxlib/gmx_lapack/dtrtri.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/ilasrt2.c [moved from src/gmxlib/gmx_lapack/ilasrt2.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/lapack_copyright [moved from src/gmxlib/gmx_lapack/lapack_copyright with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/lapack_limits.h [moved from src/gmxlib/gmx_lapack/lapack_limits.h with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/sbdsdc.c [moved from src/gmxlib/gmx_lapack/sbdsdc.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/sbdsqr.c [moved from src/gmxlib/gmx_lapack/sbdsqr.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/sgebd2.c [moved from src/gmxlib/gmx_lapack/sgebd2.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/sgebrd.c [moved from src/gmxlib/gmx_lapack/sgebrd.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/sgelq2.c [moved from src/gmxlib/gmx_lapack/sgelq2.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/sgelqf.c [moved from src/gmxlib/gmx_lapack/sgelqf.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/sgeqr2.c [moved from src/gmxlib/gmx_lapack/sgeqr2.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/sgeqrf.c [moved from src/gmxlib/gmx_lapack/sgeqrf.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/sgesdd.c [moved from src/gmxlib/gmx_lapack/sgesdd.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/sgetf2.c [moved from src/gmxlib/gmx_lapack/sgetf2.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/sgetrf.c [moved from src/gmxlib/gmx_lapack/sgetrf.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/sgetri.c [moved from src/gmxlib/gmx_lapack/sgetri.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/sgetrs.c [moved from src/gmxlib/gmx_lapack/sgetrs.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/slabrd.c [moved from src/gmxlib/gmx_lapack/slabrd.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/slacpy.c [moved from src/gmxlib/gmx_lapack/slacpy.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/slae2.c [moved from src/gmxlib/gmx_lapack/slae2.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/slaebz.c [moved from src/gmxlib/gmx_lapack/slaebz.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/slaed6.c [moved from src/gmxlib/gmx_lapack/slaed6.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/slaev2.c [moved from src/gmxlib/gmx_lapack/slaev2.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/slagtf.c [moved from src/gmxlib/gmx_lapack/slagtf.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/slagts.c [moved from src/gmxlib/gmx_lapack/slagts.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/slamrg.c [moved from src/gmxlib/gmx_lapack/slamrg.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/slange.c [moved from src/gmxlib/gmx_lapack/slange.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/slanst.c [moved from src/gmxlib/gmx_lapack/slanst.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/slansy.c [moved from src/gmxlib/gmx_lapack/slansy.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/slapy2.c [moved from src/gmxlib/gmx_lapack/slapy2.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/slar1vx.c [moved from src/gmxlib/gmx_lapack/slar1vx.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/slarf.c [moved from src/gmxlib/gmx_lapack/slarf.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/slarfb.c [moved from src/gmxlib/gmx_lapack/slarfb.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/slarfg.c [moved from src/gmxlib/gmx_lapack/slarfg.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/slarft.c [moved from src/gmxlib/gmx_lapack/slarft.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/slarnv.c [moved from src/gmxlib/gmx_lapack/slarnv.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/slarrbx.c [moved from src/gmxlib/gmx_lapack/slarrbx.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/slarrex.c [moved from src/gmxlib/gmx_lapack/slarrex.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/slarrfx.c [moved from src/gmxlib/gmx_lapack/slarrfx.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/slarrvx.c [moved from src/gmxlib/gmx_lapack/slarrvx.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/slartg.c [moved from src/gmxlib/gmx_lapack/slartg.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/slaruv.c [moved from src/gmxlib/gmx_lapack/slaruv.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/slas2.c [moved from src/gmxlib/gmx_lapack/slas2.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/slascl.c [moved from src/gmxlib/gmx_lapack/slascl.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/slasd0.c [moved from src/gmxlib/gmx_lapack/slasd0.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/slasd1.c [moved from src/gmxlib/gmx_lapack/slasd1.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/slasd2.c [moved from src/gmxlib/gmx_lapack/slasd2.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/slasd3.c [moved from src/gmxlib/gmx_lapack/slasd3.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/slasd4.c [moved from src/gmxlib/gmx_lapack/slasd4.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/slasd5.c [moved from src/gmxlib/gmx_lapack/slasd5.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/slasd6.c [moved from src/gmxlib/gmx_lapack/slasd6.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/slasd7.c [moved from src/gmxlib/gmx_lapack/slasd7.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/slasd8.c [moved from src/gmxlib/gmx_lapack/slasd8.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/slasda.c [moved from src/gmxlib/gmx_lapack/slasda.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/slasdq.c [moved from src/gmxlib/gmx_lapack/slasdq.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/slasdt.c [moved from src/gmxlib/gmx_lapack/slasdt.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/slaset.c [moved from src/gmxlib/gmx_lapack/slaset.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/slasq1.c [moved from src/gmxlib/gmx_lapack/slasq1.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/slasq2.c [moved from src/gmxlib/gmx_lapack/slasq2.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/slasq3.c [moved from src/gmxlib/gmx_lapack/slasq3.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/slasq4.c [moved from src/gmxlib/gmx_lapack/slasq4.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/slasq5.c [moved from src/gmxlib/gmx_lapack/slasq5.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/slasq6.c [moved from src/gmxlib/gmx_lapack/slasq6.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/slasr.c [moved from src/gmxlib/gmx_lapack/slasr.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/slasrt.c [moved from src/gmxlib/gmx_lapack/slasrt.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/slasrt2.c [moved from src/gmxlib/gmx_lapack/slasrt2.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/slassq.c [moved from src/gmxlib/gmx_lapack/slassq.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/slasv2.c [moved from src/gmxlib/gmx_lapack/slasv2.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/slaswp.c [moved from src/gmxlib/gmx_lapack/slaswp.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/slatrd.c [moved from src/gmxlib/gmx_lapack/slatrd.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/sorg2r.c [moved from src/gmxlib/gmx_lapack/sorg2r.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/sorgbr.c [moved from src/gmxlib/gmx_lapack/sorgbr.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/sorgl2.c [moved from src/gmxlib/gmx_lapack/sorgl2.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/sorglq.c [moved from src/gmxlib/gmx_lapack/sorglq.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/sorgqr.c [moved from src/gmxlib/gmx_lapack/sorgqr.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/sorm2l.c [moved from src/gmxlib/gmx_lapack/sorm2l.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/sorm2r.c [moved from src/gmxlib/gmx_lapack/sorm2r.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/sormbr.c [moved from src/gmxlib/gmx_lapack/sormbr.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/sorml2.c [moved from src/gmxlib/gmx_lapack/sorml2.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/sormlq.c [moved from src/gmxlib/gmx_lapack/sormlq.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/sormql.c [moved from src/gmxlib/gmx_lapack/sormql.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/sormqr.c [moved from src/gmxlib/gmx_lapack/sormqr.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/sormtr.c [moved from src/gmxlib/gmx_lapack/sormtr.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/sstebz.c [moved from src/gmxlib/gmx_lapack/sstebz.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/sstegr.c [moved from src/gmxlib/gmx_lapack/sstegr.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/sstein.c [moved from src/gmxlib/gmx_lapack/sstein.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/ssteqr.c [moved from src/gmxlib/gmx_lapack/ssteqr.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/ssterf.c [moved from src/gmxlib/gmx_lapack/ssterf.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/sstevr.c [moved from src/gmxlib/gmx_lapack/sstevr.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/ssyevr.c [moved from src/gmxlib/gmx_lapack/ssyevr.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/ssytd2.c [moved from src/gmxlib/gmx_lapack/ssytd2.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/ssytrd.c [moved from src/gmxlib/gmx_lapack/ssytrd.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/strti2.c [moved from src/gmxlib/gmx_lapack/strti2.c with 100% similarity]
src/gromacs/gmxlib/gmx_lapack/strtri.c [moved from src/gmxlib/gmx_lapack/strtri.c with 100% similarity]
src/gromacs/gmxlib/gmx_matrix.c [moved from src/gmxlib/gmx_matrix.c with 100% similarity]
src/gromacs/gmxlib/gmx_random.c [moved from src/gmxlib/gmx_random.c with 100% similarity]
src/gromacs/gmxlib/gmx_random_gausstable.h [moved from src/gmxlib/gmx_random_gausstable.h with 100% similarity]
src/gromacs/gmxlib/gmx_sort.c [moved from src/gmxlib/gmx_sort.c with 100% similarity]
src/gromacs/gmxlib/gmx_system_xdr.c [moved from src/gmxlib/gmx_system_xdr.c with 100% similarity]
src/gromacs/gmxlib/gmxcpp.c [moved from src/gmxlib/gmxcpp.c with 100% similarity]
src/gromacs/gmxlib/gmxfio.c [moved from src/gmxlib/gmxfio.c with 100% similarity]
src/gromacs/gmxlib/gmxfio_asc.c [moved from src/gmxlib/gmxfio_asc.c with 100% similarity]
src/gromacs/gmxlib/gmxfio_bin.c [moved from src/gmxlib/gmxfio_bin.c with 100% similarity]
src/gromacs/gmxlib/gmxfio_int.h [moved from src/gmxlib/gmxfio_int.h with 100% similarity]
src/gromacs/gmxlib/gmxfio_rw.c [moved from src/gmxlib/gmxfio_rw.c with 100% similarity]
src/gromacs/gmxlib/gmxfio_xdr.c [moved from src/gmxlib/gmxfio_xdr.c with 100% similarity]
src/gromacs/gmxlib/ifunc.c [moved from src/gmxlib/ifunc.c with 100% similarity]
src/gromacs/gmxlib/index.c [moved from src/gmxlib/index.c with 100% similarity]
src/gromacs/gmxlib/inputrec.c [moved from src/gmxlib/inputrec.c with 100% similarity]
src/gromacs/gmxlib/invblock.c [moved from src/gmxlib/invblock.c with 100% similarity]
src/gromacs/gmxlib/invsqrt_test.c [moved from src/gmxlib/invsqrt_test.c with 100% similarity]
src/gromacs/gmxlib/libxdrf.c [moved from src/gmxlib/libxdrf.c with 100% similarity]
src/gromacs/gmxlib/macros.c [moved from src/gmxlib/macros.c with 100% similarity]
src/gromacs/gmxlib/main.c [moved from src/gmxlib/main.c with 100% similarity]
src/gromacs/gmxlib/maths.c [moved from src/gmxlib/maths.c with 100% similarity]
src/gromacs/gmxlib/matio.c [moved from src/gmxlib/matio.c with 100% similarity]
src/gromacs/gmxlib/md5.c [moved from src/gmxlib/md5.c with 100% similarity]
src/gromacs/gmxlib/minvert.h [moved from src/gmxlib/minvert.h with 100% similarity]
src/gromacs/gmxlib/mshift.c [moved from src/gmxlib/mshift.c with 100% similarity]
src/gromacs/gmxlib/mtop_util.c [moved from src/gmxlib/mtop_util.c with 100% similarity]
src/gromacs/gmxlib/mtxio.c [moved from src/gmxlib/mtxio.c with 100% similarity]
src/gromacs/gmxlib/mvdata.c [new file with mode: 0644]
src/gromacs/gmxlib/names.c [new file with mode: 0644]
src/gromacs/gmxlib/network.c [new file with mode: 0644]
src/gromacs/gmxlib/nonbonded/nb_free_energy.c [moved from src/gmxlib/nonbonded/nb_free_energy.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_free_energy.h [moved from src/gmxlib/nonbonded/nb_free_energy.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_generic.c [moved from src/gmxlib/nonbonded/nb_generic.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_generic.h [moved from src/gmxlib/nonbonded/nb_generic.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_generic_cg.c [moved from src/gmxlib/nonbonded/nb_generic_cg.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_generic_cg.h [moved from src/gmxlib/nonbonded/nb_generic_cg.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/.gitignore [moved from src/gmxlib/gmx_lapack/.gitignore with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/Makefile.am [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/Makefile.am with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/interaction.h [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/interaction.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel010_bluegene.c [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel010_bluegene.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel010_bluegene.h [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel010_bluegene.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel020_bluegene.c [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel020_bluegene.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel020_bluegene.h [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel020_bluegene.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel030_bluegene.c [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel030_bluegene.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel030_bluegene.h [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel030_bluegene.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel100_bluegene.c [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel100_bluegene.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel100_bluegene.h [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel100_bluegene.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel101_bluegene.c [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel101_bluegene.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel101_bluegene.h [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel101_bluegene.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel102_bluegene.c [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel102_bluegene.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel102_bluegene.h [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel102_bluegene.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel103_bluegene.c [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel103_bluegene.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel103_bluegene.h [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel103_bluegene.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel104_bluegene.c [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel104_bluegene.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel104_bluegene.h [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel104_bluegene.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel110_bluegene.c [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel110_bluegene.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel110_bluegene.h [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel110_bluegene.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel111_bluegene.c [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel111_bluegene.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel111_bluegene.h [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel111_bluegene.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel112_bluegene.c [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel112_bluegene.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel112_bluegene.h [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel112_bluegene.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel113_bluegene.c [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel113_bluegene.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel113_bluegene.h [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel113_bluegene.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel114_bluegene.c [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel114_bluegene.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel114_bluegene.h [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel114_bluegene.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel120_bluegene.c [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel120_bluegene.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel120_bluegene.h [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel120_bluegene.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel121_bluegene.c [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel121_bluegene.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel121_bluegene.h [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel121_bluegene.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel122_bluegene.c [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel122_bluegene.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel122_bluegene.h [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel122_bluegene.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel123_bluegene.c [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel123_bluegene.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel123_bluegene.h [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel123_bluegene.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel124_bluegene.c [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel124_bluegene.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel124_bluegene.h [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel124_bluegene.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel130_bluegene.c [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel130_bluegene.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel130_bluegene.h [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel130_bluegene.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel131_bluegene.c [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel131_bluegene.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel131_bluegene.h [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel131_bluegene.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel132_bluegene.c [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel132_bluegene.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel132_bluegene.h [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel132_bluegene.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel133_bluegene.c [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel133_bluegene.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel133_bluegene.h [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel133_bluegene.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel134_bluegene.c [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel134_bluegene.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel134_bluegene.h [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel134_bluegene.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel200_bluegene.c [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel200_bluegene.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel200_bluegene.h [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel200_bluegene.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel201_bluegene.c [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel201_bluegene.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel201_bluegene.h [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel201_bluegene.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel202_bluegene.c [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel202_bluegene.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel202_bluegene.h [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel202_bluegene.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel203_bluegene.c [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel203_bluegene.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel203_bluegene.h [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel203_bluegene.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel204_bluegene.c [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel204_bluegene.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel204_bluegene.h [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel204_bluegene.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel210_bluegene.c [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel210_bluegene.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel210_bluegene.h [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel210_bluegene.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel211_bluegene.c [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel211_bluegene.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel211_bluegene.h [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel211_bluegene.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel212_bluegene.c [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel212_bluegene.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel212_bluegene.h [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel212_bluegene.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel213_bluegene.c [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel213_bluegene.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel213_bluegene.h [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel213_bluegene.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel214_bluegene.c [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel214_bluegene.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel214_bluegene.h [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel214_bluegene.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel220_bluegene.c [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel220_bluegene.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel220_bluegene.h [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel220_bluegene.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel221_bluegene.c [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel221_bluegene.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel221_bluegene.h [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel221_bluegene.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel222_bluegene.c [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel222_bluegene.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel222_bluegene.h [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel222_bluegene.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel223_bluegene.c [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel223_bluegene.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel223_bluegene.h [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel223_bluegene.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel224_bluegene.c [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel224_bluegene.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel224_bluegene.h [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel224_bluegene.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel230_bluegene.c [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel230_bluegene.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel230_bluegene.h [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel230_bluegene.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel231_bluegene.c [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel231_bluegene.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel231_bluegene.h [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel231_bluegene.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel232_bluegene.c [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel232_bluegene.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel232_bluegene.h [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel232_bluegene.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel233_bluegene.c [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel233_bluegene.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel233_bluegene.h [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel233_bluegene.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel234_bluegene.c [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel234_bluegene.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel234_bluegene.h [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel234_bluegene.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel300_bluegene.c [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel300_bluegene.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel300_bluegene.h [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel300_bluegene.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel301_bluegene.c [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel301_bluegene.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel301_bluegene.h [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel301_bluegene.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel302_bluegene.c [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel302_bluegene.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel302_bluegene.h [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel302_bluegene.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel303_bluegene.c [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel303_bluegene.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel303_bluegene.h [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel303_bluegene.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel304_bluegene.c [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel304_bluegene.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel304_bluegene.h [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel304_bluegene.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel310_bluegene.c [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel310_bluegene.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel310_bluegene.h [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel310_bluegene.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel311_bluegene.c [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel311_bluegene.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel311_bluegene.h [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel311_bluegene.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel312_bluegene.c [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel312_bluegene.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel312_bluegene.h [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel312_bluegene.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel313_bluegene.c [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel313_bluegene.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel313_bluegene.h [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel313_bluegene.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel314_bluegene.c [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel314_bluegene.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel314_bluegene.h [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel314_bluegene.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel320_bluegene.c [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel320_bluegene.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel320_bluegene.h [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel320_bluegene.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel321_bluegene.c [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel321_bluegene.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel321_bluegene.h [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel321_bluegene.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel322_bluegene.c [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel322_bluegene.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel322_bluegene.h [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel322_bluegene.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel323_bluegene.c [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel323_bluegene.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel323_bluegene.h [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel323_bluegene.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel324_bluegene.c [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel324_bluegene.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel324_bluegene.h [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel324_bluegene.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel330_bluegene.c [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel330_bluegene.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel330_bluegene.h [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel330_bluegene.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel331_bluegene.c [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel331_bluegene.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel331_bluegene.h [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel331_bluegene.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel332_bluegene.c [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel332_bluegene.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel332_bluegene.h [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel332_bluegene.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel333_bluegene.c [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel333_bluegene.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel333_bluegene.h [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel333_bluegene.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel334_bluegene.c [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel334_bluegene.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel334_bluegene.h [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel334_bluegene.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel400_bluegene.c [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel400_bluegene.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel400_bluegene.h [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel400_bluegene.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel410_bluegene.c [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel410_bluegene.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel410_bluegene.h [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel410_bluegene.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel420_bluegene.c [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel420_bluegene.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel420_bluegene.h [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel420_bluegene.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel430_bluegene.c [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel430_bluegene.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel430_bluegene.h [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel430_bluegene.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel_bluegene.c [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel_bluegene.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel_bluegene.h [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel_bluegene.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel_gen_bluegene.h [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel_gen_bluegene.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel_w3_bluegene.h [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel_w3_bluegene.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel_w3w3_bluegene.h [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel_w3w3_bluegene.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel_w4_bluegene.h [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel_w4_bluegene.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel_w4w4_bluegene.h [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/nb_kernel_w4w4_bluegene.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/.gitignore [moved from src/gmxlib/nonbonded/.gitignore with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/Makefile.am [moved from src/gmxlib/nonbonded/nb_kernel_c/Makefile.am with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel010.c [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel010.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel010.h [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel010.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel020.c [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel020.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel020.h [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel020.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel030.c [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel030.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel030.h [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel030.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel100.c [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel100.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel100.h [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel100.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel101.c [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel101.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel101.h [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel101.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel102.c [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel102.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel102.h [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel102.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel103.c [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel103.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel103.h [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel103.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel104.c [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel104.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel104.h [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel104.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel110.c [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel110.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel110.h [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel110.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel111.c [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel111.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel111.h [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel111.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel112.c [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel112.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel112.h [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel112.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel113.c [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel113.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel113.h [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel113.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel114.c [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel114.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel114.h [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel114.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel120.c [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel120.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel120.h [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel120.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel121.c [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel121.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel121.h [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel121.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel122.c [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel122.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel122.h [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel122.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel123.c [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel123.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel123.h [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel123.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel124.c [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel124.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel124.h [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel124.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel130.c [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel130.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel130.h [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel130.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel131.c [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel131.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel131.h [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel131.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel132.c [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel132.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel132.h [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel132.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel133.c [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel133.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel133.h [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel133.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel134.c [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel134.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel134.h [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel134.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel200.c [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel200.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel200.h [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel200.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel201.c [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel201.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel201.h [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel201.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel202.c [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel202.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel202.h [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel202.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel203.c [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel203.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel203.h [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel203.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel204.c [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel204.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel204.h [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel204.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel210.c [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel210.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel210.h [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel210.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel211.c [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel211.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel211.h [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel211.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel212.c [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel212.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel212.h [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel212.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel213.c [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel213.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel213.h [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel213.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel214.c [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel214.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel214.h [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel214.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel220.c [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel220.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel220.h [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel220.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel221.c [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel221.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel221.h [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel221.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel222.c [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel222.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel222.h [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel222.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel223.c [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel223.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel223.h [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel223.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel224.c [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel224.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel224.h [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel224.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel230.c [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel230.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel230.h [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel230.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel231.c [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel231.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel231.h [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel231.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel232.c [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel232.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel232.h [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel232.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel233.c [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel233.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel233.h [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel233.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel234.c [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel234.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel234.h [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel234.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel300.c [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel300.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel300.h [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel300.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel301.c [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel301.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel301.h [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel301.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel302.c [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel302.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel302.h [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel302.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel303.c [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel303.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel303.h [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel303.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel304.c [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel304.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel304.h [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel304.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel310.c [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel310.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel310.h [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel310.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel311.c [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel311.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel311.h [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel311.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel312.c [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel312.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel312.h [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel312.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel313.c [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel313.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel313.h [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel313.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel314.c [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel314.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel314.h [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel314.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel320.c [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel320.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel320.h [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel320.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel321.c [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel321.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel321.h [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel321.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel322.c [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel322.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel322.h [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel322.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel323.c [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel323.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel323.h [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel323.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel324.c [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel324.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel324.h [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel324.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel330.c [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel330.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel330.h [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel330.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel331.c [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel331.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel331.h [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel331.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel332.c [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel332.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel332.h [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel332.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel333.c [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel333.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel333.h [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel333.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel334.c [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel334.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel334.h [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel334.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel400.c [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel400.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel400.h [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel400.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel410.c [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel410.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel410.h [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel410.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel420.c [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel420.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel420.h [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel420.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel430.c [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel430.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel430.h [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel430.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel_allvsall.c [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel_allvsall.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel_allvsall.h [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel_allvsall.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel_allvsallgb.c [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel_allvsallgb.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel_allvsallgb.h [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel_allvsallgb.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel_c.c [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel_c.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel_c.h [moved from src/gmxlib/nonbonded/nb_kernel_c/nb_kernel_c.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/.gitignore [moved from src/gmxlib/nonbonded/nb_kernel_bluegene/.gitignore with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/Makefile.am [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/Makefile.am with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel010.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel010.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel020.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel020.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel030.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel030.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel100.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel100.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel101.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel101.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel102.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel102.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel103.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel103.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel104.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel104.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel110.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel110.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel111.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel111.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel112.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel112.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel113.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel113.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel114.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel114.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel120.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel120.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel121.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel121.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel122.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel122.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel123.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel123.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel124.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel124.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel130.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel130.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel131.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel131.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel132.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel132.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel133.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel133.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel134.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel134.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel200.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel200.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel201.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel201.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel202.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel202.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel203.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel203.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel204.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel204.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel210.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel210.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel211.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel211.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel212.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel212.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel213.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel213.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel214.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel214.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel220.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel220.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel221.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel221.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel222.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel222.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel223.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel223.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel224.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel224.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel230.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel230.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel231.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel231.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel232.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel232.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel233.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel233.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel234.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel234.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel300.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel300.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel301.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel301.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel302.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel302.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel303.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel303.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel304.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel304.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel310.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel310.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel311.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel311.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel312.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel312.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel313.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel313.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel314.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel314.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel320.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel320.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel321.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel321.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel322.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel322.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel323.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel323.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel324.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel324.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel330.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel330.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel331.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel331.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel332.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel332.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel333.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel333.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel334.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel334.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel400.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel400.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel410.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel410.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel420.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel420.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel430.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/f77dkernel430.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel010_f77_double.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel010_f77_double.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel010_f77_double.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel010_f77_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel020_f77_double.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel020_f77_double.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel020_f77_double.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel020_f77_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel030_f77_double.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel030_f77_double.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel030_f77_double.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel030_f77_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel100_f77_double.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel100_f77_double.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel100_f77_double.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel100_f77_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel101_f77_double.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel101_f77_double.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel101_f77_double.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel101_f77_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel102_f77_double.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel102_f77_double.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel102_f77_double.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel102_f77_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel103_f77_double.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel103_f77_double.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel103_f77_double.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel103_f77_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel104_f77_double.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel104_f77_double.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel104_f77_double.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel104_f77_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel110_f77_double.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel110_f77_double.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel110_f77_double.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel110_f77_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel111_f77_double.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel111_f77_double.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel111_f77_double.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel111_f77_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel112_f77_double.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel112_f77_double.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel112_f77_double.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel112_f77_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel113_f77_double.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel113_f77_double.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel113_f77_double.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel113_f77_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel114_f77_double.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel114_f77_double.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel114_f77_double.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel114_f77_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel120_f77_double.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel120_f77_double.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel120_f77_double.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel120_f77_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel121_f77_double.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel121_f77_double.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel121_f77_double.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel121_f77_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel122_f77_double.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel122_f77_double.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel122_f77_double.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel122_f77_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel123_f77_double.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel123_f77_double.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel123_f77_double.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel123_f77_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel124_f77_double.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel124_f77_double.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel124_f77_double.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel124_f77_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel130_f77_double.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel130_f77_double.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel130_f77_double.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel130_f77_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel131_f77_double.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel131_f77_double.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel131_f77_double.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel131_f77_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel132_f77_double.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel132_f77_double.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel132_f77_double.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel132_f77_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel133_f77_double.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel133_f77_double.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel133_f77_double.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel133_f77_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel134_f77_double.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel134_f77_double.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel134_f77_double.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel134_f77_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel200_f77_double.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel200_f77_double.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel200_f77_double.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel200_f77_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel201_f77_double.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel201_f77_double.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel201_f77_double.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel201_f77_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel202_f77_double.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel202_f77_double.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel202_f77_double.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel202_f77_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel203_f77_double.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel203_f77_double.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel203_f77_double.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel203_f77_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel204_f77_double.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel204_f77_double.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel204_f77_double.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel204_f77_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel210_f77_double.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel210_f77_double.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel210_f77_double.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel210_f77_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel211_f77_double.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel211_f77_double.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel211_f77_double.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel211_f77_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel212_f77_double.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel212_f77_double.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel212_f77_double.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel212_f77_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel213_f77_double.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel213_f77_double.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel213_f77_double.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel213_f77_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel214_f77_double.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel214_f77_double.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel214_f77_double.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel214_f77_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel220_f77_double.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel220_f77_double.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel220_f77_double.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel220_f77_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel221_f77_double.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel221_f77_double.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel221_f77_double.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel221_f77_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel222_f77_double.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel222_f77_double.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel222_f77_double.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel222_f77_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel223_f77_double.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel223_f77_double.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel223_f77_double.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel223_f77_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel224_f77_double.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel224_f77_double.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel224_f77_double.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel224_f77_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel230_f77_double.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel230_f77_double.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel230_f77_double.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel230_f77_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel231_f77_double.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel231_f77_double.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel231_f77_double.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel231_f77_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel232_f77_double.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel232_f77_double.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel232_f77_double.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel232_f77_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel233_f77_double.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel233_f77_double.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel233_f77_double.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel233_f77_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel234_f77_double.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel234_f77_double.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel234_f77_double.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel234_f77_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel300_f77_double.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel300_f77_double.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel300_f77_double.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel300_f77_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel301_f77_double.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel301_f77_double.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel301_f77_double.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel301_f77_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel302_f77_double.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel302_f77_double.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel302_f77_double.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel302_f77_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel303_f77_double.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel303_f77_double.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel303_f77_double.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel303_f77_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel304_f77_double.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel304_f77_double.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel304_f77_double.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel304_f77_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel310_f77_double.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel310_f77_double.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel310_f77_double.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel310_f77_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel311_f77_double.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel311_f77_double.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel311_f77_double.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel311_f77_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel312_f77_double.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel312_f77_double.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel312_f77_double.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel312_f77_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel313_f77_double.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel313_f77_double.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel313_f77_double.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel313_f77_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel314_f77_double.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel314_f77_double.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel314_f77_double.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel314_f77_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel320_f77_double.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel320_f77_double.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel320_f77_double.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel320_f77_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel321_f77_double.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel321_f77_double.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel321_f77_double.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel321_f77_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel322_f77_double.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel322_f77_double.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel322_f77_double.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel322_f77_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel323_f77_double.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel323_f77_double.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel323_f77_double.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel323_f77_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel324_f77_double.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel324_f77_double.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel324_f77_double.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel324_f77_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel330_f77_double.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel330_f77_double.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel330_f77_double.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel330_f77_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel331_f77_double.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel331_f77_double.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel331_f77_double.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel331_f77_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel332_f77_double.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel332_f77_double.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel332_f77_double.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel332_f77_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel333_f77_double.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel333_f77_double.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel333_f77_double.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel333_f77_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel334_f77_double.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel334_f77_double.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel334_f77_double.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel334_f77_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel400_f77_double.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel400_f77_double.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel400_f77_double.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel400_f77_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel410_f77_double.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel410_f77_double.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel410_f77_double.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel410_f77_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel420_f77_double.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel420_f77_double.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel420_f77_double.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel420_f77_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel430_f77_double.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel430_f77_double.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel430_f77_double.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel430_f77_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel_f77_double.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel_f77_double.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel_f77_double.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel_f77_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel_f77sync.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/nb_kernel_f77sync.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/.gitignore [moved from src/gmxlib/nonbonded/nb_kernel_c/.gitignore with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/Makefile.am [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/Makefile.am with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel010.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel010.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel020.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel020.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel030.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel030.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel100.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel100.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel101.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel101.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel102.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel102.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel103.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel103.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel104.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel104.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel110.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel110.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel111.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel111.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel112.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel112.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel113.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel113.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel114.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel114.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel120.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel120.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel121.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel121.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel122.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel122.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel123.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel123.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel124.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel124.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel130.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel130.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel131.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel131.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel132.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel132.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel133.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel133.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel134.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel134.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel200.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel200.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel201.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel201.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel202.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel202.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel203.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel203.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel204.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel204.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel210.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel210.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel211.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel211.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel212.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel212.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel213.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel213.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel214.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel214.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel220.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel220.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel221.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel221.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel222.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel222.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel223.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel223.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel224.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel224.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel230.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel230.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel231.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel231.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel232.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel232.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel233.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel233.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel234.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel234.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel300.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel300.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel301.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel301.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel302.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel302.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel303.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel303.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel304.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel304.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel310.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel310.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel311.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel311.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel312.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel312.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel313.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel313.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel314.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel314.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel320.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel320.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel321.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel321.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel322.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel322.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel323.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel323.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel324.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel324.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel330.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel330.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel331.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel331.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel332.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel332.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel333.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel333.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel334.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel334.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel400.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel400.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel410.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel410.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel420.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel420.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel430.f [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/f77skernel430.f with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel010_f77_single.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel010_f77_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel010_f77_single.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel010_f77_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel020_f77_single.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel020_f77_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel020_f77_single.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel020_f77_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel030_f77_single.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel030_f77_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel030_f77_single.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel030_f77_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel100_f77_single.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel100_f77_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel100_f77_single.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel100_f77_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel101_f77_single.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel101_f77_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel101_f77_single.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel101_f77_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel102_f77_single.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel102_f77_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel102_f77_single.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel102_f77_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel103_f77_single.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel103_f77_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel103_f77_single.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel103_f77_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel104_f77_single.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel104_f77_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel104_f77_single.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel104_f77_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel110_f77_single.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel110_f77_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel110_f77_single.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel110_f77_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel111_f77_single.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel111_f77_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel111_f77_single.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel111_f77_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel112_f77_single.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel112_f77_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel112_f77_single.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel112_f77_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel113_f77_single.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel113_f77_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel113_f77_single.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel113_f77_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel114_f77_single.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel114_f77_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel114_f77_single.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel114_f77_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel120_f77_single.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel120_f77_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel120_f77_single.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel120_f77_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel121_f77_single.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel121_f77_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel121_f77_single.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel121_f77_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel122_f77_single.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel122_f77_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel122_f77_single.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel122_f77_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel123_f77_single.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel123_f77_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel123_f77_single.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel123_f77_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel124_f77_single.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel124_f77_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel124_f77_single.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel124_f77_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel130_f77_single.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel130_f77_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel130_f77_single.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel130_f77_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel131_f77_single.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel131_f77_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel131_f77_single.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel131_f77_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel132_f77_single.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel132_f77_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel132_f77_single.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel132_f77_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel133_f77_single.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel133_f77_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel133_f77_single.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel133_f77_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel134_f77_single.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel134_f77_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel134_f77_single.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel134_f77_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel200_f77_single.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel200_f77_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel200_f77_single.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel200_f77_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel201_f77_single.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel201_f77_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel201_f77_single.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel201_f77_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel202_f77_single.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel202_f77_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel202_f77_single.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel202_f77_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel203_f77_single.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel203_f77_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel203_f77_single.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel203_f77_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel204_f77_single.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel204_f77_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel204_f77_single.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel204_f77_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel210_f77_single.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel210_f77_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel210_f77_single.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel210_f77_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel211_f77_single.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel211_f77_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel211_f77_single.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel211_f77_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel212_f77_single.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel212_f77_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel212_f77_single.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel212_f77_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel213_f77_single.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel213_f77_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel213_f77_single.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel213_f77_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel214_f77_single.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel214_f77_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel214_f77_single.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel214_f77_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel220_f77_single.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel220_f77_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel220_f77_single.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel220_f77_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel221_f77_single.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel221_f77_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel221_f77_single.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel221_f77_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel222_f77_single.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel222_f77_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel222_f77_single.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel222_f77_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel223_f77_single.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel223_f77_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel223_f77_single.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel223_f77_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel224_f77_single.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel224_f77_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel224_f77_single.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel224_f77_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel230_f77_single.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel230_f77_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel230_f77_single.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel230_f77_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel231_f77_single.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel231_f77_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel231_f77_single.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel231_f77_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel232_f77_single.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel232_f77_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel232_f77_single.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel232_f77_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel233_f77_single.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel233_f77_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel233_f77_single.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel233_f77_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel234_f77_single.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel234_f77_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel234_f77_single.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel234_f77_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel300_f77_single.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel300_f77_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel300_f77_single.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel300_f77_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel301_f77_single.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel301_f77_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel301_f77_single.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel301_f77_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel302_f77_single.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel302_f77_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel302_f77_single.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel302_f77_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel303_f77_single.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel303_f77_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel303_f77_single.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel303_f77_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel304_f77_single.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel304_f77_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel304_f77_single.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel304_f77_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel310_f77_single.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel310_f77_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel310_f77_single.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel310_f77_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel311_f77_single.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel311_f77_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel311_f77_single.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel311_f77_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel312_f77_single.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel312_f77_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel312_f77_single.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel312_f77_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel313_f77_single.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel313_f77_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel313_f77_single.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel313_f77_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel314_f77_single.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel314_f77_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel314_f77_single.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel314_f77_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel320_f77_single.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel320_f77_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel320_f77_single.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel320_f77_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel321_f77_single.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel321_f77_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel321_f77_single.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel321_f77_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel322_f77_single.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel322_f77_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel322_f77_single.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel322_f77_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel323_f77_single.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel323_f77_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel323_f77_single.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel323_f77_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel324_f77_single.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel324_f77_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel324_f77_single.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel324_f77_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel330_f77_single.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel330_f77_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel330_f77_single.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel330_f77_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel331_f77_single.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel331_f77_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel331_f77_single.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel331_f77_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel332_f77_single.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel332_f77_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel332_f77_single.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel332_f77_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel333_f77_single.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel333_f77_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel333_f77_single.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel333_f77_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel334_f77_single.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel334_f77_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel334_f77_single.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel334_f77_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel400_f77_single.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel400_f77_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel400_f77_single.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel400_f77_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel410_f77_single.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel410_f77_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel410_f77_single.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel410_f77_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel420_f77_single.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel420_f77_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel420_f77_single.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel420_f77_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel430_f77_single.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel430_f77_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel430_f77_single.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel430_f77_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel_f77_single.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel_f77_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel_f77_single.h [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel_f77_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel_f77sync.c [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/nb_kernel_f77sync.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/.gitignore [moved from src/gmxlib/nonbonded/nb_kernel_f77_double/.gitignore with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/Makefile.am [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/Makefile.am with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/README [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/README with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel010_ia32_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel010_ia32_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel010_ia32_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel010_ia32_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel010_ia32_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel010_ia32_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel030_ia32_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel030_ia32_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel030_ia32_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel030_ia32_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel030_ia32_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel030_ia32_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel100_ia32_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel100_ia32_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel100_ia32_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel100_ia32_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel100_ia32_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel100_ia32_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel101_ia32_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel101_ia32_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel101_ia32_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel101_ia32_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel101_ia32_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel101_ia32_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel102_ia32_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel102_ia32_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel102_ia32_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel102_ia32_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel102_ia32_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel102_ia32_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel103_ia32_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel103_ia32_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel103_ia32_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel103_ia32_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel103_ia32_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel103_ia32_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel104_ia32_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel104_ia32_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel104_ia32_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel104_ia32_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel104_ia32_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel104_ia32_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel110_ia32_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel110_ia32_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel110_ia32_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel110_ia32_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel110_ia32_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel110_ia32_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel111_ia32_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel111_ia32_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel111_ia32_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel111_ia32_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel111_ia32_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel111_ia32_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel112_ia32_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel112_ia32_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel112_ia32_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel112_ia32_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel112_ia32_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel112_ia32_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel113_ia32_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel113_ia32_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel113_ia32_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel113_ia32_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel113_ia32_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel113_ia32_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel114_ia32_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel114_ia32_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel114_ia32_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel114_ia32_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel114_ia32_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel114_ia32_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel130_ia32_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel130_ia32_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel130_ia32_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel130_ia32_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel130_ia32_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel130_ia32_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel131_ia32_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel131_ia32_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel131_ia32_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel131_ia32_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel131_ia32_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel131_ia32_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel132_ia32_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel132_ia32_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel132_ia32_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel132_ia32_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel132_ia32_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel132_ia32_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel133_ia32_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel133_ia32_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel133_ia32_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel133_ia32_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel133_ia32_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel133_ia32_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel134_ia32_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel134_ia32_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel134_ia32_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel134_ia32_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel134_ia32_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel134_ia32_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel200_ia32_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel200_ia32_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel200_ia32_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel200_ia32_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel200_ia32_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel200_ia32_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel201_ia32_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel201_ia32_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel201_ia32_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel201_ia32_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel201_ia32_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel201_ia32_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel202_ia32_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel202_ia32_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel202_ia32_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel202_ia32_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel202_ia32_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel202_ia32_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel203_ia32_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel203_ia32_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel203_ia32_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel203_ia32_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel203_ia32_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel203_ia32_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel204_ia32_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel204_ia32_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel204_ia32_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel204_ia32_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel204_ia32_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel204_ia32_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel210_ia32_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel210_ia32_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel210_ia32_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel210_ia32_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel210_ia32_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel210_ia32_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel211_ia32_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel211_ia32_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel211_ia32_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel211_ia32_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel211_ia32_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel211_ia32_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel212_ia32_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel212_ia32_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel212_ia32_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel212_ia32_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel212_ia32_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel212_ia32_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel213_ia32_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel213_ia32_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel213_ia32_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel213_ia32_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel213_ia32_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel213_ia32_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel214_ia32_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel214_ia32_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel214_ia32_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel214_ia32_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel214_ia32_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel214_ia32_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel230_ia32_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel230_ia32_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel230_ia32_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel230_ia32_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel230_ia32_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel230_ia32_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel231_ia32_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel231_ia32_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel231_ia32_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel231_ia32_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel231_ia32_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel231_ia32_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel232_ia32_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel232_ia32_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel232_ia32_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel232_ia32_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel232_ia32_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel232_ia32_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel233_ia32_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel233_ia32_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel233_ia32_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel233_ia32_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel233_ia32_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel233_ia32_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel234_ia32_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel234_ia32_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel234_ia32_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel234_ia32_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel234_ia32_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel234_ia32_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel300_ia32_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel300_ia32_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel300_ia32_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel300_ia32_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel300_ia32_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel300_ia32_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel301_ia32_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel301_ia32_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel301_ia32_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel301_ia32_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel301_ia32_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel301_ia32_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel302_ia32_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel302_ia32_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel302_ia32_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel302_ia32_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel302_ia32_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel302_ia32_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel303_ia32_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel303_ia32_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel303_ia32_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel303_ia32_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel303_ia32_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel303_ia32_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel304_ia32_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel304_ia32_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel304_ia32_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel304_ia32_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel304_ia32_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel304_ia32_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel310_ia32_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel310_ia32_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel310_ia32_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel310_ia32_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel310_ia32_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel310_ia32_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel311_ia32_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel311_ia32_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel311_ia32_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel311_ia32_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel311_ia32_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel311_ia32_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel312_ia32_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel312_ia32_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel312_ia32_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel312_ia32_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel312_ia32_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel312_ia32_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel313_ia32_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel313_ia32_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel313_ia32_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel313_ia32_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel313_ia32_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel313_ia32_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel314_ia32_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel314_ia32_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel314_ia32_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel314_ia32_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel314_ia32_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel314_ia32_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel330_ia32_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel330_ia32_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel330_ia32_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel330_ia32_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel330_ia32_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel330_ia32_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel331_ia32_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel331_ia32_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel331_ia32_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel331_ia32_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel331_ia32_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel331_ia32_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel332_ia32_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel332_ia32_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel332_ia32_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel332_ia32_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel332_ia32_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel332_ia32_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel333_ia32_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel333_ia32_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel333_ia32_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel333_ia32_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel333_ia32_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel333_ia32_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel334_ia32_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel334_ia32_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel334_ia32_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel334_ia32_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel334_ia32_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel334_ia32_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel400_ia32_sse.c [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel400_ia32_sse.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel400_ia32_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel400_ia32_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel410_ia32_sse.c [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel410_ia32_sse.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel410_ia32_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel410_ia32_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel430_ia32_sse.c [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel430_ia32_sse.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel430_ia32_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel430_ia32_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel_allvsall_sse2_single.c [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel_allvsall_sse2_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel_allvsall_sse2_single.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel_allvsall_sse2_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel_allvsallgb_sse2_single.c [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel_allvsallgb_sse2_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel_allvsallgb_sse2_single.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel_allvsallgb_sse2_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel_ia32_sse.c [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel_ia32_sse.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel_ia32_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel_ia32_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel_ia32_sse_test_asm.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel_ia32_sse_test_asm.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel_ia32_sse_test_asm.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel_ia32_sse_test_asm.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel_ia32_sse_test_asm_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/nb_kernel_ia32_sse_test_asm_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/.gitignore [moved from src/gmxlib/nonbonded/nb_kernel_f77_single/.gitignore with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/Makefile.am [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/Makefile.am with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/README [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/README with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel010_ia32_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel010_ia32_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel010_ia32_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel010_ia32_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel010_ia32_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel010_ia32_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel030_ia32_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel030_ia32_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel030_ia32_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel030_ia32_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel030_ia32_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel030_ia32_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel100_ia32_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel100_ia32_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel100_ia32_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel100_ia32_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel100_ia32_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel100_ia32_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel101_ia32_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel101_ia32_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel101_ia32_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel101_ia32_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel101_ia32_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel101_ia32_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel102_ia32_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel102_ia32_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel102_ia32_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel102_ia32_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel102_ia32_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel102_ia32_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel103_ia32_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel103_ia32_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel103_ia32_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel103_ia32_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel103_ia32_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel103_ia32_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel104_ia32_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel104_ia32_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel104_ia32_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel104_ia32_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel104_ia32_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel104_ia32_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel110_ia32_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel110_ia32_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel110_ia32_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel110_ia32_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel110_ia32_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel110_ia32_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel111_ia32_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel111_ia32_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel111_ia32_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel111_ia32_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel111_ia32_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel111_ia32_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel112_ia32_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel112_ia32_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel112_ia32_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel112_ia32_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel112_ia32_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel112_ia32_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel113_ia32_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel113_ia32_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel113_ia32_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel113_ia32_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel113_ia32_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel113_ia32_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel114_ia32_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel114_ia32_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel114_ia32_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel114_ia32_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel114_ia32_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel114_ia32_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel130_ia32_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel130_ia32_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel130_ia32_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel130_ia32_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel130_ia32_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel130_ia32_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel131_ia32_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel131_ia32_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel131_ia32_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel131_ia32_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel131_ia32_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel131_ia32_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel132_ia32_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel132_ia32_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel132_ia32_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel132_ia32_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel132_ia32_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel132_ia32_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel133_ia32_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel133_ia32_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel133_ia32_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel133_ia32_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel133_ia32_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel133_ia32_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel134_ia32_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel134_ia32_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel134_ia32_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel134_ia32_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel134_ia32_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel134_ia32_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel200_ia32_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel200_ia32_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel200_ia32_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel200_ia32_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel200_ia32_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel200_ia32_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel201_ia32_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel201_ia32_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel201_ia32_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel201_ia32_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel201_ia32_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel201_ia32_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel202_ia32_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel202_ia32_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel202_ia32_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel202_ia32_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel202_ia32_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel202_ia32_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel203_ia32_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel203_ia32_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel203_ia32_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel203_ia32_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel203_ia32_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel203_ia32_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel204_ia32_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel204_ia32_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel204_ia32_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel204_ia32_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel204_ia32_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel204_ia32_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel210_ia32_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel210_ia32_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel210_ia32_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel210_ia32_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel210_ia32_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel210_ia32_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel211_ia32_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel211_ia32_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel211_ia32_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel211_ia32_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel211_ia32_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel211_ia32_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel212_ia32_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel212_ia32_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel212_ia32_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel212_ia32_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel212_ia32_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel212_ia32_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel213_ia32_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel213_ia32_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel213_ia32_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel213_ia32_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel213_ia32_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel213_ia32_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel214_ia32_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel214_ia32_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel214_ia32_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel214_ia32_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel214_ia32_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel214_ia32_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel230_ia32_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel230_ia32_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel230_ia32_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel230_ia32_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel230_ia32_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel230_ia32_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel231_ia32_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel231_ia32_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel231_ia32_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel231_ia32_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel231_ia32_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel231_ia32_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel232_ia32_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel232_ia32_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel232_ia32_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel232_ia32_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel232_ia32_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel232_ia32_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel233_ia32_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel233_ia32_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel233_ia32_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel233_ia32_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel233_ia32_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel233_ia32_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel234_ia32_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel234_ia32_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel234_ia32_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel234_ia32_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel234_ia32_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel234_ia32_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel300_ia32_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel300_ia32_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel300_ia32_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel300_ia32_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel300_ia32_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel300_ia32_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel301_ia32_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel301_ia32_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel301_ia32_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel301_ia32_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel301_ia32_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel301_ia32_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel302_ia32_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel302_ia32_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel302_ia32_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel302_ia32_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel302_ia32_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel302_ia32_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel303_ia32_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel303_ia32_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel303_ia32_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel303_ia32_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel303_ia32_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel303_ia32_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel304_ia32_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel304_ia32_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel304_ia32_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel304_ia32_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel304_ia32_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel304_ia32_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel310_ia32_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel310_ia32_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel310_ia32_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel310_ia32_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel310_ia32_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel310_ia32_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel311_ia32_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel311_ia32_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel311_ia32_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel311_ia32_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel311_ia32_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel311_ia32_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel312_ia32_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel312_ia32_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel312_ia32_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel312_ia32_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel312_ia32_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel312_ia32_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel313_ia32_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel313_ia32_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel313_ia32_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel313_ia32_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel313_ia32_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel313_ia32_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel314_ia32_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel314_ia32_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel314_ia32_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel314_ia32_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel314_ia32_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel314_ia32_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel330_ia32_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel330_ia32_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel330_ia32_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel330_ia32_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel330_ia32_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel330_ia32_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel331_ia32_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel331_ia32_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel331_ia32_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel331_ia32_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel331_ia32_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel331_ia32_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel332_ia32_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel332_ia32_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel332_ia32_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel332_ia32_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel332_ia32_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel332_ia32_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel333_ia32_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel333_ia32_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel333_ia32_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel333_ia32_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel333_ia32_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel333_ia32_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel334_ia32_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel334_ia32_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel334_ia32_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel334_ia32_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel334_ia32_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel334_ia32_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel400_ia32_sse2.c [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel400_ia32_sse2.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel400_ia32_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel400_ia32_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel410_ia32_sse2.c [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel410_ia32_sse2.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel410_ia32_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel410_ia32_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel430_ia32_sse2.c [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel430_ia32_sse2.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel430_ia32_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel430_ia32_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel_allvsall_sse2_double.c [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel_allvsall_sse2_double.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel_allvsall_sse2_double.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel_allvsall_sse2_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel_allvsallgb_sse2_double.c [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel_allvsallgb_sse2_double.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel_allvsallgb_sse2_double.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel_allvsallgb_sse2_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel_ia32_sse2.c [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel_ia32_sse2.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel_ia32_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel_ia32_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel_ia32_sse2_test_asm.h [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel_ia32_sse2_test_asm.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel_ia32_sse2_test_asm.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel_ia32_sse2_test_asm.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel_ia32_sse2_test_asm_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/nb_kernel_ia32_sse2_test_asm_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_double/.gitignore [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse/.gitignore with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_double/Makefile.am [moved from src/gmxlib/nonbonded/nb_kernel_ia64_double/Makefile.am with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_double/README [moved from src/gmxlib/nonbonded/nb_kernel_ia64_double/README with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_double/ia64_cpuid.S [moved from src/gmxlib/nonbonded/nb_kernel_ia64_double/ia64_cpuid.S with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_double/ia64_cpuid.h [moved from src/gmxlib/nonbonded/nb_kernel_ia64_double/ia64_cpuid.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel010_ia64_double.S [moved from src/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel010_ia64_double.S with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel010_ia64_double.h [moved from src/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel010_ia64_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel010nf_ia64_double.S [moved from src/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel010nf_ia64_double.S with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel010nf_ia64_double.h [moved from src/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel010nf_ia64_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel030_ia64_double.S [moved from src/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel030_ia64_double.S with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel030_ia64_double.h [moved from src/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel030_ia64_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel030nf_ia64_double.S [moved from src/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel030nf_ia64_double.S with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel030nf_ia64_double.h [moved from src/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel030nf_ia64_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel100_ia64_double.S [moved from src/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel100_ia64_double.S with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel100_ia64_double.h [moved from src/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel100_ia64_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel100nf_ia64_double.S [moved from src/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel100nf_ia64_double.S with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel100nf_ia64_double.h [moved from src/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel100nf_ia64_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel110_ia64_double.S [moved from src/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel110_ia64_double.S with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel110_ia64_double.h [moved from src/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel110_ia64_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel110nf_ia64_double.S [moved from src/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel110nf_ia64_double.S with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel110nf_ia64_double.h [moved from src/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel110nf_ia64_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel130_ia64_double.S [moved from src/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel130_ia64_double.S with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel130_ia64_double.h [moved from src/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel130_ia64_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel130nf_ia64_double.S [moved from src/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel130nf_ia64_double.S with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel130nf_ia64_double.h [moved from src/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel130nf_ia64_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel200_ia64_double.S [moved from src/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel200_ia64_double.S with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel200_ia64_double.h [moved from src/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel200_ia64_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel200nf_ia64_double.S [moved from src/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel200nf_ia64_double.S with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel200nf_ia64_double.h [moved from src/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel200nf_ia64_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel210_ia64_double.S [moved from src/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel210_ia64_double.S with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel210_ia64_double.h [moved from src/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel210_ia64_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel210nf_ia64_double.S [moved from src/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel210nf_ia64_double.S with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel210nf_ia64_double.h [moved from src/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel210nf_ia64_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel230_ia64_double.S [moved from src/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel230_ia64_double.S with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel230_ia64_double.h [moved from src/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel230_ia64_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel230nf_ia64_double.S [moved from src/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel230nf_ia64_double.S with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel230nf_ia64_double.h [moved from src/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel230nf_ia64_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel300_ia64_double.S [moved from src/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel300_ia64_double.S with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel300_ia64_double.h [moved from src/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel300_ia64_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel300nf_ia64_double.S [moved from src/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel300nf_ia64_double.S with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel300nf_ia64_double.h [moved from src/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel300nf_ia64_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel310_ia64_double.S [moved from src/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel310_ia64_double.S with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel310_ia64_double.h [moved from src/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel310_ia64_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel310nf_ia64_double.S [moved from src/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel310nf_ia64_double.S with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel310nf_ia64_double.h [moved from src/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel310nf_ia64_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel330_ia64_double.S [moved from src/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel330_ia64_double.S with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel330_ia64_double.h [moved from src/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel330_ia64_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel330nf_ia64_double.S [moved from src/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel330nf_ia64_double.S with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel330nf_ia64_double.h [moved from src/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel330nf_ia64_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel400_ia64_double.S [moved from src/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel400_ia64_double.S with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel400_ia64_double.h [moved from src/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel400_ia64_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel400nf_ia64_double.S [moved from src/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel400nf_ia64_double.S with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel400nf_ia64_double.h [moved from src/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel400nf_ia64_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel410_ia64_double.S [moved from src/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel410_ia64_double.S with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel410_ia64_double.h [moved from src/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel410_ia64_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel410nf_ia64_double.S [moved from src/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel410nf_ia64_double.S with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel410nf_ia64_double.h [moved from src/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel410nf_ia64_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel430_ia64_double.S [moved from src/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel430_ia64_double.S with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel430_ia64_double.h [moved from src/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel430_ia64_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel430nf_ia64_double.S [moved from src/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel430nf_ia64_double.S with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel430nf_ia64_double.h [moved from src/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel430nf_ia64_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel_ia64_double.c [moved from src/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel_ia64_double.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel_ia64_double.h [moved from src/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel_ia64_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel_ia64_single.h [moved from src/gmxlib/nonbonded/nb_kernel_ia64_double/nb_kernel_ia64_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_single/.gitignore [moved from src/gmxlib/nonbonded/nb_kernel_ia32_sse2/.gitignore with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_single/Makefile.am [moved from src/gmxlib/nonbonded/nb_kernel_ia64_single/Makefile.am with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_single/README [moved from src/gmxlib/nonbonded/nb_kernel_ia64_single/README with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_single/ia64_cpuid.S [moved from src/gmxlib/nonbonded/nb_kernel_ia64_single/ia64_cpuid.S with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_single/ia64_cpuid.h [moved from src/gmxlib/nonbonded/nb_kernel_ia64_single/ia64_cpuid.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel010_ia64_single.S [moved from src/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel010_ia64_single.S with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel010_ia64_single.h [moved from src/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel010_ia64_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel010nf_ia64_single.S [moved from src/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel010nf_ia64_single.S with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel010nf_ia64_single.h [moved from src/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel010nf_ia64_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel030_ia64_single.S [moved from src/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel030_ia64_single.S with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel030_ia64_single.h [moved from src/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel030_ia64_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel030nf_ia64_single.S [moved from src/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel030nf_ia64_single.S with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel030nf_ia64_single.h [moved from src/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel030nf_ia64_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel100_ia64_single.S [moved from src/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel100_ia64_single.S with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel100_ia64_single.h [moved from src/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel100_ia64_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel100nf_ia64_single.S [moved from src/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel100nf_ia64_single.S with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel100nf_ia64_single.h [moved from src/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel100nf_ia64_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel110_ia64_single.S [moved from src/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel110_ia64_single.S with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel110_ia64_single.h [moved from src/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel110_ia64_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel110nf_ia64_single.S [moved from src/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel110nf_ia64_single.S with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel110nf_ia64_single.h [moved from src/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel110nf_ia64_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel130_ia64_single.S [moved from src/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel130_ia64_single.S with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel130_ia64_single.h [moved from src/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel130_ia64_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel130nf_ia64_single.S [moved from src/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel130nf_ia64_single.S with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel130nf_ia64_single.h [moved from src/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel130nf_ia64_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel200_ia64_single.S [moved from src/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel200_ia64_single.S with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel200_ia64_single.h [moved from src/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel200_ia64_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel200nf_ia64_single.S [moved from src/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel200nf_ia64_single.S with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel200nf_ia64_single.h [moved from src/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel200nf_ia64_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel210_ia64_single.S [moved from src/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel210_ia64_single.S with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel210_ia64_single.h [moved from src/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel210_ia64_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel210nf_ia64_single.S [moved from src/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel210nf_ia64_single.S with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel210nf_ia64_single.h [moved from src/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel210nf_ia64_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel230_ia64_single.S [moved from src/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel230_ia64_single.S with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel230_ia64_single.h [moved from src/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel230_ia64_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel230nf_ia64_single.S [moved from src/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel230nf_ia64_single.S with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel230nf_ia64_single.h [moved from src/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel230nf_ia64_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel300_ia64_single.S [moved from src/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel300_ia64_single.S with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel300_ia64_single.h [moved from src/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel300_ia64_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel300nf_ia64_single.S [moved from src/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel300nf_ia64_single.S with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel300nf_ia64_single.h [moved from src/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel300nf_ia64_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel310_ia64_single.S [moved from src/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel310_ia64_single.S with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel310_ia64_single.h [moved from src/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel310_ia64_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel310nf_ia64_single.S [moved from src/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel310nf_ia64_single.S with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel310nf_ia64_single.h [moved from src/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel310nf_ia64_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel330_ia64_single.S [moved from src/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel330_ia64_single.S with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel330_ia64_single.h [moved from src/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel330_ia64_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel330nf_ia64_single.S [moved from src/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel330nf_ia64_single.S with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel330nf_ia64_single.h [moved from src/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel330nf_ia64_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel400_ia64_single.S [moved from src/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel400_ia64_single.S with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel400_ia64_single.h [moved from src/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel400_ia64_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel400nf_ia64_single.S [moved from src/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel400nf_ia64_single.S with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel400nf_ia64_single.h [moved from src/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel400nf_ia64_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel410_ia64_single.S [moved from src/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel410_ia64_single.S with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel410_ia64_single.h [moved from src/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel410_ia64_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel410nf_ia64_single.S [moved from src/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel410nf_ia64_single.S with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel410nf_ia64_single.h [moved from src/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel410nf_ia64_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel430_ia64_single.S [moved from src/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel430_ia64_single.S with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel430_ia64_single.h [moved from src/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel430_ia64_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel430nf_ia64_single.S [moved from src/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel430nf_ia64_single.S with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel430nf_ia64_single.h [moved from src/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel430nf_ia64_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel_ia64_single.c [moved from src/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel_ia64_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel_ia64_single.h [moved from src/gmxlib/nonbonded/nb_kernel_ia64_single/nb_kernel_ia64_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/.gitignore [moved from src/gmxlib/nonbonded/nb_kernel_ia64_double/.gitignore with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/Makefile.am [moved from src/gmxlib/nonbonded/nb_kernel_power6/Makefile.am with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel010_power6.c [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel010_power6.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel010_power6.h [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel010_power6.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel020_power6.c [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel020_power6.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel020_power6.h [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel020_power6.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel030_power6.c [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel030_power6.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel030_power6.h [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel030_power6.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel100_power6.c [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel100_power6.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel100_power6.h [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel100_power6.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel101_power6.c [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel101_power6.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel101_power6.h [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel101_power6.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel102_power6.c [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel102_power6.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel102_power6.h [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel102_power6.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel103_power6.c [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel103_power6.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel103_power6.h [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel103_power6.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel104_power6.c [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel104_power6.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel104_power6.h [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel104_power6.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel110_power6.c [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel110_power6.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel110_power6.h [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel110_power6.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel111_power6.c [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel111_power6.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel111_power6.h [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel111_power6.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel112_power6.c [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel112_power6.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel112_power6.h [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel112_power6.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel113_power6.c [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel113_power6.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel113_power6.h [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel113_power6.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel114_power6.c [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel114_power6.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel114_power6.h [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel114_power6.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel120_power6.c [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel120_power6.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel120_power6.h [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel120_power6.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel121_power6.c [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel121_power6.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel121_power6.h [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel121_power6.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel122_power6.c [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel122_power6.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel122_power6.h [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel122_power6.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel123_power6.c [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel123_power6.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel123_power6.h [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel123_power6.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel124_power6.c [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel124_power6.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel124_power6.h [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel124_power6.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel130_power6.c [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel130_power6.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel130_power6.h [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel130_power6.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel131_power6.c [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel131_power6.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel131_power6.h [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel131_power6.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel132_power6.c [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel132_power6.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel132_power6.h [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel132_power6.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel133_power6.c [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel133_power6.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel133_power6.h [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel133_power6.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel134_power6.c [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel134_power6.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel134_power6.h [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel134_power6.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel200_power6.c [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel200_power6.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel200_power6.h [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel200_power6.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel201_power6.c [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel201_power6.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel201_power6.h [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel201_power6.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel202_power6.c [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel202_power6.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel202_power6.h [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel202_power6.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel203_power6.c [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel203_power6.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel203_power6.h [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel203_power6.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel204_power6.c [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel204_power6.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel204_power6.h [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel204_power6.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel210_power6.c [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel210_power6.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel210_power6.h [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel210_power6.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel211_power6.c [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel211_power6.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel211_power6.h [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel211_power6.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel212_power6.c [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel212_power6.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel212_power6.h [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel212_power6.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel213_power6.c [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel213_power6.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel213_power6.h [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel213_power6.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel214_power6.c [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel214_power6.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel214_power6.h [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel214_power6.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel220_power6.c [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel220_power6.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel220_power6.h [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel220_power6.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel221_power6.c [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel221_power6.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel221_power6.h [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel221_power6.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel222_power6.c [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel222_power6.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel222_power6.h [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel222_power6.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel223_power6.c [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel223_power6.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel223_power6.h [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel223_power6.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel224_power6.c [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel224_power6.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel224_power6.h [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel224_power6.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel230_power6.c [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel230_power6.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel230_power6.h [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel230_power6.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel231_power6.c [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel231_power6.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel231_power6.h [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel231_power6.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel232_power6.c [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel232_power6.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel232_power6.h [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel232_power6.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel233_power6.c [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel233_power6.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel233_power6.h [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel233_power6.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel234_power6.c [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel234_power6.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel234_power6.h [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel234_power6.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel300_power6.c [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel300_power6.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel300_power6.h [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel300_power6.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel301_power6.c [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel301_power6.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel301_power6.h [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel301_power6.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel302_power6.c [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel302_power6.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel302_power6.h [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel302_power6.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel303_power6.c [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel303_power6.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel303_power6.h [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel303_power6.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel304_power6.c [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel304_power6.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel304_power6.h [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel304_power6.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel310_power6.c [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel310_power6.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel310_power6.h [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel310_power6.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel311_power6.c [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel311_power6.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel311_power6.h [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel311_power6.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel312_power6.c [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel312_power6.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel312_power6.h [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel312_power6.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel313_power6.c [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel313_power6.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel313_power6.h [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel313_power6.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel314_power6.c [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel314_power6.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel314_power6.h [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel314_power6.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel320_power6.c [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel320_power6.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel320_power6.h [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel320_power6.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel321_power6.c [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel321_power6.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel321_power6.h [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel321_power6.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel322_power6.c [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel322_power6.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel322_power6.h [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel322_power6.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel323_power6.c [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel323_power6.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel323_power6.h [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel323_power6.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel324_power6.c [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel324_power6.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel324_power6.h [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel324_power6.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel330_power6.c [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel330_power6.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel330_power6.h [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel330_power6.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel331_power6.c [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel331_power6.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel331_power6.h [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel331_power6.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel332_power6.c [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel332_power6.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel332_power6.h [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel332_power6.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel333_power6.c [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel333_power6.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel333_power6.h [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel333_power6.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel334_power6.c [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel334_power6.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel334_power6.h [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel334_power6.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel400_power6.c [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel400_power6.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel400_power6.h [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel400_power6.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel410_power6.c [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel410_power6.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel410_power6.h [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel410_power6.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel420_power6.c [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel420_power6.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel420_power6.h [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel420_power6.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel430_power6.c [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel430_power6.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel430_power6.h [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel430_power6.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel_power6.c [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel_power6.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel_power6.h [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel_power6.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/nb_kernel_pwr6sync.c [moved from src/gmxlib/nonbonded/nb_kernel_power6/nb_kernel_pwr6sync.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel010.F [moved from src/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel010.F with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel020.F [moved from src/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel020.F with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel030.F [moved from src/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel030.F with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel100.F [moved from src/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel100.F with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel101.F [moved from src/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel101.F with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel102.F [moved from src/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel102.F with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel103.F [moved from src/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel103.F with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel104.F [moved from src/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel104.F with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel110.F [moved from src/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel110.F with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel111.F [moved from src/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel111.F with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel112.F [moved from src/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel112.F with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel113.F [moved from src/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel113.F with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel114.F [moved from src/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel114.F with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel120.F [moved from src/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel120.F with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel121.F [moved from src/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel121.F with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel122.F [moved from src/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel122.F with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel123.F [moved from src/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel123.F with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel124.F [moved from src/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel124.F with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel130.F [moved from src/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel130.F with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel131.F [moved from src/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel131.F with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel132.F [moved from src/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel132.F with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel133.F [moved from src/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel133.F with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel134.F [moved from src/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel134.F with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel200.F [moved from src/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel200.F with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel201.F [moved from src/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel201.F with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel202.F [moved from src/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel202.F with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel203.F [moved from src/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel203.F with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel204.F [moved from src/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel204.F with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel210.F [moved from src/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel210.F with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel211.F [moved from src/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel211.F with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel212.F [moved from src/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel212.F with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel213.F [moved from src/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel213.F with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel214.F [moved from src/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel214.F with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel220.F [moved from src/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel220.F with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel221.F [moved from src/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel221.F with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel222.F [moved from src/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel222.F with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel223.F [moved from src/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel223.F with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel224.F [moved from src/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel224.F with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel230.F [moved from src/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel230.F with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel231.F [moved from src/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel231.F with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel232.F [moved from src/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel232.F with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel233.F [moved from src/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel233.F with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel234.F [moved from src/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel234.F with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel300.F [moved from src/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel300.F with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel301.F [moved from src/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel301.F with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel302.F [moved from src/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel302.F with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel303.F [moved from src/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel303.F with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel304.F [moved from src/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel304.F with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel310.F [moved from src/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel310.F with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel311.F [moved from src/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel311.F with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel312.F [moved from src/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel312.F with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel313.F [moved from src/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel313.F with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel314.F [moved from src/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel314.F with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel320.F [moved from src/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel320.F with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel321.F [moved from src/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel321.F with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel322.F [moved from src/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel322.F with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel323.F [moved from src/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel323.F with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel324.F [moved from src/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel324.F with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel330.F [moved from src/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel330.F with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel331.F [moved from src/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel331.F with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel332.F [moved from src/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel332.F with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel333.F [moved from src/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel333.F with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel334.F [moved from src/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel334.F with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel400.F [moved from src/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel400.F with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel410.F [moved from src/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel410.F with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel420.F [moved from src/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel420.F with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel430.F [moved from src/gmxlib/nonbonded/nb_kernel_power6/pwr6kernel430.F with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/Makefile.am [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/Makefile.am with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/README [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/README with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel010_ppc_altivec.c [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel010_ppc_altivec.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel010_ppc_altivec.h [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel010_ppc_altivec.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel030_ppc_altivec.c [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel030_ppc_altivec.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel030_ppc_altivec.h [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel030_ppc_altivec.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel100_ppc_altivec.c [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel100_ppc_altivec.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel100_ppc_altivec.h [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel100_ppc_altivec.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel101_ppc_altivec.c [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel101_ppc_altivec.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel101_ppc_altivec.h [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel101_ppc_altivec.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel102_ppc_altivec.c [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel102_ppc_altivec.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel102_ppc_altivec.h [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel102_ppc_altivec.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel103_ppc_altivec.c [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel103_ppc_altivec.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel103_ppc_altivec.h [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel103_ppc_altivec.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel104_ppc_altivec.c [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel104_ppc_altivec.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel104_ppc_altivec.h [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel104_ppc_altivec.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel110_ppc_altivec.c [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel110_ppc_altivec.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel110_ppc_altivec.h [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel110_ppc_altivec.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel111_ppc_altivec.c [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel111_ppc_altivec.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel111_ppc_altivec.h [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel111_ppc_altivec.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel112_ppc_altivec.c [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel112_ppc_altivec.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel112_ppc_altivec.h [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel112_ppc_altivec.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel113_ppc_altivec.c [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel113_ppc_altivec.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel113_ppc_altivec.h [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel113_ppc_altivec.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel114_ppc_altivec.c [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel114_ppc_altivec.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel114_ppc_altivec.h [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel114_ppc_altivec.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel130_ppc_altivec.c [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel130_ppc_altivec.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel130_ppc_altivec.h [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel130_ppc_altivec.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel131_ppc_altivec.c [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel131_ppc_altivec.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel131_ppc_altivec.h [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel131_ppc_altivec.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel132_ppc_altivec.c [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel132_ppc_altivec.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel132_ppc_altivec.h [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel132_ppc_altivec.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel133_ppc_altivec.c [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel133_ppc_altivec.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel133_ppc_altivec.h [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel133_ppc_altivec.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel134_ppc_altivec.c [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel134_ppc_altivec.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel134_ppc_altivec.h [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel134_ppc_altivec.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel200_ppc_altivec.c [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel200_ppc_altivec.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel200_ppc_altivec.h [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel200_ppc_altivec.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel201_ppc_altivec.c [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel201_ppc_altivec.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel201_ppc_altivec.h [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel201_ppc_altivec.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel202_ppc_altivec.c [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel202_ppc_altivec.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel202_ppc_altivec.h [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel202_ppc_altivec.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel203_ppc_altivec.c [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel203_ppc_altivec.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel203_ppc_altivec.h [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel203_ppc_altivec.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel204_ppc_altivec.c [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel204_ppc_altivec.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel204_ppc_altivec.h [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel204_ppc_altivec.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel210_ppc_altivec.c [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel210_ppc_altivec.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel210_ppc_altivec.h [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel210_ppc_altivec.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel211_ppc_altivec.c [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel211_ppc_altivec.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel211_ppc_altivec.h [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel211_ppc_altivec.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel212_ppc_altivec.c [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel212_ppc_altivec.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel212_ppc_altivec.h [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel212_ppc_altivec.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel213_ppc_altivec.c [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel213_ppc_altivec.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel213_ppc_altivec.h [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel213_ppc_altivec.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel214_ppc_altivec.c [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel214_ppc_altivec.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel214_ppc_altivec.h [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel214_ppc_altivec.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel230_ppc_altivec.c [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel230_ppc_altivec.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel230_ppc_altivec.h [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel230_ppc_altivec.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel231_ppc_altivec.c [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel231_ppc_altivec.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel231_ppc_altivec.h [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel231_ppc_altivec.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel232_ppc_altivec.c [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel232_ppc_altivec.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel232_ppc_altivec.h [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel232_ppc_altivec.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel233_ppc_altivec.c [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel233_ppc_altivec.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel233_ppc_altivec.h [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel233_ppc_altivec.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel234_ppc_altivec.c [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel234_ppc_altivec.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel234_ppc_altivec.h [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel234_ppc_altivec.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel300_ppc_altivec.c [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel300_ppc_altivec.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel300_ppc_altivec.h [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel300_ppc_altivec.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel301_ppc_altivec.c [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel301_ppc_altivec.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel301_ppc_altivec.h [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel301_ppc_altivec.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel302_ppc_altivec.c [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel302_ppc_altivec.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel302_ppc_altivec.h [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel302_ppc_altivec.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel303_ppc_altivec.c [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel303_ppc_altivec.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel303_ppc_altivec.h [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel303_ppc_altivec.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel304_ppc_altivec.c [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel304_ppc_altivec.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel304_ppc_altivec.h [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel304_ppc_altivec.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel310_ppc_altivec.c [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel310_ppc_altivec.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel310_ppc_altivec.h [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel310_ppc_altivec.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel311_ppc_altivec.c [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel311_ppc_altivec.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel311_ppc_altivec.h [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel311_ppc_altivec.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel312_ppc_altivec.c [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel312_ppc_altivec.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel312_ppc_altivec.h [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel312_ppc_altivec.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel313_ppc_altivec.c [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel313_ppc_altivec.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel313_ppc_altivec.h [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel313_ppc_altivec.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel314_ppc_altivec.c [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel314_ppc_altivec.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel314_ppc_altivec.h [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel314_ppc_altivec.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel330_ppc_altivec.c [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel330_ppc_altivec.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel330_ppc_altivec.h [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel330_ppc_altivec.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel331_ppc_altivec.c [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel331_ppc_altivec.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel331_ppc_altivec.h [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel331_ppc_altivec.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel332_ppc_altivec.c [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel332_ppc_altivec.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel332_ppc_altivec.h [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel332_ppc_altivec.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel333_ppc_altivec.c [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel333_ppc_altivec.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel333_ppc_altivec.h [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel333_ppc_altivec.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel334_ppc_altivec.c [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel334_ppc_altivec.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel334_ppc_altivec.h [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel334_ppc_altivec.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel400_ppc_altivec.c [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel400_ppc_altivec.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel400_ppc_altivec.h [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel400_ppc_altivec.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel410_ppc_altivec.c [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel410_ppc_altivec.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel410_ppc_altivec.h [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel410_ppc_altivec.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel430_ppc_altivec.c [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel430_ppc_altivec.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel430_ppc_altivec.h [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel430_ppc_altivec.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel_ppc_altivec.c [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel_ppc_altivec.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel_ppc_altivec.h [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel_ppc_altivec.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel_ppc_altivec_test.c [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel_ppc_altivec_test.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel_ppc_altivec_test.h [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/nb_kernel_ppc_altivec_test.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_ppc_altivec/ppc_altivec_util.h [moved from src/gmxlib/nonbonded/nb_kernel_ppc_altivec/ppc_altivec_util.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_double/Makefile.am [moved from src/gmxlib/nonbonded/nb_kernel_sse2_double/Makefile.am with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_double/nb_kernel400_sse2_double.c [moved from src/gmxlib/nonbonded/nb_kernel_sse2_double/nb_kernel400_sse2_double.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_double/nb_kernel400_sse2_double.h [moved from src/gmxlib/nonbonded/nb_kernel_sse2_double/nb_kernel400_sse2_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_double/nb_kernel410_sse2_double.c [moved from src/gmxlib/nonbonded/nb_kernel_sse2_double/nb_kernel410_sse2_double.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_double/nb_kernel410_sse2_double.h [moved from src/gmxlib/nonbonded/nb_kernel_sse2_double/nb_kernel410_sse2_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_double/nb_kernel430_sse2_double.c [moved from src/gmxlib/nonbonded/nb_kernel_sse2_double/nb_kernel430_sse2_double.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_double/nb_kernel430_sse2_double.h [moved from src/gmxlib/nonbonded/nb_kernel_sse2_double/nb_kernel430_sse2_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_double/nb_kernel_sse2_double.c [moved from src/gmxlib/nonbonded/nb_kernel_sse2_double/nb_kernel_sse2_double.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_double/nb_kernel_sse2_double.h [moved from src/gmxlib/nonbonded/nb_kernel_sse2_double/nb_kernel_sse2_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/Makefile.am [moved from src/gmxlib/nonbonded/nb_kernel_sse2_single/Makefile.am with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel110_sse2_single.c [moved from src/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel110_sse2_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel332_sse2_single.c [moved from src/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel332_sse2_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel332_sse2_single.h [moved from src/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel332_sse2_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel400_sse2_single.c [moved from src/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel400_sse2_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel400_sse2_single.h [moved from src/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel400_sse2_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel410_sse2_single.c [moved from src/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel410_sse2_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel410_sse2_single.h [moved from src/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel410_sse2_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel430_sse2_single.c [moved from src/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel430_sse2_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel430_sse2_single.h [moved from src/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel430_sse2_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_allvsall_sse2_single.c [moved from src/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_allvsall_sse2_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_allvsall_sse2_single.h [moved from src/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_allvsall_sse2_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_allvsallgb_sse2_single.c [moved from src/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_allvsallgb_sse2_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_allvsallgb_sse2_single.h [moved from src/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_allvsallgb_sse2_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_sse2_single.c [moved from src/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_sse2_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_sse2_single.h [moved from src/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_sse2_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/sse_common_single.h [moved from src/gmxlib/nonbonded/nb_kernel_sse2_single/sse_common_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/.gitignore [moved from src/gmxlib/nonbonded/nb_kernel_ia64_single/.gitignore with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/Makefile.am [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/Makefile.am with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/README [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/README with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel010_x86_64_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel010_x86_64_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel010_x86_64_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel010_x86_64_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel010_x86_64_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel010_x86_64_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel030_x86_64_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel030_x86_64_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel030_x86_64_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel030_x86_64_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel030_x86_64_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel030_x86_64_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel100_x86_64_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel100_x86_64_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel100_x86_64_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel100_x86_64_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel100_x86_64_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel100_x86_64_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel101_x86_64_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel101_x86_64_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel101_x86_64_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel101_x86_64_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel101_x86_64_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel101_x86_64_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel102_x86_64_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel102_x86_64_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel102_x86_64_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel102_x86_64_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel102_x86_64_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel102_x86_64_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel103_x86_64_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel103_x86_64_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel103_x86_64_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel103_x86_64_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel103_x86_64_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel103_x86_64_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel104_x86_64_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel104_x86_64_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel104_x86_64_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel104_x86_64_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel104_x86_64_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel104_x86_64_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel110_x86_64_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel110_x86_64_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel110_x86_64_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel110_x86_64_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel110_x86_64_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel110_x86_64_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel111_x86_64_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel111_x86_64_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel111_x86_64_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel111_x86_64_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel111_x86_64_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel111_x86_64_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel112_x86_64_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel112_x86_64_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel112_x86_64_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel112_x86_64_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel112_x86_64_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel112_x86_64_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel113_x86_64_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel113_x86_64_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel113_x86_64_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel113_x86_64_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel113_x86_64_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel113_x86_64_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel114_x86_64_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel114_x86_64_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel114_x86_64_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel114_x86_64_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel114_x86_64_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel114_x86_64_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel130_x86_64_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel130_x86_64_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel130_x86_64_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel130_x86_64_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel130_x86_64_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel130_x86_64_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel131_x86_64_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel131_x86_64_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel131_x86_64_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel131_x86_64_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel131_x86_64_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel131_x86_64_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel132_x86_64_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel132_x86_64_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel132_x86_64_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel132_x86_64_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel132_x86_64_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel132_x86_64_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel133_x86_64_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel133_x86_64_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel133_x86_64_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel133_x86_64_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel133_x86_64_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel133_x86_64_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel134_x86_64_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel134_x86_64_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel134_x86_64_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel134_x86_64_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel134_x86_64_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel134_x86_64_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel200_x86_64_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel200_x86_64_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel200_x86_64_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel200_x86_64_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel200_x86_64_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel200_x86_64_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel201_x86_64_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel201_x86_64_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel201_x86_64_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel201_x86_64_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel201_x86_64_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel201_x86_64_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel202_x86_64_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel202_x86_64_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel202_x86_64_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel202_x86_64_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel202_x86_64_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel202_x86_64_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel203_x86_64_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel203_x86_64_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel203_x86_64_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel203_x86_64_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel203_x86_64_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel203_x86_64_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel204_x86_64_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel204_x86_64_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel204_x86_64_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel204_x86_64_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel204_x86_64_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel204_x86_64_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel210_x86_64_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel210_x86_64_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel210_x86_64_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel210_x86_64_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel210_x86_64_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel210_x86_64_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel211_x86_64_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel211_x86_64_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel211_x86_64_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel211_x86_64_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel211_x86_64_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel211_x86_64_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel212_x86_64_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel212_x86_64_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel212_x86_64_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel212_x86_64_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel212_x86_64_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel212_x86_64_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel213_x86_64_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel213_x86_64_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel213_x86_64_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel213_x86_64_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel213_x86_64_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel213_x86_64_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel214_x86_64_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel214_x86_64_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel214_x86_64_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel214_x86_64_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel214_x86_64_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel214_x86_64_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel230_x86_64_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel230_x86_64_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel230_x86_64_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel230_x86_64_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel230_x86_64_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel230_x86_64_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel231_x86_64_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel231_x86_64_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel231_x86_64_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel231_x86_64_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel231_x86_64_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel231_x86_64_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel232_x86_64_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel232_x86_64_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel232_x86_64_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel232_x86_64_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel232_x86_64_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel232_x86_64_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel233_x86_64_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel233_x86_64_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel233_x86_64_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel233_x86_64_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel233_x86_64_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel233_x86_64_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel234_x86_64_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel234_x86_64_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel234_x86_64_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel234_x86_64_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel234_x86_64_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel234_x86_64_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel300_x86_64_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel300_x86_64_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel300_x86_64_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel300_x86_64_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel300_x86_64_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel300_x86_64_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel301_x86_64_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel301_x86_64_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel301_x86_64_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel301_x86_64_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel301_x86_64_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel301_x86_64_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel302_x86_64_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel302_x86_64_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel302_x86_64_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel302_x86_64_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel302_x86_64_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel302_x86_64_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel303_x86_64_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel303_x86_64_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel303_x86_64_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel303_x86_64_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel303_x86_64_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel303_x86_64_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel304_x86_64_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel304_x86_64_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel304_x86_64_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel304_x86_64_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel304_x86_64_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel304_x86_64_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel310_x86_64_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel310_x86_64_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel310_x86_64_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel310_x86_64_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel310_x86_64_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel310_x86_64_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel311_x86_64_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel311_x86_64_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel311_x86_64_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel311_x86_64_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel311_x86_64_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel311_x86_64_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel312_x86_64_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel312_x86_64_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel312_x86_64_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel312_x86_64_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel312_x86_64_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel312_x86_64_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel313_x86_64_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel313_x86_64_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel313_x86_64_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel313_x86_64_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel313_x86_64_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel313_x86_64_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel314_x86_64_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel314_x86_64_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel314_x86_64_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel314_x86_64_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel314_x86_64_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel314_x86_64_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel330_x86_64_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel330_x86_64_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel330_x86_64_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel330_x86_64_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel330_x86_64_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel330_x86_64_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel331_x86_64_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel331_x86_64_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel331_x86_64_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel331_x86_64_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel331_x86_64_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel331_x86_64_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel332_x86_64_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel332_x86_64_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel332_x86_64_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel332_x86_64_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel332_x86_64_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel332_x86_64_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel333_x86_64_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel333_x86_64_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel333_x86_64_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel333_x86_64_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel333_x86_64_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel333_x86_64_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel334_x86_64_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel334_x86_64_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel334_x86_64_sse.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel334_x86_64_sse.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel334_x86_64_sse_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel334_x86_64_sse_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel400_x86_64_sse.c [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel400_x86_64_sse.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel400_x86_64_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel400_x86_64_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel410_x86_64_sse.c [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel410_x86_64_sse.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel410_x86_64_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel410_x86_64_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel430_x86_64_sse.c [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel430_x86_64_sse.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel430_x86_64_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel430_x86_64_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel_allvsall_sse2_single.c [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel_allvsall_sse2_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel_allvsall_sse2_single.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel_allvsall_sse2_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel_allvsallgb_sse2_single.c [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel_allvsallgb_sse2_single.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel_allvsallgb_sse2_single.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel_allvsallgb_sse2_single.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel_x86_64_sse.c [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel_x86_64_sse.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel_x86_64_sse.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel_x86_64_sse.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel_x86_64_sse_test_asm.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel_x86_64_sse_test_asm.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel_x86_64_sse_test_asm.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel_x86_64_sse_test_asm.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel_x86_64_sse_test_asm_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse/nb_kernel_x86_64_sse_test_asm_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/.gitignore [moved from src/gmxlib/nonbonded/nb_kernel_power6/.gitignore with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/Makefile.am [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/Makefile.am with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/README [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/README with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel010_x86_64_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel010_x86_64_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel010_x86_64_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel010_x86_64_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel010_x86_64_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel010_x86_64_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel030_x86_64_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel030_x86_64_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel030_x86_64_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel030_x86_64_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel030_x86_64_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel030_x86_64_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel100_x86_64_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel100_x86_64_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel100_x86_64_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel100_x86_64_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel100_x86_64_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel100_x86_64_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel101_x86_64_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel101_x86_64_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel101_x86_64_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel101_x86_64_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel101_x86_64_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel101_x86_64_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel102_x86_64_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel102_x86_64_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel102_x86_64_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel102_x86_64_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel102_x86_64_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel102_x86_64_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel103_x86_64_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel103_x86_64_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel103_x86_64_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel103_x86_64_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel103_x86_64_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel103_x86_64_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel104_x86_64_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel104_x86_64_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel104_x86_64_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel104_x86_64_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel104_x86_64_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel104_x86_64_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel110_x86_64_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel110_x86_64_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel110_x86_64_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel110_x86_64_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel110_x86_64_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel110_x86_64_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel111_x86_64_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel111_x86_64_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel111_x86_64_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel111_x86_64_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel111_x86_64_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel111_x86_64_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel112_x86_64_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel112_x86_64_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel112_x86_64_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel112_x86_64_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel112_x86_64_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel112_x86_64_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel113_x86_64_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel113_x86_64_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel113_x86_64_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel113_x86_64_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel113_x86_64_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel113_x86_64_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel114_x86_64_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel114_x86_64_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel114_x86_64_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel114_x86_64_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel114_x86_64_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel114_x86_64_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel130_x86_64_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel130_x86_64_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel130_x86_64_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel130_x86_64_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel130_x86_64_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel130_x86_64_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel131_x86_64_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel131_x86_64_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel131_x86_64_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel131_x86_64_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel131_x86_64_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel131_x86_64_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel132_x86_64_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel132_x86_64_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel132_x86_64_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel132_x86_64_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel132_x86_64_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel132_x86_64_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel133_x86_64_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel133_x86_64_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel133_x86_64_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel133_x86_64_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel133_x86_64_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel133_x86_64_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel134_x86_64_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel134_x86_64_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel134_x86_64_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel134_x86_64_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel134_x86_64_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel134_x86_64_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel200_x86_64_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel200_x86_64_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel200_x86_64_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel200_x86_64_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel200_x86_64_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel200_x86_64_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel201_x86_64_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel201_x86_64_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel201_x86_64_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel201_x86_64_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel201_x86_64_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel201_x86_64_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel202_x86_64_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel202_x86_64_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel202_x86_64_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel202_x86_64_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel202_x86_64_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel202_x86_64_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel203_x86_64_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel203_x86_64_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel203_x86_64_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel203_x86_64_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel203_x86_64_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel203_x86_64_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel204_x86_64_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel204_x86_64_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel204_x86_64_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel204_x86_64_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel204_x86_64_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel204_x86_64_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel210_x86_64_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel210_x86_64_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel210_x86_64_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel210_x86_64_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel210_x86_64_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel210_x86_64_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel211_x86_64_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel211_x86_64_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel211_x86_64_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel211_x86_64_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel211_x86_64_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel211_x86_64_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel212_x86_64_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel212_x86_64_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel212_x86_64_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel212_x86_64_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel212_x86_64_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel212_x86_64_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel213_x86_64_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel213_x86_64_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel213_x86_64_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel213_x86_64_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel213_x86_64_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel213_x86_64_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel214_x86_64_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel214_x86_64_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel214_x86_64_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel214_x86_64_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel214_x86_64_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel214_x86_64_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel230_x86_64_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel230_x86_64_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel230_x86_64_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel230_x86_64_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel230_x86_64_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel230_x86_64_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel231_x86_64_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel231_x86_64_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel231_x86_64_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel231_x86_64_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel231_x86_64_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel231_x86_64_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel232_x86_64_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel232_x86_64_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel232_x86_64_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel232_x86_64_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel232_x86_64_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel232_x86_64_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel233_x86_64_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel233_x86_64_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel233_x86_64_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel233_x86_64_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel233_x86_64_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel233_x86_64_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel234_x86_64_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel234_x86_64_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel234_x86_64_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel234_x86_64_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel234_x86_64_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel234_x86_64_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel300_x86_64_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel300_x86_64_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel300_x86_64_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel300_x86_64_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel300_x86_64_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel300_x86_64_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel301_x86_64_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel301_x86_64_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel301_x86_64_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel301_x86_64_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel301_x86_64_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel301_x86_64_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel302_x86_64_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel302_x86_64_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel302_x86_64_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel302_x86_64_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel302_x86_64_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel302_x86_64_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel303_x86_64_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel303_x86_64_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel303_x86_64_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel303_x86_64_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel303_x86_64_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel303_x86_64_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel304_x86_64_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel304_x86_64_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel304_x86_64_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel304_x86_64_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel304_x86_64_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel304_x86_64_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel310_x86_64_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel310_x86_64_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel310_x86_64_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel310_x86_64_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel310_x86_64_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel310_x86_64_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel311_x86_64_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel311_x86_64_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel311_x86_64_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel311_x86_64_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel311_x86_64_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel311_x86_64_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel312_x86_64_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel312_x86_64_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel312_x86_64_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel312_x86_64_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel312_x86_64_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel312_x86_64_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel313_x86_64_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel313_x86_64_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel313_x86_64_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel313_x86_64_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel313_x86_64_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel313_x86_64_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel314_x86_64_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel314_x86_64_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel314_x86_64_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel314_x86_64_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel314_x86_64_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel314_x86_64_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel330_x86_64_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel330_x86_64_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel330_x86_64_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel330_x86_64_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel330_x86_64_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel330_x86_64_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel331_x86_64_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel331_x86_64_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel331_x86_64_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel331_x86_64_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel331_x86_64_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel331_x86_64_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel332_x86_64_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel332_x86_64_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel332_x86_64_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel332_x86_64_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel332_x86_64_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel332_x86_64_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel333_x86_64_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel333_x86_64_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel333_x86_64_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel333_x86_64_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel333_x86_64_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel333_x86_64_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel334_x86_64_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel334_x86_64_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel334_x86_64_sse2.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel334_x86_64_sse2.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel334_x86_64_sse2_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel334_x86_64_sse2_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel400_x86_64_sse2.c [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel400_x86_64_sse2.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel400_x86_64_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel400_x86_64_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel410_x86_64_sse2.c [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel410_x86_64_sse2.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel410_x86_64_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel410_x86_64_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel430_x86_64_sse2.c [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel430_x86_64_sse2.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel430_x86_64_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel430_x86_64_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel_allvsall_sse2_double.c [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel_allvsall_sse2_double.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel_allvsall_sse2_double.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel_allvsall_sse2_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel_allvsallgb_sse2_double.c [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel_allvsallgb_sse2_double.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel_allvsallgb_sse2_double.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel_allvsallgb_sse2_double.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel_x86_64_sse2.c [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel_x86_64_sse2.c with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel_x86_64_sse2.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel_x86_64_sse2.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel_x86_64_sse2_test_asm.h [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel_x86_64_sse2_test_asm.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel_x86_64_sse2_test_asm.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel_x86_64_sse2_test_asm.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel_x86_64_sse2_test_intel_syntax.s [moved from src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/nb_kernel_x86_64_sse2_test_intel_syntax.s with 100% similarity]
src/gromacs/gmxlib/nonbonded/nb_kerneltype.h [moved from src/gmxlib/nonbonded/nb_kerneltype.h with 100% similarity]
src/gromacs/gmxlib/nonbonded/nonbonded.c [moved from src/gmxlib/nonbonded/nonbonded.c with 100% similarity]
src/gromacs/gmxlib/nrama.c [moved from src/gmxlib/nrama.c with 100% similarity]
src/gromacs/gmxlib/nrjac.c [moved from src/gmxlib/nrjac.c with 100% similarity]
src/gromacs/gmxlib/nrnb.c [moved from src/gmxlib/nrnb.c with 100% similarity]
src/gromacs/gmxlib/oenv.c [moved from src/gmxlib/oenv.c with 100% similarity]
src/gromacs/gmxlib/orires.c [moved from src/gmxlib/orires.c with 100% similarity]
src/gromacs/gmxlib/pargs.c [moved from src/gmxlib/pargs.c with 100% similarity]
src/gromacs/gmxlib/pbc.c [moved from src/gmxlib/pbc.c with 100% similarity]
src/gromacs/gmxlib/pdbio.c [moved from src/gmxlib/pdbio.c with 100% similarity]
src/gromacs/gmxlib/physics.c [new file with mode: 0644]
src/gromacs/gmxlib/physics_test.c [new file with mode: 0644]
src/gromacs/gmxlib/princ.c [moved from src/gmxlib/princ.c with 100% similarity]
src/gromacs/gmxlib/rando.c [moved from src/gmxlib/rando.c with 100% similarity]
src/gromacs/gmxlib/random.c [moved from src/gmxlib/random.c with 100% similarity]
src/gromacs/gmxlib/rbin.c [moved from src/gmxlib/rbin.c with 100% similarity]
src/gromacs/gmxlib/readinp.c [moved from src/gmxlib/readinp.c with 100% similarity]
src/gromacs/gmxlib/replace.c [moved from src/gmxlib/replace.c with 100% similarity]
src/gromacs/gmxlib/replace.h [moved from src/gmxlib/replace.h with 100% similarity]
src/gromacs/gmxlib/rmpbc.c [moved from src/gmxlib/rmpbc.c with 100% similarity]
src/gromacs/gmxlib/sfactor.c [moved from src/gmxlib/sfactor.c with 100% similarity]
src/gromacs/gmxlib/shift_util.c [moved from src/gmxlib/shift_util.c with 100% similarity]
src/gromacs/gmxlib/sighandler.c [moved from src/gmxlib/sighandler.c with 100% similarity]
src/gromacs/gmxlib/smalloc.c [moved from src/gmxlib/smalloc.c with 100% similarity]
src/gromacs/gmxlib/sortwater.c [moved from src/gmxlib/sortwater.c with 100% similarity]
src/gromacs/gmxlib/sparsematrix.c [moved from src/gmxlib/sparsematrix.c with 100% similarity]
src/gromacs/gmxlib/splitter.c [moved from src/gmxlib/splitter.c with 100% similarity]
src/gromacs/gmxlib/statistics/gmx_statistics.c [new file with mode: 0644]
src/gromacs/gmxlib/statistics/gmx_statistics_test.c [moved from src/gmxlib/statistics/gmx_statistics_test.c with 100% similarity]
src/gromacs/gmxlib/statistics/histogram.c [moved from src/gmxlib/statistics/histogram.c with 100% similarity]
src/gromacs/gmxlib/statutil.c [moved from src/gmxlib/statutil.c with 100% similarity]
src/gromacs/gmxlib/strdb.c [moved from src/gmxlib/strdb.c with 100% similarity]
src/gromacs/gmxlib/string2.c [new file with mode: 0644]
src/gromacs/gmxlib/symtab.c [moved from src/gmxlib/symtab.c with 100% similarity]
src/gromacs/gmxlib/tcontrol.c [moved from src/gmxlib/tcontrol.c with 100% similarity]
src/gromacs/gmxlib/thread_mpi/CMakeLists.txt [moved from src/gmxlib/thread_mpi/CMakeLists.txt with 100% similarity]
src/gromacs/gmxlib/thread_mpi/alltoall.c [moved from src/gmxlib/thread_mpi/alltoall.c with 100% similarity]
src/gromacs/gmxlib/thread_mpi/barrier.c [moved from src/gmxlib/thread_mpi/barrier.c with 100% similarity]
src/gromacs/gmxlib/thread_mpi/bcast.c [moved from src/gmxlib/thread_mpi/bcast.c with 100% similarity]
src/gromacs/gmxlib/thread_mpi/collective.c [moved from src/gmxlib/thread_mpi/collective.c with 100% similarity]
src/gromacs/gmxlib/thread_mpi/collective.h [moved from src/gmxlib/thread_mpi/collective.h with 100% similarity]
src/gromacs/gmxlib/thread_mpi/comm.c [moved from src/gmxlib/thread_mpi/comm.c with 100% similarity]
src/gromacs/gmxlib/thread_mpi/errhandler.c [moved from src/gmxlib/thread_mpi/errhandler.c with 100% similarity]
src/gromacs/gmxlib/thread_mpi/event.c [moved from src/gmxlib/thread_mpi/event.c with 100% similarity]
src/gromacs/gmxlib/thread_mpi/gather.c [moved from src/gmxlib/thread_mpi/gather.c with 100% similarity]
src/gromacs/gmxlib/thread_mpi/group.c [moved from src/gmxlib/thread_mpi/group.c with 100% similarity]
src/gromacs/gmxlib/thread_mpi/hwinfo.c [moved from src/gmxlib/thread_mpi/hwinfo.c with 100% similarity]
src/gromacs/gmxlib/thread_mpi/impl.h [moved from src/gmxlib/thread_mpi/impl.h with 100% similarity]
src/gromacs/gmxlib/thread_mpi/list.c [moved from src/gmxlib/thread_mpi/list.c with 100% similarity]
src/gromacs/gmxlib/thread_mpi/lock.c [moved from src/gmxlib/thread_mpi/lock.c with 100% similarity]
src/gromacs/gmxlib/thread_mpi/once.c [moved from src/gmxlib/thread_mpi/once.c with 100% similarity]
src/gromacs/gmxlib/thread_mpi/p2p.h [moved from src/gmxlib/thread_mpi/p2p.h with 100% similarity]
src/gromacs/gmxlib/thread_mpi/p2p_protocol.c [moved from src/gmxlib/thread_mpi/p2p_protocol.c with 100% similarity]
src/gromacs/gmxlib/thread_mpi/p2p_send_recv.c [moved from src/gmxlib/thread_mpi/p2p_send_recv.c with 100% similarity]
src/gromacs/gmxlib/thread_mpi/p2p_wait.c [moved from src/gmxlib/thread_mpi/p2p_wait.c with 100% similarity]
src/gromacs/gmxlib/thread_mpi/profile.c [moved from src/gmxlib/thread_mpi/profile.c with 100% similarity]
src/gromacs/gmxlib/thread_mpi/profile.h [moved from src/gmxlib/thread_mpi/profile.h with 100% similarity]
src/gromacs/gmxlib/thread_mpi/pthreads.c [moved from src/gmxlib/thread_mpi/pthreads.c with 100% similarity]
src/gromacs/gmxlib/thread_mpi/pthreads.h [moved from src/gmxlib/thread_mpi/pthreads.h with 100% similarity]
src/gromacs/gmxlib/thread_mpi/reduce.c [moved from src/gmxlib/thread_mpi/reduce.c with 100% similarity]
src/gromacs/gmxlib/thread_mpi/reduce_fast.c [moved from src/gmxlib/thread_mpi/reduce_fast.c with 100% similarity]
src/gromacs/gmxlib/thread_mpi/scatter.c [moved from src/gmxlib/thread_mpi/scatter.c with 100% similarity]
src/gromacs/gmxlib/thread_mpi/settings.h [moved from src/gmxlib/thread_mpi/settings.h with 100% similarity]
src/gromacs/gmxlib/thread_mpi/tmpi_init.c [moved from src/gmxlib/thread_mpi/tmpi_init.c with 100% similarity]
src/gromacs/gmxlib/thread_mpi/tmpi_ops.h [moved from src/gmxlib/thread_mpi/tmpi_ops.h with 100% similarity]
src/gromacs/gmxlib/thread_mpi/topology.c [moved from src/gmxlib/thread_mpi/topology.c with 100% similarity]
src/gromacs/gmxlib/thread_mpi/type.c [moved from src/gmxlib/thread_mpi/type.c with 100% similarity]
src/gromacs/gmxlib/thread_mpi/winthreads.c [moved from src/gmxlib/thread_mpi/winthreads.c with 100% similarity]
src/gromacs/gmxlib/thread_mpi/winthreads.h [moved from src/gmxlib/thread_mpi/winthreads.h with 100% similarity]
src/gromacs/gmxlib/topsort.c [moved from src/gmxlib/topsort.c with 100% similarity]
src/gromacs/gmxlib/tpxio.c [new file with mode: 0644]
src/gromacs/gmxlib/trajana/displacement.c [moved from src/gmxlib/trajana/displacement.c with 100% similarity]
src/gromacs/gmxlib/trnio.c [moved from src/gmxlib/trnio.c with 100% similarity]
src/gromacs/gmxlib/trxio.c [moved from src/gmxlib/trxio.c with 100% similarity]
src/gromacs/gmxlib/txtdump.c [new file with mode: 0644]
src/gromacs/gmxlib/typedefs.c [moved from src/gmxlib/typedefs.c with 100% similarity]
src/gromacs/gmxlib/version.h [moved from src/gmxlib/version.h with 100% similarity]
src/gromacs/gmxlib/viewit.c [moved from src/gmxlib/viewit.c with 100% similarity]
src/gromacs/gmxlib/vmddlopen.c [moved from src/gmxlib/vmddlopen.c with 100% similarity]
src/gromacs/gmxlib/vmdio.c [moved from src/gmxlib/vmdio.c with 100% similarity]
src/gromacs/gmxlib/warninp.c [moved from src/gmxlib/warninp.c with 100% similarity]
src/gromacs/gmxlib/wgms.c [moved from src/gmxlib/wgms.c with 100% similarity]
src/gromacs/gmxlib/wman.c [moved from src/gmxlib/wman.c with 100% similarity]
src/gromacs/gmxlib/writeps.c [moved from src/gmxlib/writeps.c with 100% similarity]
src/gromacs/gmxlib/xdrd.c [moved from src/gmxlib/xdrd.c with 100% similarity]
src/gromacs/gmxlib/xtcio.c [moved from src/gmxlib/xtcio.c with 100% similarity]
src/gromacs/gmxlib/xvgr.c [moved from src/gmxlib/xvgr.c with 100% similarity]
src/gromacs/gromacs.h [new file with mode: 0644]
src/gromacs/legacyheaders/3dview.h [moved from include/3dview.h with 100% similarity]
src/gromacs/legacyheaders/CMakeLists.txt [new file with mode: 0644]
src/gromacs/legacyheaders/assert.h [moved from include/assert.h with 100% similarity]
src/gromacs/legacyheaders/atomprop.h [moved from include/atomprop.h with 100% similarity]
src/gromacs/legacyheaders/bondf.h [moved from include/bondf.h with 100% similarity]
src/gromacs/legacyheaders/calcgrid.h [moved from include/calcgrid.h with 100% similarity]
src/gromacs/legacyheaders/calch.h [moved from include/calch.h with 100% similarity]
src/gromacs/legacyheaders/calcmu.h [moved from include/calcmu.h with 100% similarity]
src/gromacs/legacyheaders/chargegroup.h [moved from include/chargegroup.h with 100% similarity]
src/gromacs/legacyheaders/checkpoint.h [moved from include/checkpoint.h with 100% similarity]
src/gromacs/legacyheaders/confio.h [moved from include/confio.h with 100% similarity]
src/gromacs/legacyheaders/constr.h [moved from include/constr.h with 100% similarity]
src/gromacs/legacyheaders/copyrite.h [moved from include/copyrite.h with 100% similarity]
src/gromacs/legacyheaders/coulomb.h [moved from include/coulomb.h with 100% similarity]
src/gromacs/legacyheaders/dihre.h [moved from include/dihre.h with 100% similarity]
src/gromacs/legacyheaders/displacement.h [moved from include/displacement.h with 100% similarity]
src/gromacs/legacyheaders/disre.h [moved from include/disre.h with 100% similarity]
src/gromacs/legacyheaders/do_fit.h [moved from include/do_fit.h with 100% similarity]
src/gromacs/legacyheaders/domdec.h [moved from include/domdec.h with 100% similarity]
src/gromacs/legacyheaders/domdec_network.h [moved from include/domdec_network.h with 100% similarity]
src/gromacs/legacyheaders/ebin.h [moved from include/ebin.h with 100% similarity]
src/gromacs/legacyheaders/edsam.h [moved from include/edsam.h with 100% similarity]
src/gromacs/legacyheaders/enxio.h [moved from include/enxio.h with 100% similarity]
src/gromacs/legacyheaders/ffscanf.h [moved from include/ffscanf.h with 100% similarity]
src/gromacs/legacyheaders/filenm.h [moved from include/filenm.h with 100% similarity]
src/gromacs/legacyheaders/force.h [moved from include/force.h with 100% similarity]
src/gromacs/legacyheaders/futil.h [moved from include/futil.h with 100% similarity]
src/gromacs/legacyheaders/gbutil.h [moved from include/gbutil.h with 100% similarity]
src/gromacs/legacyheaders/gen_ad.h [moved from include/gen_ad.h with 100% similarity]
src/gromacs/legacyheaders/genborn.h [moved from include/genborn.h with 100% similarity]
src/gromacs/legacyheaders/gmx_ana.h [moved from include/gmx_ana.h with 100% similarity]
src/gromacs/legacyheaders/gmx_arpack.h [moved from include/gmx_arpack.h with 100% similarity]
src/gromacs/legacyheaders/gmx_blas.h [moved from include/gmx_blas.h with 100% similarity]
src/gromacs/legacyheaders/gmx_cyclecounter.h [moved from include/gmx_cyclecounter.h with 100% similarity]
src/gromacs/legacyheaders/gmx_fatal.h [moved from include/gmx_fatal.h with 100% similarity]
src/gromacs/legacyheaders/gmx_fft.h [moved from include/gmx_fft.h with 100% similarity]
src/gromacs/legacyheaders/gmx_ga2la.h [moved from include/gmx_ga2la.h with 100% similarity]
src/gromacs/legacyheaders/gmx_lapack.h [moved from include/gmx_lapack.h with 100% similarity]
src/gromacs/legacyheaders/gmx_matrix.h [moved from include/gmx_matrix.h with 100% similarity]
src/gromacs/legacyheaders/gmx_parallel_3dfft.h [moved from include/gmx_parallel_3dfft.h with 100% similarity]
src/gromacs/legacyheaders/gmx_random.h [moved from include/gmx_random.h with 100% similarity]
src/gromacs/legacyheaders/gmx_sort.h [moved from include/gmx_sort.h with 100% similarity]
src/gromacs/legacyheaders/gmx_sse2_double.h [moved from include/gmx_sse2_double.h with 100% similarity]
src/gromacs/legacyheaders/gmx_sse2_single.h [moved from include/gmx_sse2_single.h with 100% similarity]
src/gromacs/legacyheaders/gmx_statistics.h [new file with mode: 0644]
src/gromacs/legacyheaders/gmx_system_xdr.h [moved from include/gmx_system_xdr.h with 100% similarity]
src/gromacs/legacyheaders/gmx_wallcycle.h [new file with mode: 0644]
src/gromacs/legacyheaders/gmxcomplex.h [moved from include/gmxcomplex.h with 100% similarity]
src/gromacs/legacyheaders/gmxcpp.h [moved from include/gmxcpp.h with 100% similarity]
src/gromacs/legacyheaders/gmxfio.h [new file with mode: 0644]
src/gromacs/legacyheaders/gpp_atomtype.h [moved from include/gpp_atomtype.h with 100% similarity]
src/gromacs/legacyheaders/gpp_nextnb.h [moved from include/gpp_nextnb.h with 100% similarity]
src/gromacs/legacyheaders/grompp.h [moved from include/grompp.h with 100% similarity]
src/gromacs/legacyheaders/gstat.h [moved from include/gstat.h with 100% similarity]
src/gromacs/legacyheaders/hackblock.h [moved from include/hackblock.h with 100% similarity]
src/gromacs/legacyheaders/histogram.h [moved from include/histogram.h with 100% similarity]
src/gromacs/legacyheaders/index.h [moved from include/index.h with 100% similarity]
src/gromacs/legacyheaders/inputrec.h [moved from include/inputrec.h with 100% similarity]
src/gromacs/legacyheaders/invblock.h [moved from include/invblock.h with 100% similarity]
src/gromacs/legacyheaders/macros.h [moved from include/macros.h with 100% similarity]
src/gromacs/legacyheaders/magic.h [moved from include/magic.h with 100% similarity]
src/gromacs/legacyheaders/main.h [moved from include/main.h with 100% similarity]
src/gromacs/legacyheaders/mainpage.h [moved from include/mainpage.h with 100% similarity]
src/gromacs/legacyheaders/maths.h [moved from include/maths.h with 100% similarity]
src/gromacs/legacyheaders/matio.h [moved from include/matio.h with 100% similarity]
src/gromacs/legacyheaders/md5.h [moved from include/md5.h with 100% similarity]
src/gromacs/legacyheaders/mdatoms.h [moved from include/mdatoms.h with 100% similarity]
src/gromacs/legacyheaders/mdebin.h [moved from include/mdebin.h with 100% similarity]
src/gromacs/legacyheaders/mdrun.h [new file with mode: 0644]
src/gromacs/legacyheaders/membed.h [new file with mode: 0644]
src/gromacs/legacyheaders/molfile_plugin.h [moved from include/molfile_plugin.h with 100% similarity]
src/gromacs/legacyheaders/mpelogging.h [new file with mode: 0644]
src/gromacs/legacyheaders/mshift.h [moved from include/mshift.h with 100% similarity]
src/gromacs/legacyheaders/mtop_util.h [moved from include/mtop_util.h with 100% similarity]
src/gromacs/legacyheaders/mtxio.h [moved from include/mtxio.h with 100% similarity]
src/gromacs/legacyheaders/mvdata.h [moved from include/mvdata.h with 100% similarity]
src/gromacs/legacyheaders/names.h [new file with mode: 0644]
src/gromacs/legacyheaders/network.h [moved from include/network.h with 100% similarity]
src/gromacs/legacyheaders/nonbonded.h [moved from include/nonbonded.h with 100% similarity]
src/gromacs/legacyheaders/nrama.h [moved from include/nrama.h with 100% similarity]
src/gromacs/legacyheaders/nrjac.h [moved from include/nrjac.h with 100% similarity]
src/gromacs/legacyheaders/nrnb.h [moved from include/nrnb.h with 100% similarity]
src/gromacs/legacyheaders/ns.h [moved from include/ns.h with 100% similarity]
src/gromacs/legacyheaders/nsgrid.h [moved from include/nsgrid.h with 100% similarity]
src/gromacs/legacyheaders/oenv.h [moved from include/oenv.h with 100% similarity]
src/gromacs/legacyheaders/orires.h [moved from include/orires.h with 100% similarity]
src/gromacs/legacyheaders/partdec.h [moved from include/partdec.h with 100% similarity]
src/gromacs/legacyheaders/pbc.h [moved from include/pbc.h with 100% similarity]
src/gromacs/legacyheaders/pdb2top.h [moved from include/pdb2top.h with 100% similarity]
src/gromacs/legacyheaders/pdbio.h [moved from include/pdbio.h with 100% similarity]
src/gromacs/legacyheaders/perf_est.h [moved from include/perf_est.h with 100% similarity]
src/gromacs/legacyheaders/physics.h [new file with mode: 0644]
src/gromacs/legacyheaders/pme.h [moved from include/pme.h with 100% similarity]
src/gromacs/legacyheaders/pppm.h [moved from include/pppm.h with 100% similarity]
src/gromacs/legacyheaders/princ.h [moved from include/princ.h with 100% similarity]
src/gromacs/legacyheaders/pull.h [moved from include/pull.h with 100% similarity]
src/gromacs/legacyheaders/pull_rotation.h [new file with mode: 0644]
src/gromacs/legacyheaders/qmmm.h [moved from include/qmmm.h with 100% similarity]
src/gromacs/legacyheaders/random.h [moved from include/random.h with 100% similarity]
src/gromacs/legacyheaders/rbin.h [moved from include/rbin.h with 100% similarity]
src/gromacs/legacyheaders/rdgroup.h [moved from include/rdgroup.h with 100% similarity]
src/gromacs/legacyheaders/readinp.h [moved from include/readinp.h with 100% similarity]
src/gromacs/legacyheaders/resall.h [moved from include/resall.h with 100% similarity]
src/gromacs/legacyheaders/rmpbc.h [moved from include/rmpbc.h with 100% similarity]
src/gromacs/legacyheaders/sfactor.h [moved from include/sfactor.h with 100% similarity]
src/gromacs/legacyheaders/shellfc.h [moved from include/shellfc.h with 100% similarity]
src/gromacs/legacyheaders/shift.h [moved from include/shift.h with 100% similarity]
src/gromacs/legacyheaders/sighandler.h [moved from include/sighandler.h with 100% similarity]
src/gromacs/legacyheaders/smalloc.h [moved from include/smalloc.h with 100% similarity]
src/gromacs/legacyheaders/sortwater.h [moved from include/sortwater.h with 100% similarity]
src/gromacs/legacyheaders/sparsematrix.h [moved from include/sparsematrix.h with 100% similarity]
src/gromacs/legacyheaders/split.h [moved from include/split.h with 100% similarity]
src/gromacs/legacyheaders/splitter.h [moved from include/splitter.h with 100% similarity]
src/gromacs/legacyheaders/statutil.h [moved from include/statutil.h with 100% similarity]
src/gromacs/legacyheaders/strdb.h [moved from include/strdb.h with 100% similarity]
src/gromacs/legacyheaders/string2.h [new file with mode: 0644]
src/gromacs/legacyheaders/symtab.h [moved from include/symtab.h with 100% similarity]
src/gromacs/legacyheaders/sysstuff.h [moved from include/sysstuff.h with 100% similarity]
src/gromacs/legacyheaders/tgroup.h [moved from include/tgroup.h with 100% similarity]
src/gromacs/legacyheaders/thread_mpi.h [moved from include/thread_mpi.h with 100% similarity]
src/gromacs/legacyheaders/thread_mpi/atomic.h [moved from include/thread_mpi/atomic.h with 100% similarity]
src/gromacs/legacyheaders/thread_mpi/atomic/cycles.h [moved from include/thread_mpi/atomic/cycles.h with 100% similarity]
src/gromacs/legacyheaders/thread_mpi/atomic/gcc.h [moved from include/thread_mpi/atomic/gcc.h with 100% similarity]
src/gromacs/legacyheaders/thread_mpi/atomic/gcc_ia64.h [moved from include/thread_mpi/atomic/gcc_ia64.h with 100% similarity]
src/gromacs/legacyheaders/thread_mpi/atomic/gcc_intrinsics.h [moved from include/thread_mpi/atomic/gcc_intrinsics.h with 100% similarity]
src/gromacs/legacyheaders/thread_mpi/atomic/gcc_ppc.h [moved from include/thread_mpi/atomic/gcc_ppc.h with 100% similarity]
src/gromacs/legacyheaders/thread_mpi/atomic/gcc_spinlock.h [moved from include/thread_mpi/atomic/gcc_spinlock.h with 100% similarity]
src/gromacs/legacyheaders/thread_mpi/atomic/gcc_x86.h [moved from include/thread_mpi/atomic/gcc_x86.h with 100% similarity]
src/gromacs/legacyheaders/thread_mpi/atomic/msvc.h [moved from include/thread_mpi/atomic/msvc.h with 100% similarity]
src/gromacs/legacyheaders/thread_mpi/atomic/xlc_ppc.h [moved from include/thread_mpi/atomic/xlc_ppc.h with 100% similarity]
src/gromacs/legacyheaders/thread_mpi/barrier.h [moved from include/thread_mpi/barrier.h with 100% similarity]
src/gromacs/legacyheaders/thread_mpi/collective.h [moved from include/thread_mpi/collective.h with 100% similarity]
src/gromacs/legacyheaders/thread_mpi/event.h [moved from include/thread_mpi/event.h with 100% similarity]
src/gromacs/legacyheaders/thread_mpi/hwinfo.h [moved from include/thread_mpi/hwinfo.h with 100% similarity]
src/gromacs/legacyheaders/thread_mpi/list.h [moved from include/thread_mpi/list.h with 100% similarity]
src/gromacs/legacyheaders/thread_mpi/lock.h [moved from include/thread_mpi/lock.h with 100% similarity]
src/gromacs/legacyheaders/thread_mpi/mpi_bindings.h [moved from include/thread_mpi/mpi_bindings.h with 100% similarity]
src/gromacs/legacyheaders/thread_mpi/threads.h [moved from include/thread_mpi/threads.h with 100% similarity]
src/gromacs/legacyheaders/thread_mpi/tmpi.h [moved from include/thread_mpi/tmpi.h with 100% similarity]
src/gromacs/legacyheaders/thread_mpi/wait.h [moved from include/thread_mpi/wait.h with 100% similarity]
src/gromacs/legacyheaders/tmpi.h [moved from include/tmpi.h with 100% similarity]
src/gromacs/legacyheaders/topsort.h [moved from include/topsort.h with 100% similarity]
src/gromacs/legacyheaders/toputil.h [moved from include/toputil.h with 100% similarity]
src/gromacs/legacyheaders/tpxio.h [moved from include/tpxio.h with 100% similarity]
src/gromacs/legacyheaders/trnio.h [moved from include/trnio.h with 100% similarity]
src/gromacs/legacyheaders/txtdump.h [moved from include/txtdump.h with 100% similarity]
src/gromacs/legacyheaders/typedefs.h [moved from include/typedefs.h with 100% similarity]
src/gromacs/legacyheaders/types/atoms.h [moved from include/types/atoms.h with 100% similarity]
src/gromacs/legacyheaders/types/block.h [moved from include/types/block.h with 100% similarity]
src/gromacs/legacyheaders/types/commrec.h [moved from include/types/commrec.h with 100% similarity]
src/gromacs/legacyheaders/types/constr.h [moved from include/types/constr.h with 100% similarity]
src/gromacs/legacyheaders/types/energy.h [moved from include/types/energy.h with 100% similarity]
src/gromacs/legacyheaders/types/enums.h [new file with mode: 0644]
src/gromacs/legacyheaders/types/fcdata.h [moved from include/types/fcdata.h with 100% similarity]
src/gromacs/legacyheaders/types/filenm.h [moved from include/types/filenm.h with 100% similarity]
src/gromacs/legacyheaders/types/forcerec.h [moved from include/types/forcerec.h with 100% similarity]
src/gromacs/legacyheaders/types/genborn.h [moved from include/types/genborn.h with 100% similarity]
src/gromacs/legacyheaders/types/graph.h [moved from include/types/graph.h with 100% similarity]
src/gromacs/legacyheaders/types/group.h [moved from include/types/group.h with 100% similarity]
src/gromacs/legacyheaders/types/idef.h [moved from include/types/idef.h with 100% similarity]
src/gromacs/legacyheaders/types/ifunc.h [moved from include/types/ifunc.h with 100% similarity]
src/gromacs/legacyheaders/types/inputrec.h [new file with mode: 0644]
src/gromacs/legacyheaders/types/ishift.h [moved from include/types/ishift.h with 100% similarity]
src/gromacs/legacyheaders/types/matrix.h [moved from include/types/matrix.h with 100% similarity]
src/gromacs/legacyheaders/types/mdatom.h [moved from include/types/mdatom.h with 100% similarity]
src/gromacs/legacyheaders/types/nblist.h [moved from include/types/nblist.h with 100% similarity]
src/gromacs/legacyheaders/types/nrnb.h [moved from include/types/nrnb.h with 100% similarity]
src/gromacs/legacyheaders/types/ns.h [moved from include/types/ns.h with 100% similarity]
src/gromacs/legacyheaders/types/nsgrid.h [moved from include/types/nsgrid.h with 100% similarity]
src/gromacs/legacyheaders/types/oenv.h [moved from include/types/oenv.h with 100% similarity]
src/gromacs/legacyheaders/types/pbc.h [moved from include/types/pbc.h with 100% similarity]
src/gromacs/legacyheaders/types/qmmmrec.h [moved from include/types/qmmmrec.h with 100% similarity]
src/gromacs/legacyheaders/types/shellfc.h [moved from include/types/shellfc.h with 100% similarity]
src/gromacs/legacyheaders/types/simple.h [moved from include/types/simple.h with 100% similarity]
src/gromacs/legacyheaders/types/state.h [moved from include/types/state.h with 100% similarity]
src/gromacs/legacyheaders/types/symtab.h [moved from include/types/symtab.h with 100% similarity]
src/gromacs/legacyheaders/types/topology.h [moved from include/types/topology.h with 100% similarity]
src/gromacs/legacyheaders/types/trx.h [moved from include/types/trx.h with 100% similarity]
src/gromacs/legacyheaders/update.h [moved from include/update.h with 100% similarity]
src/gromacs/legacyheaders/vcm.h [moved from include/vcm.h with 100% similarity]
src/gromacs/legacyheaders/vec.h [new file with mode: 0644]
src/gromacs/legacyheaders/viewit.h [moved from include/viewit.h with 100% similarity]
src/gromacs/legacyheaders/vmddlopen.h [moved from include/vmddlopen.h with 100% similarity]
src/gromacs/legacyheaders/vmdio.h [moved from include/vmdio.h with 100% similarity]
src/gromacs/legacyheaders/vmdplugin.h [moved from include/vmdplugin.h with 100% similarity]
src/gromacs/legacyheaders/vsite.h [moved from include/vsite.h with 100% similarity]
src/gromacs/legacyheaders/warninp.h [moved from include/warninp.h with 100% similarity]
src/gromacs/legacyheaders/wgms.h [moved from include/wgms.h with 100% similarity]
src/gromacs/legacyheaders/wman.h [moved from include/wman.h with 100% similarity]
src/gromacs/legacyheaders/writeps.h [moved from include/writeps.h with 100% similarity]
src/gromacs/legacyheaders/xdrf.h [moved from include/xdrf.h with 100% similarity]
src/gromacs/legacyheaders/xtcio.h [moved from include/xtcio.h with 100% similarity]
src/gromacs/legacyheaders/xvgr.h [moved from include/xvgr.h with 100% similarity]
src/gromacs/libgromacs.pc.cmakein [new file with mode: 0644]
src/gromacs/mdlib/CMakeLists.txt [new file with mode: 0644]
src/gromacs/mdlib/calcmu.c [moved from src/mdlib/calcmu.c with 100% similarity]
src/gromacs/mdlib/calcvir.c [moved from src/mdlib/calcvir.c with 100% similarity]
src/gromacs/mdlib/clincs.c [moved from src/mdlib/clincs.c with 100% similarity]
src/gromacs/mdlib/constr.c [moved from src/mdlib/constr.c with 100% similarity]
src/gromacs/mdlib/coupling.c [moved from src/mdlib/coupling.c with 100% similarity]
src/gromacs/mdlib/csettle.c [moved from src/mdlib/csettle.c with 100% similarity]
src/gromacs/mdlib/domdec.c [new file with mode: 0644]
src/gromacs/mdlib/domdec_box.c [moved from src/mdlib/domdec_box.c with 100% similarity]
src/gromacs/mdlib/domdec_con.c [moved from src/mdlib/domdec_con.c with 100% similarity]
src/gromacs/mdlib/domdec_network.c [moved from src/mdlib/domdec_network.c with 100% similarity]
src/gromacs/mdlib/domdec_setup.c [moved from src/mdlib/domdec_setup.c with 100% similarity]
src/gromacs/mdlib/domdec_top.c [moved from src/mdlib/domdec_top.c with 100% similarity]
src/gromacs/mdlib/ebin.c [moved from src/mdlib/ebin.c with 100% similarity]
src/gromacs/mdlib/edsam.c [moved from src/mdlib/edsam.c with 100% similarity]
src/gromacs/mdlib/ewald.c [moved from src/mdlib/ewald.c with 100% similarity]
src/gromacs/mdlib/fft5d.c [moved from src/mdlib/fft5d.c with 100% similarity]
src/gromacs/mdlib/fft5d.h [moved from src/mdlib/fft5d.h with 100% similarity]
src/gromacs/mdlib/force.c [moved from src/mdlib/force.c with 100% similarity]
src/gromacs/mdlib/forcerec.c [moved from src/mdlib/forcerec.c with 100% similarity]
src/gromacs/mdlib/genborn.c [moved from src/mdlib/genborn.c with 100% similarity]
src/gromacs/mdlib/genborn_allvsall.c [moved from src/mdlib/genborn_allvsall.c with 100% similarity]
src/gromacs/mdlib/genborn_allvsall.h [moved from src/mdlib/genborn_allvsall.h with 100% similarity]
src/gromacs/mdlib/genborn_allvsall_sse2_double.c [moved from src/mdlib/genborn_allvsall_sse2_double.c with 100% similarity]
src/gromacs/mdlib/genborn_allvsall_sse2_double.h [moved from src/mdlib/genborn_allvsall_sse2_double.h with 100% similarity]
src/gromacs/mdlib/genborn_allvsall_sse2_single.c [moved from src/mdlib/genborn_allvsall_sse2_single.c with 100% similarity]
src/gromacs/mdlib/genborn_allvsall_sse2_single.h [moved from src/mdlib/genborn_allvsall_sse2_single.h with 100% similarity]
src/gromacs/mdlib/genborn_sse2_double.c [moved from src/mdlib/genborn_sse2_double.c with 100% similarity]
src/gromacs/mdlib/genborn_sse2_double.h [moved from src/mdlib/genborn_sse2_double.h with 100% similarity]
src/gromacs/mdlib/genborn_sse2_single.c [moved from src/mdlib/genborn_sse2_single.c with 100% similarity]
src/gromacs/mdlib/genborn_sse2_single.h [moved from src/mdlib/genborn_sse2_single.h with 100% similarity]
src/gromacs/mdlib/ghat.c [moved from src/mdlib/ghat.c with 100% similarity]
src/gromacs/mdlib/gmx_fft.c [moved from src/mdlib/gmx_fft.c with 100% similarity]
src/gromacs/mdlib/gmx_fft_acml.c [moved from src/mdlib/gmx_fft_acml.c with 100% similarity]
src/gromacs/mdlib/gmx_fft_fftpack.c [moved from src/mdlib/gmx_fft_fftpack.c with 100% similarity]
src/gromacs/mdlib/gmx_fft_fftw2.c [moved from src/mdlib/gmx_fft_fftw2.c with 100% similarity]
src/gromacs/mdlib/gmx_fft_fftw3.c [moved from src/mdlib/gmx_fft_fftw3.c with 100% similarity]
src/gromacs/mdlib/gmx_fft_mkl.c [moved from src/mdlib/gmx_fft_mkl.c with 100% similarity]
src/gromacs/mdlib/gmx_parallel_3dfft.c [moved from src/mdlib/gmx_parallel_3dfft.c with 100% similarity]
src/gromacs/mdlib/gmx_qhop_db.h [moved from src/mdlib/gmx_qhop_db.h with 100% similarity]
src/gromacs/mdlib/gmx_qhop_db_test.c [moved from src/mdlib/gmx_qhop_db_test.c with 100% similarity]
src/gromacs/mdlib/gmx_qhop_parm.c [moved from src/mdlib/gmx_qhop_parm.c with 100% similarity]
src/gromacs/mdlib/gmx_qhop_parm.h [moved from src/mdlib/gmx_qhop_parm.h with 100% similarity]
src/gromacs/mdlib/gmx_qhop_xml.c [moved from src/mdlib/gmx_qhop_xml.c with 100% similarity]
src/gromacs/mdlib/gmx_qhop_xml.h [moved from src/mdlib/gmx_qhop_xml.h with 100% similarity]
src/gromacs/mdlib/gmx_wallcycle.c [new file with mode: 0644]
src/gromacs/mdlib/groupcoord.c [moved from src/mdlib/groupcoord.c with 100% similarity]
src/gromacs/mdlib/groupcoord.h [moved from src/mdlib/groupcoord.h with 100% similarity]
src/gromacs/mdlib/init.c [moved from src/mdlib/init.c with 100% similarity]
src/gromacs/mdlib/mdatom.c [moved from src/mdlib/mdatom.c with 100% similarity]
src/gromacs/mdlib/mdebin.c [new file with mode: 0644]
src/gromacs/mdlib/mdebin_bar.c [moved from src/mdlib/mdebin_bar.c with 100% similarity]
src/gromacs/mdlib/mdebin_bar.h [moved from src/mdlib/mdebin_bar.h with 100% similarity]
src/gromacs/mdlib/minimize.c [new file with mode: 0644]
src/gromacs/mdlib/mvxvf.c [moved from src/mdlib/mvxvf.c with 100% similarity]
src/gromacs/mdlib/ns.c [new file with mode: 0644]
src/gromacs/mdlib/nsgrid.c [moved from src/mdlib/nsgrid.c with 100% similarity]
src/gromacs/mdlib/partdec.c [moved from src/mdlib/partdec.c with 100% similarity]
src/gromacs/mdlib/perf_est.c [moved from src/mdlib/perf_est.c with 100% similarity]
src/gromacs/mdlib/pme.c [moved from src/mdlib/pme.c with 100% similarity]
src/gromacs/mdlib/pme_pp.c [moved from src/mdlib/pme_pp.c with 100% similarity]
src/gromacs/mdlib/pppm.c [moved from src/mdlib/pppm.c with 100% similarity]
src/gromacs/mdlib/pull.c [moved from src/mdlib/pull.c with 100% similarity]
src/gromacs/mdlib/pull_rotation.c [new file with mode: 0644]
src/gromacs/mdlib/pullutil.c [moved from src/mdlib/pullutil.c with 100% similarity]
src/gromacs/mdlib/qm_gamess.c [moved from src/mdlib/qm_gamess.c with 100% similarity]
src/gromacs/mdlib/qm_gaussian.c [moved from src/mdlib/qm_gaussian.c with 100% similarity]
src/gromacs/mdlib/qm_mopac.c [moved from src/mdlib/qm_mopac.c with 100% similarity]
src/gromacs/mdlib/qm_orca.c [moved from src/mdlib/qm_orca.c with 100% similarity]
src/gromacs/mdlib/qmmm.c [moved from src/mdlib/qmmm.c with 100% similarity]
src/gromacs/mdlib/rf_util.c [moved from src/mdlib/rf_util.c with 100% similarity]
src/gromacs/mdlib/shakef.c [moved from src/mdlib/shakef.c with 100% similarity]
src/gromacs/mdlib/shellfc.c [moved from src/mdlib/shellfc.c with 100% similarity]
src/gromacs/mdlib/sim_util.c [new file with mode: 0644]
src/gromacs/mdlib/stat.c [moved from src/mdlib/stat.c with 100% similarity]
src/gromacs/mdlib/tables.c [moved from src/mdlib/tables.c with 100% similarity]
src/gromacs/mdlib/tgroup.c [moved from src/mdlib/tgroup.c with 100% similarity]
src/gromacs/mdlib/tpi.c [new file with mode: 0644]
src/gromacs/mdlib/update.c [moved from src/mdlib/update.c with 100% similarity]
src/gromacs/mdlib/vcm.c [moved from src/mdlib/vcm.c with 100% similarity]
src/gromacs/mdlib/vsite.c [moved from src/mdlib/vsite.c with 100% similarity]
src/gromacs/mdlib/wall.c [moved from src/mdlib/wall.c with 100% similarity]
src/gromacs/mdlib/wnblist.c [moved from src/mdlib/wnblist.c with 100% similarity]
src/gromacs/options.h [new file with mode: 0644]
src/gromacs/options/CMakeLists.txt [new file with mode: 0644]
src/gromacs/options/abstractoption.h [new file with mode: 0644]
src/gromacs/options/abstractoptionstorage.cpp [new file with mode: 0644]
src/gromacs/options/abstractoptionstorage.h [new file with mode: 0644]
src/gromacs/options/asciihelpwriter-impl.h [new file with mode: 0644]
src/gromacs/options/asciihelpwriter.cpp [new file with mode: 0644]
src/gromacs/options/asciihelpwriter.h [new file with mode: 0644]
src/gromacs/options/basicoptions.cpp [new file with mode: 0644]
src/gromacs/options/basicoptions.h [new file with mode: 0644]
src/gromacs/options/basicoptionstorage.cpp [new file with mode: 0644]
src/gromacs/options/basicoptionstorage.h [new file with mode: 0644]
src/gromacs/options/cmdlineparser-impl.h [new file with mode: 0644]
src/gromacs/options/cmdlineparser.cpp [new file with mode: 0644]
src/gromacs/options/cmdlineparser.h [new file with mode: 0644]
src/gromacs/options/globalproperties.cpp [new file with mode: 0644]
src/gromacs/options/globalproperties.h [new file with mode: 0644]
src/gromacs/options/optionfiletype.h [new file with mode: 0644]
src/gromacs/options/optionflags.h [new file with mode: 0644]
src/gromacs/options/options-impl.h [new file with mode: 0644]
src/gromacs/options/options.cpp [new file with mode: 0644]
src/gromacs/options/options.h [new file with mode: 0644]
src/gromacs/options/optionsassigner-impl.h [new file with mode: 0644]
src/gromacs/options/optionsassigner.cpp [new file with mode: 0644]
src/gromacs/options/optionsassigner.h [new file with mode: 0644]
src/gromacs/options/optionstoragetemplate.h [new file with mode: 0644]
src/gromacs/options/optionsvisitor.cpp [new file with mode: 0644]
src/gromacs/options/optionsvisitor.h [new file with mode: 0644]
src/gromacs/options/tests/.gitignore [new file with mode: 0644]
src/gromacs/options/tests/CMakeLists.txt [new file with mode: 0644]
src/gromacs/options/tests/abstractoptionstorage.cpp [new file with mode: 0644]
src/gromacs/options/tests/cmdlineparser.cpp [new file with mode: 0644]
src/gromacs/options/tests/option.cpp [new file with mode: 0644]
src/gromacs/options/tests/optionsassigner.cpp [new file with mode: 0644]
src/gromacs/options/tests/test_gmock_main.cpp [new file with mode: 0644]
src/gromacs/options/tests/test_main.cpp [new file with mode: 0644]
src/gromacs/selection.h [new file with mode: 0644]
src/gromacs/selection/CMakeLists.txt [new file with mode: 0644]
src/gromacs/selection/centerofmass.cpp [new file with mode: 0644]
src/gromacs/selection/centerofmass.h [new file with mode: 0644]
src/gromacs/selection/compiler.cpp [new file with mode: 0644]
src/gromacs/selection/evaluate.cpp [new file with mode: 0644]
src/gromacs/selection/evaluate.h [new file with mode: 0644]
src/gromacs/selection/indexutil.cpp [new file with mode: 0644]
src/gromacs/selection/indexutil.h [new file with mode: 0644]
src/gromacs/selection/keywords.h [new file with mode: 0644]
src/gromacs/selection/mempool.cpp [new file with mode: 0644]
src/gromacs/selection/mempool.h [new file with mode: 0644]
src/gromacs/selection/nbsearch.cpp [new file with mode: 0644]
src/gromacs/selection/nbsearch.h [new file with mode: 0644]
src/gromacs/selection/params.cpp [new file with mode: 0644]
src/gromacs/selection/parser.cpp [new file with mode: 0644]
src/gromacs/selection/parser.h [new file with mode: 0644]
src/gromacs/selection/parser.y [new file with mode: 0644]
src/gromacs/selection/parsetree.cpp [new file with mode: 0644]
src/gromacs/selection/parsetree.h [new file with mode: 0644]
src/gromacs/selection/poscalc.cpp [new file with mode: 0644]
src/gromacs/selection/poscalc.h [new file with mode: 0644]
src/gromacs/selection/position.cpp [new file with mode: 0644]
src/gromacs/selection/position.h [new file with mode: 0644]
src/gromacs/selection/regenerate_parser.sh [new file with mode: 0755]
src/gromacs/selection/scanner.cpp [new file with mode: 0644]
src/gromacs/selection/scanner.h [new file with mode: 0644]
src/gromacs/selection/scanner.l [new file with mode: 0644]
src/gromacs/selection/scanner_flex.h [new file with mode: 0644]
src/gromacs/selection/scanner_internal.cpp [new file with mode: 0644]
src/gromacs/selection/scanner_internal.h [new file with mode: 0644]
src/gromacs/selection/selection.cpp [new file with mode: 0644]
src/gromacs/selection/selection.h [new file with mode: 0644]
src/gromacs/selection/selectioncollection-impl.h [new file with mode: 0644]
src/gromacs/selection/selectioncollection.cpp [new file with mode: 0644]
src/gromacs/selection/selectioncollection.h [new file with mode: 0644]
src/gromacs/selection/selectionenums.h [new file with mode: 0644]
src/gromacs/selection/selectionoption.cpp [new file with mode: 0644]
src/gromacs/selection/selectionoption.h [new file with mode: 0644]
src/gromacs/selection/selectionoptionstorage.cpp [new file with mode: 0644]
src/gromacs/selection/selectionoptionstorage.h [new file with mode: 0644]
src/gromacs/selection/selelem.cpp [new file with mode: 0644]
src/gromacs/selection/selelem.h [new file with mode: 0644]
src/gromacs/selection/selhelp.cpp [new file with mode: 0644]
src/gromacs/selection/selhelp.h [new file with mode: 0644]
src/gromacs/selection/selmethod.cpp [new file with mode: 0644]
src/gromacs/selection/selmethod.h [new file with mode: 0644]
src/gromacs/selection/selparam.h [new file with mode: 0644]
src/gromacs/selection/selvalue.cpp [new file with mode: 0644]
src/gromacs/selection/selvalue.h [new file with mode: 0644]
src/gromacs/selection/sm_compare.cpp [new file with mode: 0644]
src/gromacs/selection/sm_distance.cpp [new file with mode: 0644]
src/gromacs/selection/sm_insolidangle.cpp [new file with mode: 0644]
src/gromacs/selection/sm_keywords.cpp [new file with mode: 0644]
src/gromacs/selection/sm_merge.cpp [new file with mode: 0644]
src/gromacs/selection/sm_permute.cpp [new file with mode: 0644]
src/gromacs/selection/sm_position.cpp [new file with mode: 0644]
src/gromacs/selection/sm_same.cpp [new file with mode: 0644]
src/gromacs/selection/sm_simple.cpp [new file with mode: 0644]
src/gromacs/selection/symrec.cpp [new file with mode: 0644]
src/gromacs/selection/symrec.h [new file with mode: 0644]
src/gromacs/selection/tests/CMakeLists.txt [new file with mode: 0644]
src/gromacs/selection/tests/selectioncollection.cpp [new file with mode: 0644]
src/gromacs/selection/tests/selectionoption.cpp [new file with mode: 0644]
src/gromacs/selection/tests/simple.gro [new file with mode: 0644]
src/gromacs/selection/tests/test_main.cpp [new file with mode: 0644]
src/gromacs/trajectoryanalysis/CMakeLists.txt [new file with mode: 0644]
src/gromacs/trajectoryanalysis/analysismodule-impl.h [new file with mode: 0644]
src/gromacs/trajectoryanalysis/analysismodule.cpp [new file with mode: 0644]
src/gromacs/trajectoryanalysis/analysismodule.h [new file with mode: 0644]
src/gromacs/trajectoryanalysis/analysissettings-impl.h [new file with mode: 0644]
src/gromacs/trajectoryanalysis/analysissettings.cpp [new file with mode: 0644]
src/gromacs/trajectoryanalysis/analysissettings.h [new file with mode: 0644]
src/gromacs/trajectoryanalysis/cmdlinerunner.cpp [new file with mode: 0644]
src/gromacs/trajectoryanalysis/cmdlinerunner.h [new file with mode: 0644]
src/gromacs/trajectoryanalysis/modules.cpp [new file with mode: 0644]
src/gromacs/trajectoryanalysis/modules.h [new file with mode: 0644]
src/gromacs/trajectoryanalysis/modules/distance.cpp [new file with mode: 0644]
src/gromacs/trajectoryanalysis/modules/distance.h [new file with mode: 0644]
src/gromacs/trajectoryanalysis/modules/select.cpp [new file with mode: 0644]
src/gromacs/trajectoryanalysis/modules/select.h [new file with mode: 0644]
src/gromacs/trajectoryanalysis/runnercommon.cpp [new file with mode: 0644]
src/gromacs/trajectoryanalysis/runnercommon.h [new file with mode: 0644]
src/gromacs/trajectoryanalysis/tests/CMakeLists.txt [new file with mode: 0644]
src/gromacs/trajectoryanalysis/tests/test_selection.cpp [new file with mode: 0644]
src/gromacs/utility/CMakeLists.txt [new file with mode: 0644]
src/gromacs/utility/flags.h [new file with mode: 0644]
src/gromacs/version.c.cmakein [new file with mode: 0644]
src/kernel/.cvsignore [deleted file]
src/kernel/.gitignore
src/kernel/CMakeLists.txt
src/kernel/Makefile.am
src/kernel/grompp.c
src/kernel/md.c
src/kernel/md_openmm.c
src/kernel/md_openmm.h
src/kernel/mdrun.c
src/kernel/membed.c [new file with mode: 0644]
src/kernel/readir.c
src/kernel/readir.h
src/kernel/readrot.c [new file with mode: 0644]
src/kernel/runner.c
src/mdlib/.cvsignore [deleted file]
src/mdlib/.gitignore [deleted file]
src/mdlib/CMakeLists.txt [deleted file]
src/mdlib/Makefile.am [deleted file]
src/mdlib/domdec.c [deleted file]
src/mdlib/gmx_wallcycle.c [deleted file]
src/mdlib/libmd.pc.cmakein [deleted file]
src/mdlib/libmd.pc.in [deleted file]
src/mdlib/mdebin.c [deleted file]
src/mdlib/minimize.c [deleted file]
src/mdlib/ns.c [deleted file]
src/mdlib/sim_util.c [deleted file]
src/mdlib/tpi.c [deleted file]
src/ngmx/.cvsignore [deleted file]
src/ngmx/.gitignore
src/programs/CMakeLists.txt [new file with mode: 0644]
src/programs/g_ana/.gitignore [new file with mode: 0644]
src/programs/g_ana/CMakeLists.txt [new file with mode: 0644]
src/programs/g_ana/g_ana.cpp [new file with mode: 0644]
src/tools/.cvsignore [deleted file]
src/tools/.gitignore
src/tools/CMakeLists.txt
src/tools/Makefile.am
src/tools/gmx_membed.c
src/tools/gmx_msd.c
src/tools/gmx_pme_error.c
src/tools/gmx_saltbr.c
src/tools/gmx_select.c
src/tools/gmx_tune_pme.c

index d045126b09d34e6eebbda8c9fe988e67b018f184..b5ac2ca9ef78439638d7eabf0b979b497b155c02 100644 (file)
@@ -38,6 +38,7 @@ if(NOT CMAKE_BUILD_TYPE)
 endif(NOT CMAKE_BUILD_TYPE)
 
 enable_language(C)
+enable_language(CXX)
 
 set(CPACK_PACKAGE_VERSION ${PROJECT_VERSION})
 set(CPACK_PACKAGE_VENDOR "gromacs.org")
@@ -432,6 +433,9 @@ if (GMX_DLOPEN)
     list(APPEND GMX_EXTRA_LIBRARIES ${CMAKE_DL_LIBS})
 endif (GMX_DLOPEN)
 
+find_package(GTest)
+find_package(GMock)
+
 ########################################################################
 # Generate development version info for cache
 ########################################################################
@@ -443,8 +447,11 @@ endif (GMX_DLOPEN)
 ########################################################################
 
 add_definitions( -DHAVE_CONFIG_H )
+include_directories(${CMAKE_SOURCE_DIR}/src)
+# Required for config.h, maybe should only be set in src/CMakeLists.txt
 include_directories(${CMAKE_BINARY_DIR}/src)
-include_directories(${CMAKE_SOURCE_DIR}/include)
+# Required for now to make old code compile
+include_directories(${CMAKE_SOURCE_DIR}/src/gromacs/legacyheaders)
 
 include(gmxCheckBuildUserTime)
 gmx_check_build_user_time(BUILD_TIME BUILD_USER BUILD_MACHINE)
@@ -758,7 +765,6 @@ if(NOT CMAKE_SYSTEM_NAME STREQUAL "Darwin")
 endif()
 
 add_subdirectory(share)
-add_subdirectory(include)
 add_subdirectory(man)
 add_subdirectory(src)
 add_subdirectory(scripts)
@@ -785,7 +791,6 @@ include(CTest)
 mark_as_advanced(BUILD_TESTING)
 IF(BUILD_TESTING)
        enable_testing()
-       add_test(TestBuildAll make)
        add_subdirectory(tests)
 ENDIF()
 
diff --git a/README b/README
index 398c9fca27ec27446c4c5b32b695e0c5bc7d9769..d6a9e05e4531cc2665b3b44f70dcd518828b23a4 100644 (file)
--- a/README
+++ b/README
@@ -74,5 +74,3 @@ Don't hesitate to contact us at gromacs@gromacs.org if you are interested.
 
 
 
-
-
diff --git a/admin/.cvsignore b/admin/.cvsignore
deleted file mode 100644 (file)
index 282522d..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-Makefile
-Makefile.in
diff --git a/cmake/FindGMock.cmake b/cmake/FindGMock.cmake
new file mode 100644 (file)
index 0000000..f4aa532
--- /dev/null
@@ -0,0 +1,127 @@
+# Locate the Google C++ Mocking Framework.
+#
+# Defines the following variables:
+#
+#   GMOCK_FOUND - Found the Google Mocking framework
+#   GMOCK_INCLUDE_DIRS - Include directories
+#
+# Also defines the library variables below as normal
+# variables.  These contain debug/optimized keywords when
+# a debugging library is found.
+#
+#   GMOCK_BOTH_LIBRARIES - Both libgmock & libgmock-main
+#   GMOCK_LIBRARIES - libgmock
+#   GMOCK_MAIN_LIBRARIES - libgmock-main
+#
+# Accepts the following variables as input:
+#
+#   GMOCK_ROOT - (as a CMake or environment variable)
+#                The root directory of the gmock install prefix
+#
+#   GMOCK_MSVC_SEARCH - If compiling with MSVC, this variable can be set to
+#                       "MD" or "MT" to enable searching a GTest build tree
+#                       (defaults: "MD")
+#
+#-----------------------
+# Example Usage:
+#
+#    enable_testing()
+#    find_package(GMock REQUIRED)
+#    include_directories(${GMOCK_INCLUDE_DIRS})
+#
+#    add_executable(foo foo.cc)
+#    target_link_libraries(foo ${GMOCK_BOTH_LIBRARIES})
+#
+#    add_test(AllTestsInFoo foo)
+
+#=============================================================================
+# Copyright 2009 Kitware, Inc.
+# Copyright 2009 Philip Lowman <philip@yhbt.com>
+# Copyright 2009 Daniel Blezek <blezek@gmail.com>
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+#
+# Adapted from FindGTest.cmake in the CMake distribution by
+# Teemu Murtola <teemu.murtola@cbr.su.se>.
+
+function(_gmock_append_debugs _endvar _library)
+    if(${_library} AND ${_library}_DEBUG)
+        set(_output optimized ${${_library}} debug ${${_library}_DEBUG})
+    else()
+        set(_output ${${_library}})
+    endif()
+    set(${_endvar} ${_output} PARENT_SCOPE)
+endfunction()
+
+function(_gmock_find_library _name)
+    find_library(${_name}
+        NAMES ${ARGN}
+        HINTS
+            $ENV{GMOCK_ROOT}
+            ${GMOCK_ROOT}
+        PATH_SUFFIXES ${_gmock_libpath_suffixes}
+    )
+    mark_as_advanced(${_name})
+endfunction()
+
+#
+
+find_package(GTest)
+
+if(NOT DEFINED GMOCK_MSVC_SEARCH)
+    set(GMOCK_MSVC_SEARCH MD)
+endif()
+
+set(_gmock_libpath_suffixes lib)
+if(MSVC)
+    if(GMOCK_MSVC_SEARCH STREQUAL "MD")
+        list(APPEND _gmock_libpath_suffixes
+            msvc/gmock-md/Debug
+            msvc/gmock-md/Release)
+    elseif(GMOCK_MSVC_SEARCH STREQUAL "MT")
+        list(APPEND _gmock_libpath_suffixes
+            msvc/gmock/Debug
+            msvc/gmock/Release)
+    endif()
+endif()
+
+
+find_path(GMOCK_INCLUDE_DIR gmock/gmock.h
+    HINTS
+        $ENV{GMOCK_ROOT}/include
+        ${GMOCK_ROOT}/include
+)
+mark_as_advanced(GMOCK_INCLUDE_DIR)
+
+if(MSVC AND GMOCK_MSVC_SEARCH STREQUAL "MD")
+    # The provided /MD project files for Google Mock add -md suffixes to the
+    # library names.
+    _gmock_find_library(GMOCK_LIBRARY            gmock-md  gmock)
+    _gmock_find_library(GMOCK_LIBRARY_DEBUG      gmock-mdd gmockd)
+    _gmock_find_library(GMOCK_MAIN_LIBRARY       gmock_main-md  gmock_main)
+    _gmock_find_library(GMOCK_MAIN_LIBRARY_DEBUG gmock_main-mdd gmock_maind)
+else()
+    _gmock_find_library(GMOCK_LIBRARY            gmock)
+    _gmock_find_library(GMOCK_LIBRARY_DEBUG      gmockd)
+    _gmock_find_library(GMOCK_MAIN_LIBRARY       gmock_main)
+    _gmock_find_library(GMOCK_MAIN_LIBRARY_DEBUG gmock_maind)
+endif()
+
+include(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(GMock DEFAULT_MSG GMOCK_LIBRARY GMOCK_INCLUDE_DIR GMOCK_MAIN_LIBRARY)
+
+if(GMOCK_FOUND)
+    set(GMOCK_INCLUDE_DIRS ${GMOCK_INCLUDE_DIR} ${GTEST_INCLUDE_DIRS})
+    _gmock_append_debugs(GMOCK_LIBRARIES      GMOCK_LIBRARY)
+    set(GMOCK_LIBRARIES ${GMOCK_LIBRARIES} ${GTEST_LIBRARIES})
+    _gmock_append_debugs(GMOCK_MAIN_LIBRARIES GMOCK_MAIN_LIBRARY)
+    set(GMOCK_MAIN_LIBRARIES ${GMOCK_MAIN_LIBRARIES} ${GTEST_LIBRARIES})
+    set(GMOCK_BOTH_LIBRARIES ${GMOCK_LIBRARIES} ${GMOCK_MAIN_LIBRARIES})
+endif()
+
diff --git a/cmake/FindGTest.cmake b/cmake/FindGTest.cmake
new file mode 100644 (file)
index 0000000..1bcd469
--- /dev/null
@@ -0,0 +1,158 @@
+# Locate the Google C++ Testing Framework.
+#
+# Defines the following variables:
+#
+#   GTEST_FOUND - Found the Google Testing framework
+#   GTEST_INCLUDE_DIRS - Include directories
+#
+# Also defines the library variables below as normal
+# variables.  These contain debug/optimized keywords when
+# a debugging library is found.
+#
+#   GTEST_BOTH_LIBRARIES - Both libgtest & libgtest-main
+#   GTEST_LIBRARIES - libgtest
+#   GTEST_MAIN_LIBRARIES - libgtest-main
+#
+# Accepts the following variables as input:
+#
+#   GTEST_ROOT - (as a CMake or environment variable)
+#                The root directory of the gtest install prefix
+#
+#   GTEST_MSVC_SEARCH - If compiling with MSVC, this variable can be set to
+#                       "MD" or "MT" to enable searching a GTest build tree
+#                       (defaults: "MD")
+#
+#-----------------------
+# Example Usage:
+#
+#    enable_testing()
+#    find_package(GTest REQUIRED)
+#    include_directories(${GTEST_INCLUDE_DIRS})
+#
+#    add_executable(foo foo.cc)
+#    target_link_libraries(foo ${GTEST_BOTH_LIBRARIES})
+#
+#    add_test(AllTestsInFoo foo)
+#
+#-----------------------
+#
+# If you would like each Google test to show up in CTest as
+# a test you may use the following macro.
+# NOTE: It will slow down your tests by running an executable
+# for each test and test fixture.  You will also have to rerun
+# CMake after adding or removing tests or test fixtures.
+#
+# GTEST_ADD_TESTS(executable extra_args ARGN)
+#    executable = The path to the test executable
+#    extra_args = Pass a list of extra arguments to be passed to
+#                 executable enclosed in quotes (or "" for none)
+#    ARGN =       A list of source files to search for tests & test
+#                 fixtures.
+#
+#  Example:
+#     set(FooTestArgs --foo 1 --bar 2)
+#     add_executable(FooTest FooUnitTest.cc)
+#     GTEST_ADD_TESTS(FooTest "${FooTestArgs}" FooUnitTest.cc)
+
+#=============================================================================
+# Copyright 2009 Kitware, Inc.
+# Copyright 2009 Philip Lowman <philip@yhbt.com>
+# Copyright 2009 Daniel Blezek <blezek@gmail.com>
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+# (To distributed this file outside of CMake, substitute the full
+#  License text for the above reference.)
+#
+# Thanks to Daniel Blezek <blezek@gmail.com> for the GTEST_ADD_TESTS code
+
+function(GTEST_ADD_TESTS executable extra_args)
+    if(NOT ARGN)
+        message(FATAL_ERROR "Missing ARGN: Read the documentation for GTEST_ADD_TESTS")
+    endif()
+    foreach(source ${ARGN})
+        file(READ "${source}" contents)
+        string(REGEX MATCHALL "TEST_?F?\\(([A-Za-z_0-9 ,]+)\\)" found_tests ${contents})
+        foreach(hit ${found_tests})
+            string(REGEX REPLACE ".*\\( *([A-Za-z_0-9]+), *([A-Za-z_0-9]+) *\\).*" "\\1.\\2" test_name ${hit})
+            add_test(${test_name} ${executable} --gtest_filter=${test_name} ${extra_args})
+        endforeach()
+    endforeach()
+endfunction()
+
+function(_gtest_append_debugs _endvar _library)
+    if(${_library} AND ${_library}_DEBUG)
+        set(_output optimized ${${_library}} debug ${${_library}_DEBUG})
+    else()
+        set(_output ${${_library}})
+    endif()
+    set(${_endvar} ${_output} PARENT_SCOPE)
+endfunction()
+
+function(_gtest_find_library _name)
+    find_library(${_name}
+        NAMES ${ARGN}
+        HINTS
+            $ENV{GTEST_ROOT}
+            ${GTEST_ROOT}
+        PATH_SUFFIXES ${_gtest_libpath_suffixes}
+    )
+    mark_as_advanced(${_name})
+endfunction()
+
+#
+
+if(NOT DEFINED GTEST_MSVC_SEARCH)
+    set(GTEST_MSVC_SEARCH MD)
+endif()
+
+set(_gtest_libpath_suffixes lib)
+if(MSVC)
+    if(GTEST_MSVC_SEARCH STREQUAL "MD")
+        list(APPEND _gtest_libpath_suffixes
+            msvc/gtest-md/Debug
+            msvc/gtest-md/Release)
+    elseif(GTEST_MSVC_SEARCH STREQUAL "MT")
+        list(APPEND _gtest_libpath_suffixes
+            msvc/gtest/Debug
+            msvc/gtest/Release)
+    endif()
+endif()
+
+
+find_path(GTEST_INCLUDE_DIR gtest/gtest.h
+    HINTS
+        $ENV{GTEST_ROOT}/include
+        ${GTEST_ROOT}/include
+)
+mark_as_advanced(GTEST_INCLUDE_DIR)
+
+if(MSVC AND GTEST_MSVC_SEARCH STREQUAL "MD")
+    # The provided /MD project files for Google Test add -md suffixes to the
+    # library names.
+    _gtest_find_library(GTEST_LIBRARY            gtest-md  gtest)
+    _gtest_find_library(GTEST_LIBRARY_DEBUG      gtest-mdd gtestd)
+    _gtest_find_library(GTEST_MAIN_LIBRARY       gtest_main-md  gtest_main)
+    _gtest_find_library(GTEST_MAIN_LIBRARY_DEBUG gtest_main-mdd gtest_maind)
+else()
+    _gtest_find_library(GTEST_LIBRARY            gtest)
+    _gtest_find_library(GTEST_LIBRARY_DEBUG      gtestd)
+    _gtest_find_library(GTEST_MAIN_LIBRARY       gtest_main)
+    _gtest_find_library(GTEST_MAIN_LIBRARY_DEBUG gtest_maind)
+endif()
+
+include(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(GTest DEFAULT_MSG GTEST_LIBRARY GTEST_INCLUDE_DIR GTEST_MAIN_LIBRARY)
+
+if(GTEST_FOUND)
+    set(GTEST_INCLUDE_DIRS ${GTEST_INCLUDE_DIR})
+    _gtest_append_debugs(GTEST_LIBRARIES      GTEST_LIBRARY)
+    _gtest_append_debugs(GTEST_MAIN_LIBRARIES GTEST_MAIN_LIBRARY)
+    set(GTEST_BOTH_LIBRARIES ${GTEST_LIBRARIES} ${GTEST_MAIN_LIBRARIES})
+endif()
+
index 853372741c14e6128fd8b40ae3685c352b190b9c..97a228bb4906d46af391d5aca82b980dfec5050f 100644 (file)
@@ -9,7 +9,7 @@ MACRO(TEST_TMPI_ATOMICS VARIABLE)
     if (NOT DEFINED TMPI_ATOMICS)
         try_compile(TEST_ATOMICS "${CMAKE_BINARY_DIR}"
                 "${CMAKE_SOURCE_DIR}/cmake/TestAtomics.c"
-                COMPILE_DEFINITIONS "-I${CMAKE_SOURCE_DIR}/include" )
+                COMPILE_DEFINITIONS "-I${CMAKE_SOURCE_DIR}/src/gromacs/legacyheaders" )
 
         if (TEST_ATOMICS)
             message(STATUS "Atomics found")
diff --git a/include/.cvsignore b/include/.cvsignore
deleted file mode 100644 (file)
index fd19000..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-Makefile.in
-Makefile
-config.h
-stamp-h.in
diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt
deleted file mode 100644 (file)
index 05b41fd..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-# includes: Nothing to build, just installation
-install(DIRECTORY . DESTINATION ${INCL_INSTALL_DIR}/gromacs
-  COMPONENT development
-  PATTERN "Makefile*" EXCLUDE
-  PATTERN "CMake*" EXCLUDE
-  PATTERN "cmake*" EXCLUDE
-  PATTERN "*~" EXCLUDE
-)
diff --git a/include/Makefile.am b/include/Makefile.am
deleted file mode 100644 (file)
index 26f0ee0..0000000
+++ /dev/null
@@ -1,158 +0,0 @@
-## Process this file with automake to produce Makefile.in
-#
-# Don't edit - this file is generated automatically from Makefile.am
-#
-
-SUBDIRS = . types thread_mpi
-
-
-pkginclude_HEADERS = \
-3dview.h \
-assert.h \
-atomprop.h \
-bondf.h \
-calcgrid.h \
-calch.h \
-calcmu.h \
-centerofmass.h \
-chargegroup.h \
-checkpoint.h \
-confio.h \
-constr.h \
-copyrite.h \
-coulomb.h \
-dihre.h \
-displacement.h \
-disre.h \
-do_fit.h \
-domdec.h \
-domdec_network.h \
-ebin.h \
-edsam.h \
-enxio.h \
-ffscanf.h \
-filenm.h \
-force.h \
-futil.h \
-gbutil.h \
-gen_ad.h \
-genborn.h \
-gmx_ana.h \
-gmx_arpack.h \
-gmx_blas.h \
-gmx_cyclecounter.h \
-gmx_fatal.h \
-gmx_fft.h \
-gmx_ga2la.h \
-gmx_lapack.h \
-gmx_matrix.h \
-gmx_parallel_3dfft.h \
-gmx_random.h \
-gmx_sort.h \
-gmx_sse2_single.h \
-gmx_statistics.h \
-gmx_system_xdr.h \
-gmx_wallcycle.h \
-gmxcomplex.h \
-gmxcpp.h \
-gmxfio.h \
-gpp_atomtype.h \
-gpp_nextnb.h \
-grompp.h \
-gstat.h \
-hackblock.h \
-histogram.h \
-index.h \
-indexutil.h \
-inputrec.h \
-invblock.h \
-macros.h \
-magic.h \
-main.h \
-maths.h \
-matio.h \
-md5.h \
-mdatoms.h \
-mdebin.h \
-mdrun.h \
-mpelogging.h \
-mshift.h \
-mtop_util.h\
-mtxio.h \
-mvdata.h \
-names.h \
-nbsearch.h \
-network.h \
-nonbonded.h \
-nrama.h \
-nrjac.h \
-nrnb.h \
-ns.h \
-nsgrid.h \
-orires.h \
-partdec.h \
-pbc.h \
-pdbio.h \
-pdb2top.h \
-perf_est.h \
-physics.h \
-pme.h \
-poscalc.h \
-position.h \
-pppm.h \
-princ.h \
-pull.h \
-qmmm.h \
-random.h \
-rbin.h \
-rdgroup.h \
-readinp.h \
-resall.h \
-rmpbc.h \
-selection.h \
-selmethod.h \
-selparam.h \
-selvalue.h \
-sfactor.h \
-shellfc.h \
-shift.h \
-smalloc.h \
-sortwater.h \
-sparsematrix.h \
-split.h \
-splitter.h \
-statutil.h \
-strdb.h \
-string2.h \
-symtab.h \
-sysstuff.h \
-tgroup.h \
-topsort.h \
-toputil.h \
-tpxio.h \
-trajana.h \
-trnio.h \
-txtdump.h \
-typedefs.h \
-update.h \
-vcm.h \
-vec.h \
-viewit.h \
-vmdio.h \
-vsite.h \
-warninp.h \
-wgms.h \
-wman.h \
-writeps.h \
-xdrf.h \
-xtcio.h \
-xvgr.h \
-thread_mpi.h \
-tmpi.h \
-mainpage.h \
-molfile_plugin.h \
-vmddlopen.h \
-vmdplugin.h \
-oenv.h \
-sighandler.h \
-gmx_sse2_double.h
diff --git a/include/centerofmass.h b/include/centerofmass.h
deleted file mode 100644 (file)
index b66ca76..0000000
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- *
- *                This source code is part of
- *
- *                 G   R   O   M   A   C   S
- *
- *          GROningen MAchine for Chemical Simulations
- *
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
- * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
- * Copyright (c) 2001-2009, The GROMACS development team,
- * check out http://www.gromacs.org for more information.
-
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * If you want to redistribute modifications, please consider that
- * scientific software is very special. Version control is crucial -
- * bugs must be traceable. We will be happy to consider code for
- * inclusion in the official distribution, but derived work must not
- * be called official GROMACS. Details are found in the README & COPYING
- * files - if they are missing, get the official version at www.gromacs.org.
- *
- * To help us fund GROMACS development, we humbly ask that you cite
- * the papers on the package - you can find them in the top README file.
- *
- * For more info, check our website at http://www.gromacs.org
- */
-/*! \file
- * \brief API for calculation of centers of mass/geometry.
- *
- * This header defines a few functions that can be used to calculate
- * centers of mass/geometry for a group of atoms.
- * These routines can be used independently of the other parts of the
- * library, but they are also used internally by the selection engine.
- * In most cases, it should not be necessary to call these functions
- * directly.
- * Instead, one should write an analysis tool such that it gets all
- * positions through selections.
- *
- * The functions in the header can be divided into a few groups based on the
- * parameters they take. The simplest group of functions calculates the center
- * of a single group of atoms:
- *  - gmx_calc_cog(): Calculates the center of geometry (COG) of a given
- *    group of atoms.
- *  - gmx_calc_com(): Calculates the center of mass (COM) of a given group
- *    of atoms.
- *  - gmx_calc_comg(): Calculates either the COM or COG, based on a
- *    gmx_boolean flag.
- *
- * A second set of routines is provided for calculating the centers for groups
- * that wrap over periodic boundaries (gmx_calc_cog_pbc(), gmx_calc_com_pbc(),
- * gmx_calc_comg_pbc()). These functions are slower, because they need to
- * adjust the center iteratively.
- *
- * It is also possible to calculate centers for several groups of atoms in
- * one call. The functions gmx_calc_cog_block(), gmx_calc_com_block() and
- * gmx_calc_comg_block() take an index group and a partitioning of that index
- * group (as a \c t_block structure), and calculate the centers for
- * each group defined by the \c t_block structure separately.
- *
- * Finally, there is a function gmx_calc_comg_blocka() that takes both the
- * index group and the partitioning as a single \c t_blocka structure.
- */
-#ifndef CENTEROFMASS_H
-#define CENTEROFMASS_H
-
-#include "typedefs.h"
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif
-
-/** Calculate a single center of geometry. */
-int
-gmx_calc_cog(t_topology *top, rvec x[], int nrefat, atom_id index[], rvec xout);
-/** Calculate a single center of mass. */
-int
-gmx_calc_com(t_topology *top, rvec x[], int nrefat, atom_id index[], rvec xout);
-/** Calculate force on a single center of geometry. */
-int
-gmx_calc_cog_f(t_topology *top, rvec f[], int nrefat, atom_id index[], rvec fout);
-/** Calculate a single center of mass/geometry. */
-int
-gmx_calc_comg(t_topology *top, rvec x[], int nrefat, atom_id index[],
-              gmx_bool bMass, rvec xout);
-/** Calculate force on a single center of mass/geometry. */
-int
-gmx_calc_comg_f(t_topology *top, rvec f[], int nrefat, atom_id index[],
-                gmx_bool bMass, rvec fout);
-
-/** Calculate a single center of geometry iteratively, taking PBC into account. */
-int
-gmx_calc_cog_pbc(t_topology *top, rvec x[], t_pbc *pbc,
-                 int nrefat, atom_id index[], rvec xout);
-/** Calculate a single center of mass iteratively, taking PBC into account. */
-int
-gmx_calc_com_pbc(t_topology *top, rvec x[], t_pbc *pbc,
-                 int nrefat, atom_id index[], rvec xout);
-/** Calculate a single center of mass/geometry iteratively with PBC. */
-int
-gmx_calc_comg_pbc(t_topology *top, rvec x[], t_pbc *pbc,
-                  int nrefat, atom_id index[], gmx_bool bMass, rvec xout);
-
-/** Calculate centers of geometry for a blocked index. */
-int
-gmx_calc_cog_block(t_topology *top, rvec x[], t_block *block,
-                   atom_id index[], rvec xout[]);
-/** Calculate centers of mass for a blocked index. */
-int
-gmx_calc_com_block(t_topology *top, rvec x[], t_block *block,
-                   atom_id index[], rvec xout[]);
-/** Calculate forces on centers of geometry for a blocked index. */
-int
-gmx_calc_cog_f_block(t_topology *top, rvec f[], t_block *block,
-                     atom_id index[], rvec fout[]);
-/** Calculate centers of mass/geometry for a blocked index. */
-int
-gmx_calc_comg_block(t_topology *top, rvec x[], t_block *block,
-                    atom_id index[], gmx_bool bMass, rvec xout[]);
-/** Calculate forces on centers of mass/geometry for a blocked index. */
-int
-gmx_calc_comg_f_block(t_topology *top, rvec f[], t_block *block,
-                      atom_id index[], gmx_bool bMass, rvec fout[]);
-/** Calculate centers of mass/geometry for a set of blocks; */
-int
-gmx_calc_comg_blocka(t_topology *top, rvec x[], t_blocka *block,
-                     gmx_bool bMass, rvec xout[]);
-/** Calculate forces on centers of mass/geometry for a set of blocks; */
-int
-gmx_calc_comg_f_blocka(t_topology *top, rvec x[], t_blocka *block,
-                       gmx_bool bMass, rvec xout[]);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/include/gmx_statistics.h b/include/gmx_statistics.h
deleted file mode 100644 (file)
index 5d28891..0000000
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * 
- *                This source code is part of
- * 
- *                 G   R   O   M   A   C   S
- * 
- *          GROningen MAchine for Chemical Simulations
- * 
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
- * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
- * Copyright (c) 2001-2008, The GROMACS development team,
- * check out http://www.gromacs.org for more information.
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- * 
- * If you want to redistribute modifications, please consider that
- * scientific software is very special. Version control is crucial -
- * bugs must be traceable. We will be happy to consider code for
- * inclusion in the official distribution, but derived work must not
- * be called official GROMACS. Details are found in the README & COPYING
- * files - if they are missing, get the official version at www.gromacs.org.
- * 
- * To help us fund GROMACS development, we humbly ask that you cite
- * the papers on the package - you can find them in the top README file.
- * 
- * For more info, check our website at http://www.gromacs.org
- * 
- * And Hey:
- * Gallium Rubidium Oxygen Manganese Argon Carbon Silicon
- */
-
-#ifndef _GMX_STATS_H
-#define _GMX_STATS_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include "typedefs.h"
-
-typedef struct gmx_stats *gmx_stats_t;
-       
-/* Error codes returned by the routines */
-enum { estatsOK, estatsNO_POINTS, estatsNO_MEMORY, estatsERROR, 
-       estatsINVALID_INPUT, estatsNOT_IMPLEMENTED, estatsNR };
-       
-enum { elsqWEIGHT_NONE, elsqWEIGHT_X, elsqWEIGHT_Y, 
-       elsqWEIGHT_XY, elsqWEIGHT_NR  };
-
-enum { ehistoX, ehistoY, ehistoNR };
-  
-gmx_stats_t gmx_stats_init();
-
-int gmx_stats_done(gmx_stats_t stats);
-
-/* Remove outliers from a straight line, where level in units of
-   sigma. Level needs to be larger than one obviously. */
-int gmx_stats_remove_outliers(gmx_stats_t stats,double level);
-
-int gmx_stats_add_point(gmx_stats_t stats,double x,double y,
-                              double dx,double dy);
-
-/* The arrays dx and dy may be NULL if no uncertainties are available,
-   in that case zero uncertainties will be assumed. */
-int gmx_stats_add_points(gmx_stats_t stats,int n,real *x,real *y,
-                               real *dx,real *dy);
-
-/* Return the data points one by one. Return estatsOK while there are
-   more points, and returns estatsNOPOINTS when the last point has
-   been returned. Should be used in a while loop. Variables for either
-   pointer may be NULL, in which case the routine can be used as an
-   expensive point counter. */
-int gmx_stats_get_point(gmx_stats_t stats,real *x,real *y,
-                              real *dx,real *dy);
-
-/* Fit the data to y = ax + b, possibly weighted, if uncertainties
-   have been input. Returns slope in *a and intercept in b, *return
-   sigmas in *da and *db respectively. Returns normalized *quality of
-   fit in *chi2 and correlation of fit with data in Rfit. chi2, Rfit,
-   da and db may be NULL. */
-int gmx_stats_get_ab(gmx_stats_t stats,int weight,
-                           real *a,real *b,
-                           real *da,real *db,real *chi2,real *Rfit);
-
-/* Fit the data to y = ax, possibly weighted, if uncertainties have
-   been input. Returns slope in *a, sigma in a in *da, and normalized
-   quality of fit in *chi2 and correlation of fit with data in
-   Rfit. chi2, Rfit and da may be NULL. */
-int gmx_stats_get_a(gmx_stats_t stats,int weight,
-                          real *a,real *da,real *chi2,real *Rfit);
-
-/* Return the correlation coefficient between the data (x and y) as
-   input to the structure. */
-int gmx_stats_get_corr_coeff(gmx_stats_t stats,real *R);
-
-/* Returns the root mean square deviation between x and y values. */
-int gmx_stats_get_rmsd(gmx_stats_t gstats,real *rmsd);
-
-int gmx_stats_get_npoints(gmx_stats_t stats,int *N);
-
-int gmx_stats_get_average(gmx_stats_t stats,real *aver);
-
-int gmx_stats_get_sigma(gmx_stats_t stats,real *sigma);
-
-int gmx_stats_get_error(gmx_stats_t stats,real *error);
-
-/* Get all three of the above. Pointers may be null, in which case no
-   assignment will be done. */
-int gmx_stats_get_ase(gmx_stats_t gstats,real *aver,real *sigma,real *error);
-
-/* Dump the x, y, dx, dy data to a text file */
-int gmx_stats_dump_xy(gmx_stats_t gstats,FILE *fp);
-
-/* Make a histogram of the data present. Uses either bindwith to
-   determine the number of bins, or nbins to determine the binwidth,
-   therefore one of these should be zero, but not the other. If *nbins = 0
-   the number of bins will be returned in this variable. ehisto should be one of 
-   ehistoX or ehistoY. If
-   normalized not equal to zero, the integral of the histogram will be
-   normalized to one. The output is in two arrays, *x and *y, to which
-   you should pass a pointer. Memory for the arrays will be allocated
-   as needed. Function returns one of the estats codes. */
-int gmx_stats_make_histogram(gmx_stats_t gstats,real binwidth,int *nbins,
-                                   int ehisto,
-                                   int normalized,real **x,real **y);
-
-/* Return message belonging to error code */
-const char *gmx_stats_message(int estats);
-
-/****************************************************
- * Some statistics utilities for convenience: useful when a complete data
- * set is available already from another source, e.g. an xvg file.
- ****************************************************/
-int lsq_y_ax(int n, real x[], real y[], real *a);
-/* Fit a straight line y=ax thru the n data points x, y, return the
-   slope in *a. Return value can be estatsOK, or something else. */
-
-int lsq_y_ax_b(int n, real x[], real y[], real *a, real *b,real *r,
-                     real *chi2);
-/* Fit a straight line y=ax+b thru the n data points x,y.
- * Returns the "fit quality" sigma = sqrt(chi^2/(n-2)).
- * The correlation coefficient is returned in r.
- */
-
-int lsq_y_ax_b_xdouble(int n, double x[], real y[],
-                              real *a, real *b,real *r,real *chi2);
-/* As lsq_y_ax_b, but with x in double precision.
- */
-
-int lsq_y_ax_b_error(int n, real x[], real y[], real dy[],
-                            real *a, real *b, real *da, real *db,
-                            real *r,real *chi2);
-/* Fit a straight line y=ax+b thru the n data points x,y, with sigma dy
- * Returns the "fit quality" sigma = sqrt(chi^2/(n-2)).
- * The correlation coefficient is returned in r.
- */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/include/gmx_wallcycle.h b/include/gmx_wallcycle.h
deleted file mode 100644 (file)
index 9d5c5cf..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * 
- *                This source code is part of
- * 
- *                 G   R   O   M   A   C   S
- * 
- *          GROningen MAchine for Chemical Simulations
- * 
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
- * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
- * Copyright (c) 2001-2008, The GROMACS development team,
- * check out http://www.gromacs.org for more information.
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- * 
- * If you want to redistribute modifications, please consider that
- * scientific software is very special. Version control is crucial -
- * bugs must be traceable. We will be happy to consider code for
- * inclusion in the official distribution, but derived work must not
- * be called official GROMACS. Details are found in the README & COPYING
- * files - if they are missing, get the official version at www.gromacs.org.
- * 
- * To help us fund GROMACS development, we humbly ask that you cite
- * the papers on the package - you can find them in the top README file.
- * 
- * For more info, check our website at http://www.gromacs.org
- * 
- * And Hey:
- * Gallium Rubidium Oxygen Manganese Argon Carbon Silicon
- */
-
-
-#ifndef _gmx_wallcycle_h
-#define _gmx_wallcycle_h
-
-#include <stdio.h>
-#include "typedefs.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-  enum { ewcRUN, ewcSTEP, ewcPPDURINGPME, ewcDOMDEC, ewcDDCOMMLOAD, ewcDDCOMMBOUND, ewcVSITECONSTR, ewcPP_PMESENDX, ewcMOVEX, ewcNS, ewcGB, ewcFORCE, ewcMOVEF, ewcPMEMESH, ewcPME_REDISTXF, ewcPME_SPREADGATHER, ewcPME_FFT, ewcPME_SOLVE, ewcPMEWAITCOMM, ewcPP_PMEWAITRECVF, ewcVSITESPREAD, ewcTRAJ, ewcUPDATE, ewcCONSTR, ewcMoveE, ewcTEST, ewcNR };
-
-gmx_bool wallcycle_have_counter(void);
-/* Returns if cycle counting is supported */
-
-gmx_wallcycle_t wallcycle_init(FILE *fplog,int resetstep,t_commrec *cr);
-/* Returns the wall cycle structure.
- * Returns NULL when cycle counting is not supported.
- */
-
-void wallcycle_start(gmx_wallcycle_t wc, int ewc);
-/* Set the start cycle count for ewc */
-
-double wallcycle_stop(gmx_wallcycle_t wc, int ewc);
-/* Stop the cycle count for ewc, returns the last cycle count */
-
-void wallcycle_reset_all(gmx_wallcycle_t wc);
-/* Resets all cycle counters to zero */
-
-void wallcycle_sum(t_commrec *cr, gmx_wallcycle_t wc,double cycles[]);
-/* Sum the cycles over the nodes in cr->mpi_comm_mysim */
-
-void wallcycle_print(FILE *fplog, int nnodes, int npme, double realtime,
-                           gmx_wallcycle_t wc, double cycles[]);
-/* Print the cycle and time accounting */
-
-gmx_large_int_t wcycle_get_reset_counters(gmx_wallcycle_t wc);
-/* Return reset_counters from wc struct */
-
-void wcycle_set_reset_counters(gmx_wallcycle_t wc, gmx_large_int_t reset_counters);
-/* Set reset_counters */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _gmx_wallcycle_h */
diff --git a/include/gmxfio.h b/include/gmxfio.h
deleted file mode 100644 (file)
index da5acaa..0000000
+++ /dev/null
@@ -1,454 +0,0 @@
-/*
- * 
- *                This source code is part of
- * 
- *                 G   R   O   M   A   C   S
- * 
- *          GROningen MAchine for Chemical Simulations
- * 
- *                        VERSION 3.2.0
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
- * 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.
-
- * 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:
- * Gromacs Runs On Most of All Computer Systems
- */
-
-#ifndef _gmxfio_h
-#define _gmxfio_h
-
-#include <stdio.h>
-#include "sysstuff.h"
-#include "typedefs.h"
-#include "xdrf.h"
-#include "futil.h"
-
-/* types */
-
-
-/* Enumerated for different items in files */
-enum { eitemHEADER, eitemIR, eitemBOX, 
-       eitemTOP, eitemX, eitemV, eitemF, eitemNR };
-       
-/* Enumerated for data types in files */
-enum { eioREAL, eioFLOAT, eioDOUBLE, eioINT, eioGMX_LARGE_INT,
-       eioUCHAR, eioNUCHAR, eioUSHORT,
-       eioRVEC, eioNRVEC, eioIVEC, eioSTRING, eioNR };
-
-typedef struct t_fileio t_fileio;
-
-extern const char *itemstr[eitemNR];
-extern const char *comment_str[eitemNR];
-
-/* NOTE ABOUT THREAD SAFETY:
-
-   The functions are all thread-safe, provided that two threads don't 
-   do something silly like closing the same file, or one thread 
-   accesses a file that has been closed by another.
-   */
-
-/********************************************************
- * Open and Close 
- ********************************************************/
-
-t_fileio *gmx_fio_open(const char *fn,const char *mode);
-/* Open a new file for reading or writing.
- * The file type will be deduced from the file name.
- * If fn is NULL, stdin / stdout will be used for Ascii I/O (TPA type)
- * mode may be "r", "w", or "a". You should append a "b" to the mode
- * if you are writing a binary file, but the routine will also 
- * doublecheck it and try to do it if you forgot. This has no effect on
- * unix, but is important on windows.
- */
-int gmx_fio_close(t_fileio *fp);
-/* Close the file corresponding to fp (if not stdio)
- * The routine will exit when an invalid fio is handled.
- * Returns 0 on success.
- */
-
-int gmx_fio_fp_close(t_fileio *fp);
-/* Close the file corresponding to fp without closing the FIO entry
- * Needed e.g. for trxio because the FIO entries are used to store 
- * additional data.
- * NOTE that the fp still needs to be properly closed with gmx_fio_close().
- * The routine will exit when an invalid fio is handled.
- * Returns 0 on success.
- */
-
-
-/* Open a file, return a stream, record the entry in internal FIO object */
-FILE* gmx_fio_fopen(const char *fn,const char *mode);
-
-/* Close a file previously opened with gmx_fio_fopen. 
- * Do not mix these calls with standard fopen/fclose ones!
- * Returns 0 on success.  */
-int gmx_fio_fclose(FILE *fp);
-
-
-
-/********************************************************
- * Change properties of the open file
- ********************************************************/
-
-void gmx_fio_setprecision(t_fileio *fio,gmx_bool bDouble);
-/* Select the floating point precision for reading and writing files */
-
-char *gmx_fio_getname(t_fileio *fio);
-/* Return the filename corresponding to the fio index */
-
-int gmx_fio_getftp(t_fileio *fio);
-/* Return the filetype corresponding to the fio index. 
-    There is as of now no corresponding setftp function because the file
-    was opened as a specific file type and changing that midway is most 
-    likely an evil hack. */
-
-void gmx_fio_setdebug(t_fileio *fio,gmx_bool bDebug);
-/* Set the debug mode */
-
-gmx_bool gmx_fio_getdebug(t_fileio *fio);
-/* Return  whether debug mode is on in fio  */
-
-gmx_bool gmx_fio_getread(t_fileio *fio);
-/* Return  whether read mode is on in fio  */
-
-
-void gmx_fio_checktype(t_fileio *fio);
-/* Check whether the fio is of a sane type */
-
-/***************************************************
- * FILE Operations
- ***************************************************/
-
-void gmx_fio_rewind(t_fileio *fio);
-/* Rewind the tpa file in fio */
-
-int gmx_fio_flush(t_fileio *fio);
-/* Flush the fio, returns 0 on success */
-
-int gmx_fio_fsync(t_fileio *fio);
-/* fsync the fio, returns 0 on success. 
-   NOTE: don't use fsync function unless you're absolutely sure you need it
-   because it deliberately interferes with the OS's caching mechanisms and
-   can cause dramatically slowed down IO performance. Some OSes (Linux, 
-   for example), may implement fsync as a full sync() point. */
-
-gmx_off_t gmx_fio_ftell(t_fileio *fio);
-/* Return file position if possible */
-
-int gmx_fio_seek(t_fileio *fio,gmx_off_t fpos);
-/* Set file position if possible, quit otherwise */
-
-FILE *gmx_fio_getfp(t_fileio *fio);
-/* Return the file pointer itself */
-
-XDR *gmx_fio_getxdr(t_fileio *fio);
-/* Return the file pointer itself */
-
-
-
-
-
-/* Element with information about position in a currently open file.
- * gmx_off_t should be defined by autoconf if your system does not have it.
- * If you do not have it on some other platform you do not have largefile 
- * support at all, and you can define it to int (or better, find out how to 
- * enable large files).  */
-typedef struct
-{
-       char      filename[STRLEN];
-       gmx_off_t offset; 
-       unsigned char chksum[16];
-       int       chksum_size;
-} 
-gmx_file_position_t;
-
-
-int gmx_fio_check_file_position(t_fileio *fio);
-/* Check if the file position is out of the range of off_t.
- * The result is stored along with the other file data of fio.
- */
-
-int gmx_fio_get_output_file_positions(gmx_file_position_t ** outputfiles,
-                                      int *nfiles );
-/* Return the name and file pointer positions for all currently open
- * output files. This is used for saving in the checkpoint files, so we
- * can truncate output files upon restart-with-appending.
- *
- * For the first argument you should use a pointer, which will be set to
- * point to a list of open files.
- */
-
-t_fileio *gmx_fio_all_output_fsync(void);
-/* fsync all open output files. This is used for checkpointing, where
-   we need to ensure that all output is actually written out to 
-   disk. 
-   This is most important in the case of some networked file systems, 
-   where data is not synced with the file server until close() or 
-   fsync(), so data could remain in cache for days.
-   Note the caveats reported with gmx_fio_fsync(). 
-   
-    returns: NULL if no error occurred, or a pointer to the first file that
-             failed if an error occurred 
-*/
-
-
-int gmx_fio_get_file_md5(t_fileio *fio, gmx_off_t offset,  
-                         unsigned char digest[]);
-
-
-int xtc_seek_frame(t_fileio *fio, int frame, int natoms);
-
-int xtc_seek_time(t_fileio *fio, real time, int natoms);
-
-       
-/* Add this to the comment string for debugging */
-void gmx_fio_set_comment(t_fileio *fio, const char *comment);
-
-/* Remove previously set comment */
-void gmx_fio_unset_comment(t_fileio *fio);
-
-
-
-
-/********************************************************
- * Read and write
- ********************************************************/
-
-
-/* basic reading & writing */
-gmx_bool gmx_fio_reade_real(t_fileio *fio, real *item, 
-                        const char *desc, const char *srcfile, int line);
-gmx_bool gmx_fio_reade_float(t_fileio *fio, float *item, 
-                          const char *desc, const char *srcfile, int line);
-gmx_bool gmx_fio_reade_double(t_fileio *fio, double *item, 
-                          const char *desc, const char *srcfile, int line);
-gmx_bool gmx_fio_reade_int(t_fileio *fio, int *item, 
-                       const char *desc, const char *srcfile, int line);
-gmx_bool gmx_fio_reade_gmx_large_int(t_fileio *fio, gmx_large_int_t *item, 
-                                 const char *desc, const char *srcfile, int line);
-gmx_bool gmx_fio_reade_uchar(t_fileio *fio, unsigned char *item, 
-                         const char *desc, const char *srcfile, int line);
-gmx_bool gmx_fio_reade_ushort(t_fileio *fio, unsigned short *item, 
-                         const char *desc, const char *srcfile, int line);
-gmx_bool gmx_fio_reade_rvec(t_fileio *fio, rvec *item, 
-                        const char *desc, const char *srcfile, int line);
-gmx_bool gmx_fio_reade_ivec(t_fileio *fio, ivec *item, 
-                        const char *desc, const char *srcfile, int line);
-gmx_bool gmx_fio_reade_string(t_fileio *fio, char *item, 
-                          const char *desc, const char *srcfile, int line);
-
-gmx_bool gmx_fio_writee_real(t_fileio *fio, real item, 
-                         const char *desc, const char *srcfile, int line);
-gmx_bool gmx_fio_writee_float(t_fileio *fio, float item, 
-                           const char *desc, const char *srcfile, int line);
-gmx_bool gmx_fio_writee_double(t_fileio *fio, double item, 
-                           const char *desc, const char *srcfile, int line);
-gmx_bool gmx_fio_writee_int(t_fileio *fio, int item, 
-                        const char *desc, const char *srcfile, int line);
-gmx_bool gmx_fio_writee_gmx_large_int(t_fileio *fio, gmx_large_int_t item, 
-                                  const char *desc, const char *srcfile, int line);
-gmx_bool gmx_fio_writee_uchar(t_fileio *fio, unsigned char item, 
-                          const char *desc, const char *srcfile, int line);
-gmx_bool gmx_fio_writee_ushort(t_fileio *fio, unsigned short item, 
-                          const char *desc, const char *srcfile, int line);
-gmx_bool gmx_fio_writee_rvec(t_fileio *fio, rvec *item, 
-                         const char *desc, const char *srcfile, int line);
-gmx_bool gmx_fio_writee_ivec(t_fileio *fio, ivec *item, 
-                         const char *desc, const char *srcfile, int line);
-gmx_bool gmx_fio_writee_string(t_fileio *fio, const char *item, 
-                           const char *desc, const char *srcfile, int line);
-
-/* reading or writing, depending on the file's opening mode string */
-gmx_bool gmx_fio_doe_real(t_fileio *fio, real *item, 
-                      const char *desc, const char *srcfile, int line);
-gmx_bool gmx_fio_doe_float(t_fileio *fio, float *item, 
-                       const char *desc, const char *srcfile, int line);
-gmx_bool gmx_fio_doe_double(t_fileio *fio, double *item, 
-                        const char *desc, const char *srcfile, int line);
-gmx_bool gmx_fio_doe_gmx_bool(t_fileio *fio, gmx_bool *item, 
-                     const char *desc, const char *srcfile, int line);
-gmx_bool gmx_fio_doe_int(t_fileio *fio, int *item, 
-                     const char *desc, const char *srcfile, int line);
-gmx_bool gmx_fio_doe_gmx_large_int(t_fileio *fio, gmx_large_int_t *item, 
-                               const char *desc, const char *srcfile, int line);
-gmx_bool gmx_fio_doe_uchar(t_fileio *fio, unsigned char *item, 
-                       const char *desc, const char *srcfile, int line);
-gmx_bool gmx_fio_doe_ushort(t_fileio *fio, unsigned short *item, 
-                       const char *desc, const char *srcfile, int line);
-gmx_bool gmx_fio_doe_rvec(t_fileio *fio, rvec *item, 
-                      const char *desc, const char *srcfile, int line);
-gmx_bool gmx_fio_doe_ivec(t_fileio *fio, ivec *item, 
-                      const char *desc, const char *srcfile, int line);
-gmx_bool gmx_fio_doe_string(t_fileio *fio, char *item, 
-                        const char *desc, const char *srcfile, int line);
-
-
-
-
-/* array reading & writing */
-gmx_bool gmx_fio_nreade_real(t_fileio *fio, real *item, int n, 
-                         const char *desc, const char *srcfile, int line);
-gmx_bool gmx_fio_nreade_float(t_fileio *fio, float *item, int n, 
-                          const char *desc, const char *srcfile, int line);
-gmx_bool gmx_fio_nreade_double(t_fileio *fio, double *item, int n, 
-                           const char *desc, const char *srcfile, int line);
-gmx_bool gmx_fio_nreade_int(t_fileio *fio, int *item, int n, 
-                        const char *desc, const char *srcfile, int line);
-gmx_bool gmx_fio_nreade_gmx_large_int(t_fileio *fio, gmx_large_int_t *item, int n, 
-                                  const char *desc, const char *srcfile, 
-                                  int line);
-gmx_bool gmx_fio_nreade_uchar(t_fileio *fio, unsigned char *item, int n, 
-                          const char *desc, const char *srcfile, int line);
-gmx_bool gmx_fio_nreade_ushort(t_fileio *fio, unsigned short *item, int n, 
-                          const char *desc, const char *srcfile, int line);
-gmx_bool gmx_fio_nreade_rvec(t_fileio *fio, rvec *item, int n, 
-                         const char *desc, const char *srcfile, int line);
-gmx_bool gmx_fio_nreade_ivec(t_fileio *fio, ivec *item, int n, 
-                         const char *desc, const char *srcfile, int line);
-gmx_bool gmx_fio_nreade_string(t_fileio *fio, char *item[], int n, 
-                           const char *desc, const char *srcfile, int line);
-
-gmx_bool gmx_fio_nwritee_real(t_fileio *fio, const real *item, int n, 
-                          const char *desc, const char *srcfile, int line);
-gmx_bool gmx_fio_nwritee_float(t_fileio *fio, const float *item, int n, 
-                           const char *desc, const char *srcfile, int line);
-gmx_bool gmx_fio_nwritee_double(t_fileio *fio, const double *item, int n, 
-                            const char *desc, const char *srcfile, int line);
-gmx_bool gmx_fio_nwritee_int(t_fileio *fio, const int *item, int n, 
-                         const char *desc, const char *srcfile, int line);
-gmx_bool gmx_fio_nwritee_gmx_large_int(t_fileio *fio, 
-                                   const gmx_large_int_t *item, int n,
-                                   const char *desc, const char *srcfile, 
-                                   int line);
-gmx_bool gmx_fio_nwritee_uchar(t_fileio *fio, const unsigned char *item, int n, 
-                           const char *desc, const char *srcfile, int line);
-gmx_bool gmx_fio_nwritee_ushort(t_fileio *fio, const unsigned short *item, int n, 
-                           const char *desc, const char *srcfile, int line);
-gmx_bool gmx_fio_nwritee_rvec(t_fileio *fio, const rvec *item, int n, 
-                          const char *desc, const char *srcfile, int line);
-gmx_bool gmx_fio_nwritee_ivec(t_fileio *fio, const ivec *item, int n, 
-                          const char *desc, const char *srcfile, int line);
-gmx_bool gmx_fio_nwritee_string(t_fileio *fio, const char *item[], int n, 
-                            const char *desc, const char *srcfile, int line);
-
-gmx_bool gmx_fio_ndoe_real(t_fileio *fio, real *item, int n, 
-                       const char *desc, const char *srcfile, int line);
-gmx_bool gmx_fio_ndoe_float(t_fileio *fio, float *item, int n, 
-                         const char *desc, const char *srcfile, int line);
-gmx_bool gmx_fio_ndoe_double(t_fileio *fio, double *item, int n, 
-                         const char *desc, const char *srcfile, int line);
-gmx_bool gmx_fio_ndoe_gmx_bool(t_fileio *fio, gmx_bool *item, int n, 
-                      const char *desc, const char *srcfile, int line);
-gmx_bool gmx_fio_ndoe_int(t_fileio *fio, int *item, int n, 
-                      const char *desc, const char *srcfile, int line);
-gmx_bool gmx_fio_ndoe_gmx_large_int(t_fileio *fio, gmx_large_int_t *item, int n, 
-                                const char *desc, const char *srcfile, 
-                                int line);
-gmx_bool gmx_fio_ndoe_uchar(t_fileio *fio, unsigned char *item, int n, 
-                        const char *desc, const char *srcfile, int line);
-gmx_bool gmx_fio_ndoe_ushort(t_fileio *fio, unsigned short *item, int n, 
-                        const char *desc, const char *srcfile, int line);
-gmx_bool gmx_fio_ndoe_rvec(t_fileio *fio, rvec *item, int n, 
-                       const char *desc, const char *srcfile, int line);
-gmx_bool gmx_fio_ndoe_ivec(t_fileio *fio, ivec *item, int n, 
-                       const char *desc, const char *srcfile, int line);
-gmx_bool gmx_fio_ndoe_string(t_fileio *fio, char *item[], int n, 
-                         const char *desc, const char *srcfile, int line);
-
-
-
-/* convenience macros */
-#define gmx_fio_read_real(fio, item)           gmx_fio_reade_real(fio, &item, (#item), __FILE__, __LINE__)
-#define gmx_fio_read_float(fio, item)          gmx_fio_reade_float(fio, &item, (#item), __FILE__, __LINE__)
-#define gmx_fio_read_double(fio, item)         gmx_fio_reade_double(fio, &item, (#item), __FILE__, __LINE__)
-#define gmx_fio_read_int(fio, item)            gmx_fio_reade_int(fio, &item, (#item), __FILE__, __LINE__)
-#define gmx_fio_read_gmx_large_int(fio, item)  gmx_fio_reade_gmx_large_int(fio, &item, (#item), __FILE__, __LINE__)
-#define gmx_fio_read_uchar(fio, item)          gmx_fio_reade_uchar(fio, &item, (#item), __FILE__, __LINE__)
-#define gmx_fio_read_ushort(fio, item)         gmx_fio_reade_ushort(fio, &item, (#item), __FILE__, __LINE__)
-#define gmx_fio_read_rvec(fio, item)           gmx_fio_reade_rvec(fio, item, (#item), __FILE__, __LINE__)
-#define gmx_fio_read_ivec(fio, item)           gmx_fio_reade_ivec(fio, item, (#item), __FILE__, __LINE__)
-#define gmx_fio_read_string(fio, item)         gmx_fio_reade_string(fio, item, (#item), __FILE__, __LINE__)
-
-#define gmx_fio_write_real(fio, item)           gmx_fio_writee_real(fio, item, (#item), __FILE__, __LINE__)
-#define gmx_fio_write_float(fio, item)          gmx_fio_writee_float(fio, item, (#item), __FILE__, __LINE__)
-#define gmx_fio_write_double(fio, item)         gmx_fio_writee_double(fio, item, (#item), __FILE__, __LINE__)
-#define gmx_fio_write_int(fio, item)            gmx_fio_writee_int(fio, item, (#item), __FILE__, __LINE__)
-#define gmx_fio_write_gmx_large_int(fio, item)  gmx_fio_writee_gmx_large_int(fio, item, (#item), __FILE__, __LINE__)
-#define gmx_fio_write_uchar(fio, item)          gmx_fio_writee_uchar(fio, item, (#item), __FILE__, __LINE__)
-#define gmx_fio_write_ushort(fio, item)         gmx_fio_writee_ushort(fio, item, (#item), __FILE__, __LINE__)
-#define gmx_fio_write_rvec(fio, item)           gmx_fio_writee_rvec(fio, item, (#item), __FILE__, __LINE__)
-#define gmx_fio_write_ivec(fio, item)           gmx_fio_writee_ivec(fio, item, (#item), __FILE__, __LINE__)
-#define gmx_fio_write_string(fio, item)         gmx_fio_writee_string(fio, item, (#item), __FILE__, __LINE__)
-
-#define gmx_fio_do_real(fio, item)              gmx_fio_doe_real(fio, &item, (#item), __FILE__, __LINE__)
-#define gmx_fio_do_float(fio, item)             gmx_fio_doe_float(fio, &item, (#item), __FILE__, __LINE__)
-#define gmx_fio_do_double(fio, item)            gmx_fio_doe_double(fio, &item, (#item), __FILE__, __LINE__)
-#define gmx_fio_do_gmx_bool(fio, item)              gmx_fio_doe_gmx_bool(fio, &item, (#item), __FILE__, __LINE__)
-#define gmx_fio_do_int(fio, item)               gmx_fio_doe_int(fio, &item, (#item), __FILE__, __LINE__)
-#define gmx_fio_do_gmx_large_int(fio, item)     gmx_fio_doe_gmx_large_int(fio, &item, (#item), __FILE__, __LINE__)
-#define gmx_fio_do_uchar(fio, item)             gmx_fio_doe_uchar(fio, &item, (#item), __FILE__, __LINE__)
-#define gmx_fio_do_ushort(fio, item)            gmx_fio_doe_ushort(fio, &item, (#item), __FILE__, __LINE__)
-#define gmx_fio_do_rvec(fio, item)              gmx_fio_doe_rvec(fio, &item, (#item), __FILE__, __LINE__)
-#define gmx_fio_do_ivec(fio, item)              gmx_fio_doe_ivec(fio, &item, (#item), __FILE__, __LINE__)
-#define gmx_fio_do_string(fio, item)            gmx_fio_doe_string(fio, item, (#item), __FILE__, __LINE__)
-
-
-
-
-#define gmx_fio_nread_real(fio, item, n)            gmx_fio_nreade_real(fio, item, n, (#item), __FILE__, __LINE__)
-#define gmx_fio_nread_float(fio, item, n)           gmx_fio_nreade_float(fio, item, n, (#item), __FILE__, __LINE__)
-#define gmx_fio_nread_double(fio, item, n)          gmx_fio_nreade_double(fio, item, n, (#item), __FILE__, __LINE__)
-#define gmx_fio_nread_int(fio, item, n)             gmx_fio_nreade_int(fio, item, n, (#item), __FILE__, __LINE__)
-#define gmx_fio_nread_gmx_large_int(fio, item, n)   gmx_fio_nreade_gmx_large_int(fio, item, n, (#item), __FILE__, __LINE__)
-#define gmx_fio_nread_uchar(fio, item, n)           gmx_fio_nreade_uchar(fio, item, n, (#item), __FILE__, __LINE__)
-#define gmx_fio_nread_ushort(fio, item, n)          gmx_fio_nreade_ushort(fio, item, n, (#item), __FILE__, __LINE__)
-#define gmx_fio_nread_rvec(fio, item, n)            gmx_fio_nreade_rvec(fio, item, n, (#item), __FILE__, __LINE__)
-#define gmx_fio_nread_ivec(fio, item, n)            gmx_fio_nreade_ivec(fio, item, n, (#item), __FILE__, __LINE__)
-#define gmx_fio_nread_string(fio, item, n)          gmx_fio_nreade_string(fio, item, n, (#item), __FILE__, __LINE__)
-
-#define gmx_fio_nwrite_real(fio, item, n)           gmx_fio_nwritee_real(fio, item, n, (#item), __FILE__, __LINE__)
-#define gmx_fio_nwrite_float(fio, item, n)          gmx_fio_nwritee_float(fio, item, n, (#item), __FILE__, __LINE__)
-#define gmx_fio_nwrite_double(fio, item, n)         gmx_fio_nwritee_double(fio, item, n, (#item), __FILE__, __LINE__)
-#define gmx_fio_nwrite_int(fio, item, n)            gmx_fio_nwritee_int(fio, item, n, (#item), __FILE__, __LINE__)
-#define gmx_fio_nwrite_gmx_large_int(fio, item, n)  gmx_fio_nwritee_gmx_large_int(fio, item, n, (#item), __FILE__, __LINE__)
-#define gmx_fio_nwrite_uchar(fio, item, n)          gmx_fio_nwritee_uchar(fio, item, n, (#item), __FILE__, __LINE__)
-#define gmx_fio_nwrite_ushort(fio, item, n)         gmx_fio_nwritee_ushort(fio, item, n, (#item), __FILE__, __LINE__)
-#define gmx_fio_nwrite_rvec(fio, item, n)           gmx_fio_nwritee_rvec(fio, item, n, (#item), __FILE__, __LINE__)
-#define gmx_fio_nwrite_ivec(fio, item, n)           gmx_fio_nwritee_ivec(fio, item, n, (#item), __FILE__, __LINE__)
-#define gmx_fio_nwrite_string(fio, item, n)         gmx_fio_nwritee_string(fio, item, n, (#item), __FILE__, __LINE__)
-
-#define gmx_fio_ndo_real(fio, item, n)              gmx_fio_ndoe_real(fio, item, n, (#item), __FILE__, __LINE__)
-#define gmx_fio_ndo_float(fio, item, n)             gmx_fio_ndoe_float(fio, item, n, (#item), __FILE__, __LINE__)
-#define gmx_fio_ndo_double(fio, item, n)            gmx_fio_ndoe_double(fio, item, n, (#item), __FILE__, __LINE__)
-#define gmx_fio_ndo_gmx_bool(fio, item, n)              gmx_fio_ndoe_gmx_bool(fio, item, n, (#item), __FILE__, __LINE__)
-#define gmx_fio_ndo_int(fio, item, n)               gmx_fio_ndoe_int(fio, item, n, (#item), __FILE__, __LINE__)
-#define gmx_fio_ndo_gmx_large_int(fio, item, n)     gmx_fio_ndoe_gmx_large_int(fio, item, n, (#item), __FILE__, __LINE__)
-#define gmx_fio_ndo_uchar(fio, item, n)             gmx_fio_ndoe_uchar(fio, item, n, (#item), __FILE__, __LINE__)
-#define gmx_fio_ndo_ushort(fio, item, n)            gmx_fio_ndoe_ushort(fio, item, n, (#item), __FILE__, __LINE__)
-#define gmx_fio_ndo_rvec(fio, item, n)              gmx_fio_ndoe_rvec(fio, item, n, (#item), __FILE__, __LINE__)
-#define gmx_fio_ndo_ivec(fio, item, n)              gmx_fio_ndoe_ivec(fio, item, n, (#item), __FILE__, __LINE__)
-#define gmx_fio_ndo_string(fio, item, n)            gmx_fio_ndoe_string(fio, item, n, (#item), __FILE__, __LINE__)
-
-
-
-#endif
diff --git a/include/indexutil.h b/include/indexutil.h
deleted file mode 100644 (file)
index 6af9d9d..0000000
+++ /dev/null
@@ -1,357 +0,0 @@
-/*
- *
- *                This source code is part of
- *
- *                 G   R   O   M   A   C   S
- *
- *          GROningen MAchine for Chemical Simulations
- *
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
- * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
- * Copyright (c) 2001-2009, The GROMACS development team,
- * check out http://www.gromacs.org for more information.
-
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * If you want to redistribute modifications, please consider that
- * scientific software is very special. Version control is crucial -
- * bugs must be traceable. We will be happy to consider code for
- * inclusion in the official distribution, but derived work must not
- * be called official GROMACS. Details are found in the README & COPYING
- * files - if they are missing, get the official version at www.gromacs.org.
- *
- * To help us fund GROMACS development, we humbly ask that you cite
- * the papers on the package - you can find them in the top README file.
- *
- * For more info, check our website at http://www.gromacs.org
- */
-/*! \file
- * \brief API for handling index files and index groups.
- *
- * The API contains functions and data structures for handling index
- * files more conveniently than as several separate variables.
- * In addition to basic functions for initializing the data structures and
- * making copies, functions are provided for performing (most) set operations
- * on sorted index groups.
- * There is also a function for partitioning a index group based on
- * topology information such as residues or molecules.
- * Finally, there is a set of functions for constructing mappings between
- * an index group and its subgroups such.
- * These can be used with dynamic index group in calculations if one
- * needs to have a unique ID for each possible atom/residue/molecule in the
- * selection, e.g., for analysis of dynamics or for look-up tables.
- *
- * Mostly, these functions are used internally by the library and the
- * selection engine.
- * However, some of the checking functions can be useful in user code to
- * check the validity of input groups.
- * Also, the mapping functions are useful when dealing with dynamic index
- * groups.
- */
-#ifndef INDEXUTIL_H
-#define INDEXUTIL_H
-
-#include "typedefs.h"
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif
-
-/** Stores a set of index groups. */
-typedef struct gmx_ana_indexgrps_t gmx_ana_indexgrps_t;
-
-/*! \brief
- * Specifies the type of index partition or index mapping in several contexts.
- *
- * \see gmx_ana_index_make_block(), gmx_ana_indexmap_init()
- */
-typedef enum
-{
-    INDEX_UNKNOWN, /**< Unknown index type.*/
-    INDEX_ATOM,    /**< Each atom in a separate block.*/
-    INDEX_RES,     /**< Each residue in a separate block.*/
-    INDEX_MOL,     /**< Each molecule in a separate block.*/
-    INDEX_ALL      /**< All atoms in a single block.*/
-} e_index_t;
-
-/*! \brief
- * Stores a single index group.
- */
-typedef struct gmx_ana_index_t
-{
-    /** Number of atoms. */
-    int                 isize;
-    /** List of atoms. */
-    atom_id            *index;
-    /** Group name. */
-    char               *name;
-    /** Number of items allocated for \p index. */
-    int                 nalloc_index;
-} gmx_ana_index_t;
-
-/*! \brief
- * Data structure for calculating index group mappings.
- */
-typedef struct gmx_ana_indexmap_t
-{
-    /** Type of the mapping. */
-    e_index_t           type;
-    /*! \brief
-     * Current number of mapped values.
-     *
-     * This is the current number of values in the \p refid and \p mapid
-     * arrays.
-     * If \p bMaskOnly is provided to gmx_ana_indexmap_update(), this
-     * is always equal to \p b.nr, i.e., the number of blocks in the
-     * original index group.
-     */
-    int                 nr;
-    /*! \brief
-     * Current reference IDs.
-     *
-     * This array provides a mapping from the current index group (last given
-     * to gmx_ana_indexmap_update()) to the blocks in \p b, i.e., the
-     * original index group used in gmx_ana_indexmap_init().
-     * The mapping is zero-based.
-     * If \p bMaskOnly is provided to gmx_ana_indexmap_update(), the indices
-     * for blocks not present in the current group are set to -1, otherwise
-     * they are removed completely and the \p nr field updated.
-     */
-    int                *refid;
-    /*! \brief
-     * Current mapped IDs.
-     *
-     * This array provides an arbitrary mapping from the current index group
-     * to the original index group. Instead of a zero-based mapping, the
-     * values from the \p orgid array are used. That is,
-     * \c mapid[i]=orgid[refid[i]].
-     * If \p bMaskOnly is provided to gmx_ana_indexmap_update(), this array
-     * equals \p orgid.
-     */
-    int                *mapid;
-    /*! \brief
-     * Mapped block structure.
-     *
-     * A block structure that corresponds to the current index group.
-     */
-    t_block             mapb;
-
-    /*! \brief
-     * Arbitrary ID numbers for the blocks.
-     *
-     * This array has \p b.nr elements, each defining an ID number for a
-     * block in \p b.
-     * These are initialized in gmx_ana_indexmap_init() based on the type:
-     *  - \ref INDEX_ATOM : the atom indices
-     *  - \ref INDEX_RES :  the residue numbers
-     *  - \ref INDEX_MOL :  the molecule numbers
-     *
-     * All the above numbers are zero-based.
-     * After gmx_ana_indexmap_init(), the user is free to change these values
-     * if the above are not appropriate.
-     * The mapped values can be read through \p mapid.
-     */
-    int                *orgid;
-
-    /*! \brief
-     * Block data that defines the mapping (internal use only).
-     *
-     * The data is initialized by gmx_ana_indexmap_init() and is not changed
-     * after that.
-     * Hence, it cannot be directly applied to the index group passed to
-     * gmx_ana_indexmap_update() unless \p bMaskOnly was specified or the
-     * index group is identical to the one provided to gmx_ana_indexmap_init().
-     */
-    t_blocka            b;
-    /*! \brief
-     * TRUE if the current reference IDs are for the whole group (internal use only).
-     *
-     * This is used internally to optimize the evaluation such that
-     * gmx_ana_indexmap_update() does not take any time if the group is
-     * actually static.
-     */
-    gmx_bool                bStatic;
-    /*! \brief
-     * TRUE if the current mapping is for the whole group (internal use only).
-     *
-     * This is used internally to optimize the evaluation such that
-     * gmx_ana_indexmap_update() does not take any time if the group is
-     * actually static.
-     */
-    gmx_bool                bMapStatic;
-} gmx_ana_indexmap_t;
-
-
-/*! \name Functions for handling gmx_ana_indexgrps_t
- */
-/*@{*/
-/** Allocate memory for index groups. */
-void
-gmx_ana_indexgrps_alloc(gmx_ana_indexgrps_t **g, int ngrps);
-/** Initializes index groups from arrays. */
-void
-gmx_ana_indexgrps_set(gmx_ana_indexgrps_t **g, int ngrps, int *isize,
-                      atom_id **index, char **name, gmx_bool bFree);
-/** Reads index groups from a file or constructs them from topology. */
-void
-gmx_ana_indexgrps_init(gmx_ana_indexgrps_t **g, t_topology *top, 
-                       const char *fnm);
-/** Ask user to select index groups, possibly constructing groups from 
- *  topology. */
-void
-gmx_ana_indexgrps_get(gmx_ana_indexgrps_t **g, t_topology *top, 
-                      const char *fnm, int ngrps);
-/** Ask user to select index groups from those specified in a file. */
-void
-gmx_ana_indexgrps_rd(gmx_ana_indexgrps_t **g, const char *fnm, int ngrps);
-/** Frees memory allocated for index groups. */
-void
-gmx_ana_indexgrps_free(gmx_ana_indexgrps_t *g);
-/** Create a deep copy of \c gmx_ana_indexgrps_t. */
-void
-gmx_ana_indexgrps_clone(gmx_ana_indexgrps_t **dest, gmx_ana_indexgrps_t *src);
-/** Returns TRUE if the index group structure is emtpy. */
-gmx_bool
-gmx_ana_indexgrps_is_empty(gmx_ana_indexgrps_t *g);
-
-/** Returns a pointer to an index group. */
-gmx_ana_index_t *
-gmx_ana_indexgrps_get_grp(gmx_ana_indexgrps_t *g, int n);
-/** Extracts a single index group. */
-gmx_bool
-gmx_ana_indexgrps_extract(gmx_ana_index_t *dest, gmx_ana_indexgrps_t *src, int n);
-/** Finds and extracts a single index group by name. */
-gmx_bool
-gmx_ana_indexgrps_find(gmx_ana_index_t *dest, gmx_ana_indexgrps_t *src, char *name);
-
-/** Writes out a list of index groups. */
-void
-gmx_ana_indexgrps_print(gmx_ana_indexgrps_t *g, int maxn);
-/*@}*/
-
-/*! \name Functions for handling gmx_ana_index_t
- */
-/*@{*/
-/** Reserves memory to store an index group of size \p isize. */
-void
-gmx_ana_index_reserve(gmx_ana_index_t *g, int isize);
-/** Frees any memory not necessary to hold the current contents. */
-void
-gmx_ana_index_squeeze(gmx_ana_index_t *g);
-/** Initializes an empty index group. */
-void
-gmx_ana_index_clear(gmx_ana_index_t *g);
-/** Constructs a \c gmx_ana_index_t from given values. */
-void
-gmx_ana_index_set(gmx_ana_index_t *g, int isize, atom_id *index, char *name,
-                  int nalloc);
-/** Creates a simple index group from the first to the \p natoms'th atom. */
-void
-gmx_ana_index_init_simple(gmx_ana_index_t *g, int natoms, char *name);
-/** Frees memory allocated for an index group. */
-void
-gmx_ana_index_deinit(gmx_ana_index_t *g);
-/** Copies a \c gmx_ana_index_t. */
-void
-gmx_ana_index_copy(gmx_ana_index_t *dest, gmx_ana_index_t *src, gmx_bool bAlloc);
-
-/** Writes out the contents of a index group. */
-void
-gmx_ana_index_dump(gmx_ana_index_t *g, int i, int maxn);
-
-/** Checks whether all indices are between 0 and \p natoms. */
-void
-gmx_ana_index_check(gmx_ana_index_t *g, int natoms);
-/** Checks whether an index group is sorted. */
-gmx_bool
-gmx_ana_index_check_sorted(gmx_ana_index_t *g);
-/*@}*/
-
-/*! \name Functions for set operations on gmx_ana_index_t
- */
-/*@{*/
-/** Sorts the indices within an index group. */
-void
-gmx_ana_index_sort(gmx_ana_index_t *g);
-/** Checks whether two index groups are equal. */
-gmx_bool
-gmx_ana_index_equals(gmx_ana_index_t *a, gmx_ana_index_t *b);
-/** Checks whether a sorted index group contains another sorted index group. */
-gmx_bool
-gmx_ana_index_contains(gmx_ana_index_t *a, gmx_ana_index_t *b);
-
-/** Calculates the intersection between two sorted index groups. */
-void
-gmx_ana_index_intersection(gmx_ana_index_t *dest,
-                           gmx_ana_index_t *a, gmx_ana_index_t *b);
-/** Calculates the set difference between two sorted index groups. */
-void
-gmx_ana_index_difference(gmx_ana_index_t *dest,
-                         gmx_ana_index_t *a, gmx_ana_index_t *b);
-/** Calculates the size of the difference between two sorted index groups. */
-int
-gmx_ana_index_difference_size(gmx_ana_index_t *a, gmx_ana_index_t *b);
-/** Calculates the union of two sorted index groups. */
-void
-gmx_ana_index_union(gmx_ana_index_t *dest,
-                    gmx_ana_index_t *a, gmx_ana_index_t *b);
-/** Merges two distinct sorted index groups. */
-void
-gmx_ana_index_merge(gmx_ana_index_t *dest,
-                    gmx_ana_index_t *a, gmx_ana_index_t *b);
-/** Calculates the intersection and the difference in one call. */
-void
-gmx_ana_index_partition(gmx_ana_index_t *dest1, gmx_ana_index_t *dest2,
-                        gmx_ana_index_t *src, gmx_ana_index_t *g);
-/*@}*/
-
-/*! \name Functions for handling gmx_ana_indexmap_t and related things
- */
-/*@{*/
-/** Partition a group based on topology information. */
-void
-gmx_ana_index_make_block(t_blocka *t, t_topology *top, gmx_ana_index_t *g,
-                         e_index_t type, gmx_bool bComplete);
-/** Checks whether a group consists of full blocks. */
-gmx_bool
-gmx_ana_index_has_full_blocks(gmx_ana_index_t *g, t_block *b);
-/** Checks whether a group consists of full blocks. */
-gmx_bool
-gmx_ana_index_has_full_ablocks(gmx_ana_index_t *g, t_blocka *b);
-/** Checks whether a group consists of full residues/molecules. */
-gmx_bool
-gmx_ana_index_has_complete_elems(gmx_ana_index_t *g, e_index_t type, t_topology *top);
-
-/** Initializes an empty index group mapping. */
-void
-gmx_ana_indexmap_clear(gmx_ana_indexmap_t *m);
-/** Reserves memory for an index group mapping. */
-void
-gmx_ana_indexmap_reserve(gmx_ana_indexmap_t *m, int nr, int isize);
-/** Initializes an index group mapping. */
-void
-gmx_ana_indexmap_init(gmx_ana_indexmap_t *m, gmx_ana_index_t *g,
-                      t_topology *top, e_index_t type);
-/** Sets an index group mapping to be static. */
-void
-gmx_ana_indexmap_set_static(gmx_ana_indexmap_t *m, t_blocka *b);
-/** Frees memory allocated for index group mapping. */
-void
-gmx_ana_indexmap_deinit(gmx_ana_indexmap_t *m);
-/** Makes a deep copy of an index group mapping. */
-void
-gmx_ana_indexmap_copy(gmx_ana_indexmap_t *dest, gmx_ana_indexmap_t *src, gmx_bool bFirst);
-/** Updates an index group mapping. */
-void
-gmx_ana_indexmap_update(gmx_ana_indexmap_t *m, gmx_ana_index_t *g, gmx_bool bMaskOnly);
-/*@}*/
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/include/mdrun.h b/include/mdrun.h
deleted file mode 100644 (file)
index 7bf4434..0000000
+++ /dev/null
@@ -1,370 +0,0 @@
-/*
- * 
- *                This source code is part of
- * 
- *                 G   R   O   M   A   C   S
- * 
- *          GROningen MAchine for Chemical Simulations
- * 
- *                        VERSION 3.2.0
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
- * 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.
-
- * 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:
- * Gromacs Runs On Most of All Computer Systems
- */
-
-#ifndef _mdrun_h
-#define _mdrun_h
-
-#include <stdio.h>
-#include <time.h>
-#include "typedefs.h"
-#include "network.h"
-#include "tgroup.h"
-#include "filenm.h"
-#include "mshift.h"
-#include "force.h"
-#include "edsam.h"
-#include "mdebin.h"
-#include "vcm.h"
-#include "vsite.h"
-#include "pull.h"
-#include "update.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define MD_POLARISE       (1<<2)
-#define MD_IONIZE         (1<<3)
-#define MD_RERUN          (1<<4)
-#define MD_RERUN_VSITE    (1<<5)
-#define MD_FFSCAN         (1<<6)
-#define MD_SEPPOT         (1<<7)
-#define MD_PARTDEC        (1<<9)
-#define MD_DDBONDCHECK    (1<<10)
-#define MD_DDBONDCOMM     (1<<11)
-#define MD_CONFOUT        (1<<12)
-#define MD_REPRODUCIBLE   (1<<13)
-#define MD_READ_RNG       (1<<14)
-#define MD_APPENDFILES    (1<<15)
-#define MD_KEEPANDNUMCPT  (1<<16)
-#define MD_READ_EKIN      (1<<17)
-#define MD_STARTFROMCPT   (1<<18)
-#define MD_RESETCOUNTERSHALFWAY (1<<19)
-
-/* Define a number of flags to better control the information
- * passed to compute_globals in md.c and global_stat.
- */
-
-/* We are rerunning the simulation */
-#define CGLO_RERUNMD        (1<<1)
-/* we are computing the kinetic energy from average velocities */
-#define CGLO_EKINAVEVEL     (1<<2)
-/* we are removing the center of mass momenta */
-#define CGLO_STOPCM         (1<<3)
-/* bGStat is defined in do_md */
-#define CGLO_GSTAT          (1<<4)
-/* Sum the energy terms in global computation */
-#define CGLO_ENERGY         (1<<6)
-/* Sum the kinetic energy terms in global computation */
-#define CGLO_TEMPERATURE    (1<<7)
-/* Sum the kinetic energy terms in global computation */
-#define CGLO_PRESSURE       (1<<8)
-/* Sum the constraint term in global computation */
-#define CGLO_CONSTRAINT     (1<<9)
-/* we are using an integrator that requires iteration over some steps - currently not used*/
-#define CGLO_ITERATE        (1<<10)
-/* it is the first time we are iterating (or, only once through is required */
-#define CGLO_FIRSTITERATE   (1<<11)
-/* Reading ekin from the trajectory */
-#define CGLO_READEKIN       (1<<12)
-/* we need to reset the ekin rescaling factor here */
-#define CGLO_SCALEEKIN      (1<<13)
-  
-enum {
-  ddnoSEL, ddnoINTERLEAVE, ddnoPP_PME, ddnoCARTESIAN, ddnoNR
-};
-
-typedef struct {
-  double real;
-#ifdef GMX_CRAY_XT3
-  double proc;
-#else
-  clock_t proc;
-#endif
-  double realtime;
-  double proctime;
-  double time_per_step;
-  double last;
-  gmx_large_int_t nsteps_done;
-} gmx_runtime_t;
-
-typedef struct {
-  t_fileio *fp_trn;
-  t_fileio *fp_xtc;
-  int  xtc_prec;
-  ener_file_t fp_ene;
-  const char *fn_cpt;
-  gmx_bool bKeepAndNumCPT;
-  int  eIntegrator;
-  int  simulation_part;
-  FILE *fp_dhdl;
-  FILE *fp_field;
-} gmx_mdoutf_t;
-
-/* Variables for temporary use with the deform option,
- * used in runner.c and md.c.
- * (These variables should be stored in the tpx file.)
- */
-extern gmx_large_int_t     deform_init_init_step_tpx;
-extern matrix              deform_init_box_tpx;
-#ifdef GMX_THREADS
-extern tMPI_Thread_mutex_t deform_init_box_mutex;
-
-/* The minimum number of atoms per thread. With fewer atoms than this,
- * the number of threads will get lowered.
- */
-#define MIN_ATOMS_PER_THREAD    90
-#endif
-
-
-typedef double gmx_integrator_t(FILE *log,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 *inputrec,
-                               gmx_mtop_t *mtop,t_fcdata *fcd,
-                               t_state *state,
-                               t_mdatoms *mdatoms,
-                               t_nrnb *nrnb,gmx_wallcycle_t wcycle,
-                               gmx_edsam_t ed, 
-                               t_forcerec *fr,
-                               int repl_ex_nst,int repl_ex_seed,
-                               real cpt_period,real max_hours,
-                               const char *deviceOptions,
-                               unsigned long Flags,
-                               gmx_runtime_t *runtime);
-
-typedef struct gmx_global_stat *gmx_global_stat_t;
-
-/* ROUTINES from md.c */
-
-gmx_integrator_t do_md;
-
-gmx_integrator_t do_md_openmm;
-
-/* ROUTINES from minimize.c */
-
-gmx_integrator_t do_steep;
-/* Do steepest descents EM */
-
-gmx_integrator_t do_cg;
-/* Do conjugate gradient EM */
-
-gmx_integrator_t do_lbfgs;
-/* Do conjugate gradient L-BFGS */
-
-gmx_integrator_t do_nm;
-/* Do normal mode analysis */
-
-/* ROUTINES from tpi.c */
-
-gmx_integrator_t do_tpi;
-/* Do test particle insertion */
-
-
-/* ROUTINES from sim_util.c */
-void do_pbc_first(FILE *log,matrix box,t_forcerec *fr,
-                        t_graph *graph,rvec x[]);
-
-void do_pbc_first_mtop(FILE *fplog,int ePBC,matrix box,
-                             gmx_mtop_t *mtop,rvec x[]);
-
-void do_pbc_mtop(FILE *fplog,int ePBC,matrix box,
-                       gmx_mtop_t *mtop,rvec x[]);
-
-                    
-/* ROUTINES from stat.c */
-gmx_global_stat_t global_stat_init(t_inputrec *ir);
-
-void global_stat_destroy(gmx_global_stat_t gs);
-
-void global_stat(FILE *log,gmx_global_stat_t gs,
-                       t_commrec *cr,gmx_enerdata_t *enerd,
-                       tensor fvir,tensor svir,rvec mu_tot,
-                       t_inputrec *inputrec,
-                       gmx_ekindata_t *ekind,
-                       gmx_constr_t constr,t_vcm *vcm,
-                       int nsig,real *sig,
-                       gmx_mtop_t *top_global, t_state *state_local, 
-                       gmx_bool bSumEkinhOld, int flags);
-/* Communicate statistics over cr->mpi_comm_mysim */
-
-gmx_mdoutf_t *init_mdoutf(int nfile,const t_filenm fnm[],
-                                int mdrun_flags,
-                                const t_commrec *cr,const t_inputrec *ir,
-                                const output_env_t oenv);
-/* Returns a pointer to a data structure with all output file pointers
- * and names required by mdrun.
- */
-
-void done_mdoutf(gmx_mdoutf_t *of);
-/* Close all open output files and free the of pointer */
-
-#define MDOF_X   (1<<0)
-#define MDOF_V   (1<<1)
-#define MDOF_F   (1<<2)
-#define MDOF_XTC (1<<3)
-#define MDOF_CPT (1<<4)
-
-void write_traj(FILE *fplog,t_commrec *cr,
-                      gmx_mdoutf_t *of,
-                      int mdof_flags,
-                      gmx_mtop_t *top_global,
-                      gmx_large_int_t step,double t,
-                      t_state *state_local,t_state *state_global,
-                      rvec *f_local,rvec *f_global,
-                      int *n_xtc,rvec **x_xtc);
-/* Routine that writes frames to trn, xtc and/or checkpoint.
- * What is written is determined by the mdof_flags defined above.
- * Data is collected to the master node only when necessary.
- */
-
-int do_per_step(gmx_large_int_t step,gmx_large_int_t nstep);
-/* Return TRUE if io should be done */
-
-int do_any_io(int step, t_inputrec *ir);
-
-/* ROUTINES from sim_util.c */
-
-double gmx_gettime();
-
-void print_time(FILE *out, gmx_runtime_t *runtime,
-                       gmx_large_int_t step,t_inputrec *ir, t_commrec *cr);
-
-void runtime_start(gmx_runtime_t *runtime);
-
-void runtime_end(gmx_runtime_t *runtime);
-
-void runtime_upd_proc(gmx_runtime_t *runtime);
-/* The processor time should be updated every once in a while,
- * since on 32-bit manchines it loops after 72 minutes.
- */
-  
-void print_date_and_time(FILE *log,int pid,const char *title,
-                               const gmx_runtime_t *runtime);
-  
-void nstop_cm(FILE *log,t_commrec *cr,
-                    int start,int nr_atoms,real mass[],rvec x[],rvec v[]);
-
-void finish_run(FILE *log,t_commrec *cr,const char *confout,
-                      t_inputrec *inputrec,
-                      t_nrnb nrnb[],gmx_wallcycle_t wcycle,
-                      gmx_runtime_t *runtime,
-                      gmx_bool bWriteStat);
-
-void calc_enervirdiff(FILE *fplog,int eDispCorr,t_forcerec *fr);
-
-void calc_dispcorr(FILE *fplog,t_inputrec *ir,t_forcerec *fr,
-                         gmx_large_int_t step, int natoms, 
-                         matrix box,real lambda,tensor pres,tensor virial,
-                         real *prescorr, real *enercorr, real *dvdlcorr);
-
-typedef enum
-{
-  LIST_SCALARS =0001,
-  LIST_INPUTREC        =0002,
-  LIST_TOP     =0004,
-  LIST_X       =0010,
-  LIST_V       =0020,
-  LIST_F       =0040,
-  LIST_LOAD    =0100
-} t_listitem;
-
-void check_nnodes_top(char *fn,t_topology *top);
-/* Reset the tpr file to work with one node if necessary */
-
-
-/* check the version */
-void check_ir_old_tpx_versions(t_commrec *cr,FILE *fplog,
-                               t_inputrec *ir,gmx_mtop_t *mtop);
-
-/* Allocate and initialize node-local state entries. */
-void set_state_entries(t_state *state,const t_inputrec *ir,int nnodes);
-
-/* Broadcast the data for a simulation, and allocate node-specific settings
-   such as rng generators. */
-void init_parallel(FILE *log, t_commrec *cr, t_inputrec *inputrec,
-                          gmx_mtop_t *mtop);
-
-
-void do_constrain_first(FILE *log,gmx_constr_t constr,
-                              t_inputrec *inputrec,t_mdatoms *md,
-                              t_state *state,rvec *f,
-                              t_graph *graph,t_commrec *cr,t_nrnb *nrnb,
-                              t_forcerec *fr, gmx_localtop_t *top, tensor shake_vir); 
-                         
-void dynamic_load_balancing(gmx_bool bVerbose,t_commrec *cr,real capacity[],
-                                  int dimension,t_mdatoms *md,t_topology *top,
-                                  rvec x[],rvec v[],matrix box);
-/* Perform load balancing, i.e. split the particles over processors
- * based on their coordinates in the "dimension" direction.
- */
-                                  
-int mdrunner(int nthreads_requested, 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,
-            int nstepout, int resetstep, int nmultisim, int repl_ex_nst,
-             int repl_ex_seed, real pforce,real cpt_period,real max_hours,
-            const char *deviceOptions, unsigned long Flags);
-/* Driver routine, that calls the different methods */
-
-void md_print_warning(const t_commrec *cr,FILE *fplog,const char *buf);
-/* Print a warning message to stderr on the master node
- * and to fplog if fplog!=NULL.
- */
-
-void init_md(FILE *fplog,
-                   t_commrec *cr,t_inputrec *ir, const output_env_t oenv, 
-                   double *t,double *t0,
-                   real *lambda,double *lam0,
-                   t_nrnb *nrnb,gmx_mtop_t *mtop,
-                   gmx_update_t *upd,
-                   int nfile,const t_filenm fnm[],
-                   gmx_mdoutf_t **outf,t_mdebin **mdebin,
-                   tensor force_vir,tensor shake_vir,
-                   rvec mu_tot,
-                   gmx_bool *bSimAnn,t_vcm **vcm, 
-                   t_state *state, unsigned long Flags);
-  /* Routine in sim_util.c */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _mdrun_h */
diff --git a/include/mpelogging.h b/include/mpelogging.h
deleted file mode 100644 (file)
index 5a5bea6..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * 
- *                This source code is part of
- * 
- *                 G   R   O   M   A   C   S
- * 
- *          GROningen MAchine for Chemical Simulations
- * 
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
- * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
- * Copyright (c) 2001-2008, The GROMACS development team,
- * check out http://www.gromacs.org for more information.
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- * 
- * If you want to redistribute modifications, please consider that
- * scientific software is very special. Version control is crucial -
- * bugs must be traceable. We will be happy to consider code for
- * inclusion in the official distribution, but derived work must not
- * be called official GROMACS. Details are found in the README & COPYING
- * files - if they are missing, get the official version at www.gromacs.org.
- * 
- * To help us fund GROMACS development, we humbly ask that you cite
- * the papers on the package - you can find them in the top README file.
- * 
- * For more info, check our website at http://www.gromacs.org
- * 
- * And Hey:
- * Gallium Rubidium Oxygen Manganese Argon Carbon Silicon
- */
-
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* define USE_MPE if you want MPE logging 
- *
- * you then need to link with the appropriate libraries
- * that come with the mpich distribution (can be found in the
- * mpe subdirectory */
-/* #define USE_MPE */
-
-/* define BARRIERS if you want to have extra MPI_Barriers
- * in the code which might help analyzing the MPE logfiles 
- */
-/* #define BARRIERS */
-#ifdef BARRIERS
-#define GMX_BARRIER(communicator) MPI_Barrier(communicator)
-#else
-#define GMX_BARRIER(communicator)
-#endif
-
-#ifdef USE_MPE
-#define GMX_MPE_LOG(event) MPE_Log_event(event, 0, "")
-#else
-#define GMX_MPE_LOG(event)
-#endif
-
-#ifdef USE_MPE
-#include <mpe.h>
-     /* Define MPE logging events here */
-     /* General events */
-     int ev_timestep1,               ev_timestep2;
-     int ev_ns_start,                ev_ns_finish;
-     int ev_calc_bonds_start,        ev_calc_bonds_finish;
-     int ev_send_coordinates_start,  ev_send_coordinates_finish;
-     int ev_update_fr_start,         ev_update_fr_finish;
-     int ev_clear_rvecs_start,       ev_clear_rvecs_finish;
-     int ev_output_start,            ev_output_finish;
-     int ev_update_start,            ev_update_finish;     
-     int ev_force_start,             ev_force_finish;
-     int ev_do_fnbf_start,           ev_do_fnbf_finish;
-     
-     /* Shift related events*/
-     int ev_shift_start,             ev_shift_finish;     
-     int ev_unshift_start,           ev_unshift_finish;     
-     int ev_mk_mshift_start,         ev_mk_mshift_finish;
-     
-     /* PME related events */
-     int ev_pme_start,               ev_pme_finish;
-     int ev_spread_on_grid_start,    ev_spread_on_grid_finish;
-     int ev_sum_qgrid_start,         ev_sum_qgrid_finish;
-     int ev_gmxfft3d_start,          ev_gmxfft3d_finish;
-     int ev_solve_pme_start,         ev_solve_pme_finish;
-     int ev_gather_f_bsplines_start, ev_gather_f_bsplines_finish;
-     int ev_reduce_start,            ev_reduce_finish;
-     int ev_rscatter_start,          ev_rscatter_finish;
-     int ev_alltoall_start,          ev_alltoall_finish;
-     int ev_pmeredist_start,         ev_pmeredist_finish;
-     int ev_init_pme_start,          ev_init_pme_finish;
-     int ev_global_stat_start,       ev_global_stat_finish;
-     int ev_sum_lrforces_start,      ev_sum_lrforces_finish;
-     int ev_virial_start,            ev_virial_finish;
-     int ev_sort_start,              ev_sort_finish;
-     int ev_sum_qgrid_start,         ev_sum_qgrid_finish;
-     
-     /* Essential dynamics related events */
-     int ev_edsam_start,             ev_edsam_finish;
-     int ev_get_group_x_start,       ev_get_group_x_finish;
-     int ev_ed_apply_cons_start,     ev_ed_apply_cons_finish;
-     int ev_fit_to_reference_start,  ev_fit_to_reference_finish;
-#endif
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/include/names.h b/include/names.h
deleted file mode 100644 (file)
index a396bda..0000000
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * 
- *                This source code is part of
- * 
- *                 G   R   O   M   A   C   S
- * 
- *          GROningen MAchine for Chemical Simulations
- * 
- *                        VERSION 3.2.0
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
- * 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.
-
- * 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:
- * Gromacs Runs On Most of All Computer Systems
- */
-
-#ifndef _names_h
-#define _names_h
-
-
-#include "typedefs.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* All string arrays are NULL terminated, and therefore have an
- * extra argument (the +1)
- * these should correspond to names.c and include/types/enums.h
- */
-extern const char *epbc_names[epbcNR+1];
-extern const char *etcoupl_names[etcNR+1];
-extern const char *epcoupl_names[epcNR+1];
-extern const char *epcoupltype_names[epctNR+1];
-extern const char *erefscaling_names[erscNR+1];
-extern const char *ens_names[ensNR+1];
-extern const char *ei_names[eiNR+1];
-extern const char *yesno_names[BOOL_NR+1];
-extern const char *bool_names[BOOL_NR+1];
-extern const char *eel_names[eelNR+1];
-extern const char *eewg_names[eewgNR+1];
-extern const char *evdw_names[evdwNR+1];
-extern const char *econstr_names[econtNR+1];
-extern const char *ptype_str[eptNR+1];
-extern const char *egrp_nm[egNR+1];
-extern const char *edisre_names[edrNR+1];
-extern const char *edisreweighting_names[edrwNR+1];
-extern const char *enbf_names[eNBF_NR+1];
-extern const char *ecomb_names[eCOMB_NR+1];
-extern const char *gtypes[egcNR+1];
-extern const char *efep_names[efepNR+1];
-extern const char *separate_dhdl_file_names[efepNR+1];
-extern const char *dhdl_derivatives_names[efepNR+1];
-extern const char *efep_names[efepNR+1];
-extern const char *esol_names[esolNR+1];
-extern const char *enlist_names[enlistNR+1];
-extern const char *edispc_names[edispcNR+1];
-extern const char *ecm_names[ecmNR+1];
-extern const char *eann_names[eannNR+1];
-extern const char *egb_names[egbNR+1];
-extern const char *eis_names[eisNR+1];
-extern const char *esa_names[esaNR+1];
-extern const char *ewt_names[ewtNR+1];
-extern const char *epull_names[epullNR+1];
-extern const char *epullg_names[epullgNR+1];
-extern const char *eQMmethod_names[eQMmethodNR+1];
-extern const char *eQMbasis_names[eQMbasisNR+1];
-extern const char *eQMMMscheme_names[eQMMMschemeNR+1];
-extern const char *eMultentOpt_names[eMultentOptNR+1];
-
-#define        UNDEFINED               "UNDEFINED"
-#define ENUM_NAME(e,max,names) ((((e)<0)||((e)>=(max)))?UNDEFINED:(names)[e])
-
-#define BOOL(e)        ENUM_NAME(e,BOOL_NR,bool_names)
-#define ENS(e)         ENUM_NAME(e,ensNR,ens_names)
-#define EI(e)          ENUM_NAME(e,eiNR,ei_names)
-#define EPBC(e)        ENUM_NAME(e,epbcNR,epbc_names)
-#define ETCOUPLTYPE(e) ENUM_NAME(e,etcNR,etcoupl_names)
-#define EPCOUPLTYPE(e) ENUM_NAME(e,epcNR,epcoupl_names)
-#define EPCOUPLTYPETYPE(e) ENUM_NAME(e,epctNR,epcoupltype_names)
-#define EREFSCALINGTYPE(e) ENUM_NAME(e,erscNR,erefscaling_names)
-#define EBLOCKS(e)     ENUM_NAME(e,ebNR,eblock_names)
-#define EPARAM(e)      ENUM_NAME(e,epNR,eparam_names)
-#define EELTYPE(e)     ENUM_NAME(e,eelNR,eel_names)
-#define EVDWTYPE(e)    ENUM_NAME(e,evdwNR,evdw_names)
-#define ECONSTRTYPE(e) ENUM_NAME(e,econtNR,econstr_names)
-#define EDISRETYPE(e)  ENUM_NAME(e,edrNR,edisre_names)
-#define EDISREWEIGHTING(e)  ENUM_NAME(e,edrwNR,edisreweighting_names)
-#define ENBFNAME(e)    ENUM_NAME(e,eNBF_NR,enbf_names)
-#define ECOMBNAME(e)   ENUM_NAME(e,eCOMB_NR,ecomb_names)
-#define EFEPTYPE(e)    ENUM_NAME(e,efepNR,efep_names)
-#define SEPDHDLFILETYPE(e) ENUM_NAME(e,sepdhdlfileNR,separate_dhdl_file_names)
-#define DHDLDERIVATIVESTYPE(e) ENUM_NAME(e,dhdlderivativesNR,dhdl_derivatives_names)
-#define ESOLTYPE(e)    ENUM_NAME(e,esolNR,esol_names)
-#define ENLISTTYPE(e)  ENUM_NAME(e,enlistNR,enlist_names)
-#define EDISPCORR(e)   ENUM_NAME(e,edispcNR,edispc_names)
-#define ECOM(e)        ENUM_NAME(e,ecmNR,ecm_names)
-#define EANNEAL(e)      ENUM_NAME(e,eannNR,eann_names)
-#define EGBALGORITHM(e) ENUM_NAME(e,egbNR,egb_names)
-#define ESAALGORITHM(e) ENUM_NAME(e,esaNR,esa_names)
-#define EIMPLICITSOL(e) ENUM_NAME(e,eisNR,eis_names)
-#define EWALLTYPE(e)   ENUM_NAME(e,ewtNR,ewt_names)
-#define EPULLTYPE(e)   ENUM_NAME(e,epullNR,epull_names)
-#define EPULLGEOM(e)   ENUM_NAME(e,epullgNR,epullg_names)
-#define EQMMETHOD(e)   ENUM_NAME(e,eQMmethodNR,eQMmethod_names)
-#define EQMBASIS(e)    ENUM_NAME(e,eQMbasisNR,eQMbasis_names)
-#define EQMMMSCHEME(e) ENUM_NAME(e,eQMMMschemeNR,eQMMMscheme_names)
-#define EMULTENTOPT(e) ENUM_NAME(e,eMultentOptNR,eMultentOpt_names)
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _names_h */
diff --git a/include/nbsearch.h b/include/nbsearch.h
deleted file mode 100644 (file)
index 5dd7352..0000000
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- *
- *                This source code is part of
- *
- *                 G   R   O   M   A   C   S
- *
- *          GROningen MAchine for Chemical Simulations
- *
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
- * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
- * Copyright (c) 2001-2009, The GROMACS development team,
- * check out http://www.gromacs.org for more information.
-
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * If you want to redistribute modifications, please consider that
- * scientific software is very special. Version control is crucial -
- * bugs must be traceable. We will be happy to consider code for
- * inclusion in the official distribution, but derived work must not
- * be called official GROMACS. Details are found in the README & COPYING
- * files - if they are missing, get the official version at www.gromacs.org.
- *
- * To help us fund GROMACS development, we humbly ask that you cite
- * the papers on the package - you can find them in the top README file.
- *
- * For more info, check our website at http://www.gromacs.org
- */
-/*! \file
- * \brief API for neighborhood searching.
- *
- * The API is documented in more detail on a separate page:
- * \ref nbsearch
- *
- * The functions within this file can be used independently of the other parts
- * of the library.
- * The library also uses the functions internally.
- */
-#ifndef NBSEARCH_H
-#define NBSEARCH_H
-
-#include "typedefs.h"
-
-#include "indexutil.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct gmx_ana_pos_t;
-
-/** Data structure for neighborhood searches. */
-typedef struct gmx_ana_nbsearch_t gmx_ana_nbsearch_t;
-
-/** Create a new neighborhood search data structure. */
-int
-gmx_ana_nbsearch_create(gmx_ana_nbsearch_t **d, real cutoff, int maxn);
-/** Free memory allocated for neighborhood search. */
-void
-gmx_ana_nbsearch_free(gmx_ana_nbsearch_t *d);
-
-/** Initializes neighborhood search for a new frame. */
-int
-gmx_ana_nbsearch_init(gmx_ana_nbsearch_t *d, t_pbc *pbc, int n, rvec x[]);
-/** Initializes neighborhood search for a frame using \c gmx_ana_pos_t.  */
-int
-gmx_ana_nbsearch_pos_init(gmx_ana_nbsearch_t *d, t_pbc *pbc,
-                          struct gmx_ana_pos_t *p);
-/** Sets the exclusions for the next neighborhood search. */
-int
-gmx_ana_nbsearch_set_excl(gmx_ana_nbsearch_t *d, int nexcl, int excl[]);
-/** Check whether a point is within a neighborhood. */
-gmx_bool
-gmx_ana_nbsearch_is_within(gmx_ana_nbsearch_t *d, rvec x);
-/** Check whether a position is within a neighborhood. */
-gmx_bool
-gmx_ana_nbsearch_pos_is_within(gmx_ana_nbsearch_t *d,
-                               struct gmx_ana_pos_t *p, int i);
-/** Calculates the minimun distance from the reference points. */
-real
-gmx_ana_nbsearch_mindist(gmx_ana_nbsearch_t *d, rvec x);
-/** Calculates the minimun distance from the reference points. */
-real
-gmx_ana_nbsearch_pos_mindist(gmx_ana_nbsearch_t *d,
-                             struct gmx_ana_pos_t *p, int i);
-/** Finds the first reference position within the cutoff. */
-gmx_bool
-gmx_ana_nbsearch_first_within(gmx_ana_nbsearch_t *d, rvec x, int *jp);
-/** Finds the first reference position within the cutoff. */
-gmx_bool
-gmx_ana_nbsearch_pos_first_within(gmx_ana_nbsearch_t *d,
-                                  struct gmx_ana_pos_t *p, int i, int *jp);
-/** Finds the next reference position within the cutoff. */
-gmx_bool
-gmx_ana_nbsearch_next_within(gmx_ana_nbsearch_t *d, int *jp);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/include/physics.h b/include/physics.h
deleted file mode 100644 (file)
index e72608c..0000000
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * 
- *                This source code is part of
- * 
- *                 G   R   O   M   A   C   S
- * 
- *          GROningen MAchine for Chemical Simulations
- * 
- *                        VERSION 3.2.0
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
- * 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.
-
- * 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:
- * Gromacs Runs On Most of All Computer Systems
- */
-
-#ifndef _physics_h
-#define _physics_h
-
-/*
- * Physical constants to be used in Gromacs.
- * No constants (apart from 0, 1 or 2) should
- * be anywhere else in the code.
- */
-
-#include <math.h>
-
-/* we do it anyway. */
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifndef M_PI
-#ifdef _PI
-#define M_PI _PI
-#else
-#define M_PI        3.14159265358979323846
-#endif
-#endif
-
-#define ANGSTROM        (1e-10)                /* Old...       */
-#define KILO            (1e3)                  /* Thousand     */
-#define NANO            (1e-9)                 /* A Number     */
-#define PICO            (1e-12)                /* A Number     */
-#define A2NM            (ANGSTROM/NANO)        /* NANO         */
-#define NM2A            (NANO/ANGSTROM)        /* 10.0         */
-#define RAD2DEG                 (180.0/M_PI)           /* Conversion   */
-#define DEG2RAD                 (M_PI/180.0)           /* id           */
-#define CAL2JOULE       (4.184)                /* id           */
-#define E_CHARGE         (1.60217733e-19)      /* Coulomb      */
-
-#define AMU              (1.6605402e-27)        /* kg           */
-#define BOLTZMANN       (1.380658e-23)         /* (J/K)        */
-#define AVOGADRO        (6.0221367e23)         /* ()           */
-#define RGAS             (BOLTZMANN*AVOGADRO)   /* (J/(mol K))  */
-#define BOLTZ            (RGAS/KILO)            /* (kJ/(mol K)) */
-#define FARADAY          (E_CHARGE*AVOGADRO)    /* (C/mol)      */
-#define ELECTRONVOLT     (E_CHARGE*AVOGADRO/KILO) /* (kJ/mol)   */     
-#define PLANCK1          (6.6262e-34)           /* J s */
-#define PLANCK           (6.6262e-34*AVOGADRO/(PICO*KILO)) /* (kJ/mol) ps */
-
-#define EPSILON0        (5.72765E-4)           /* (e^2 / Na (kJ nm))     
-                                                  == (e^2 mol/(kJ nm)) */
-                                                
-#define SPEED_OF_LIGHT   (2.9979245800E05)      /* nm/ps                */
-#define ATOMICMASS_keV   (940000.0)             /* Atomic mass in keV   */
-#define ELECTRONMASS_keV (512.0)                /* Electron mas in keV  */
-
-/* Improved accuracy (PL & EL, 20090421) */
-#define FACEL           (332.0636930*CAL2JOULE)/* (10 * (ONE_4PI_EPS0)) */
-#define ONE_4PI_EPS0    (FACEL*0.1)            /* 1/(4*pi*e0)*/
-#define PRESFAC           (16.6054)             /* bar / pressure unity */
-#define ENM2DEBYE         48.0321               /* Convert electron nm  *
-                                                * to debye             */
-#define DEBYE2ENM         0.02081941
-/* to convert from a acceleration in (e V)/(amu nm) */
-/* FIELDFAC is also Faraday's constant and E_CHARGE/(1e6 AMU) */
-#define FIELDFAC          (FARADAY/KILO)
-
-/* to convert AU to MD units: */
-#define HARTREE2KJ        4.3597482e-21
-#define BOHR2NM           0.0529177249
-#define HARTREE_BOHR2MD   (HARTREE2KJ*AVOGADRO/BOHR2NM)
-
-
-/* The four basic units */
-#define unit_length   "nm"
-#define unit_time     "ps"
-#define unit_mass     "u"
-#define unit_energy   "kJ/mol"
-
-/* Temperature unit, T in this unit times BOLTZ give energy in unit_energy */
-#define unit_temp_K   "K"
-
-/* Charge unit, electron charge, involves ONE_4PI_EPS0 */
-#define unit_charge_e "e"
-
-/* Pressure unit, pressure in basic units times PRESFAC gives this unit */
-#define unit_pres_bar "bar"
-
-/* Dipole unit, debye, conversion from the unit_charge_e involves ENM2DEBYE */
-#define unit_dipole_D "D"
-
-/* Derived units from basic units only */
-#define unit_vel      unit_length "/" unit_time
-#define unit_volume   unit_length "^3"
-#define unit_invtime  "1/" unit_time
-
-/* Other derived units */
-#define unit_surft_bar unit_pres_bar " " unit_length
-
-/* SI units, conversion from basic units involves NANO, PICO and AMU */
-#define unit_length_SI  "m"
-#define unit_time_SI    "s"
-#define unit_mass_SI    "kg"
-
-#define unit_density_SI unit_mass_SI "/" unit_length_SI "^3"
-#define unit_invvisc_SI unit_length_SI " " unit_time_SI "/" unit_mass_SI
-
-#ifdef __cplusplus
-}
-#endif
-
-
-#endif /* _physics_h */
-
-
diff --git a/include/poscalc.h b/include/poscalc.h
deleted file mode 100644 (file)
index aaac183..0000000
+++ /dev/null
@@ -1,192 +0,0 @@
-/*
- *
- *                This source code is part of
- *
- *                 G   R   O   M   A   C   S
- *
- *          GROningen MAchine for Chemical Simulations
- *
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
- * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
- * Copyright (c) 2001-2009, The GROMACS development team,
- * check out http://www.gromacs.org for more information.
-
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * If you want to redistribute modifications, please consider that
- * scientific software is very special. Version control is crucial -
- * bugs must be traceable. We will be happy to consider code for
- * inclusion in the official distribution, but derived work must not
- * be called official GROMACS. Details are found in the README & COPYING
- * files - if they are missing, get the official version at www.gromacs.org.
- *
- * To help us fund GROMACS development, we humbly ask that you cite
- * the papers on the package - you can find them in the top README file.
- *
- * For more info, check our website at http://www.gromacs.org
- */
-/*! \file
- * \brief API for structured and optimized calculation of positions.
- *
- * The functions in this header are used internally by the analysis library
- * to calculate positions.
- * They can also be used in user code, but in most cases there should be no
- * need. Instead, one should write an analysis tool such that it gets all
- * positions through selections.
- *
- * \internal
- *
- * The API is documented in more detail on a separate page:
- * \ref poscalcengine.
- */
-#ifndef POSCALC_H
-#define POSCALC_H
-
-#include "typedefs.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*! \name Flags for position calculation.
- * \anchor poscalc_flags
- */
-/*@{*/
-/*! \brief
- * Use mass weighting.
- *
- * If this flag is set, the positions will be calculated using mass weighting,
- * i.e., one gets center-of-mass positions.
- * Without the flag, center-of-geometry positions are calculated.
- * Does not have any effect if the calculation type is \ref POS_ATOM.
- */
-#define POS_MASS        1
-/*! \brief
- * Calculate positions for the same atoms in residues/molecules.
- *
- * If this flag is set, the positions are always calculated using the same
- * atoms for each residue/molecule, even if the evaluation group contains only
- * some of the atoms for some frames.
- * The group passed to gmx_ana_poscalc_set_maxindex() is used to determine
- * the atoms to use for the calculation.
- *
- * Has no effect unless \ref POS_DYNAMIC is set or if the calculation type
- * is not \ref POS_RES of \ref POS_MOL.
- */
-#define POS_COMPLMAX    2
-/*! \brief
- * Calculate positions for whole residues/molecules.
- *
- * If this flag is set, the positions will be calculated for whole
- * residues/molecules, even if the group contains only some of the atoms in
- * the residue/molecule.
- *
- * Has no effect unless the calculation type is \ref POS_RES or \ref POS_MOL.
- */
-#define POS_COMPLWHOLE  4
-/*! \brief
- * Enable handling of changing calculation groups.
- *
- * Can be used for static calculations as well, but implies a small
- * performance penalty.
- */
-#define POS_DYNAMIC     16
-/*! \brief
- * Update \c gmx_ana_pos_t::m dynamically for an otherwise static
- * calculation.
- *
- * Has effect only if \ref POS_DYNAMIC is not set.
- */
-#define POS_MASKONLY    32
-/*! \brief
- * Calculate velocities of the positions.
- */
-#define POS_VELOCITIES  64
-/*! \brief
- * Calculate forces on the positions.
- */
-#define POS_FORCES      128
-/*@}*/
-
-/** Specifies the type of positions to be calculated. */
-typedef enum
-{
-    POS_ATOM,    /**< Copy atomic coordinates. */
-    POS_RES,     /**< Calculate center for each residue. */
-    POS_MOL,     /**< Calculate center for each molecule. */
-    POS_ALL,     /**< Calculate center for the whole group. */
-    POS_ALL_PBC  /**< Calculate center for the whole group with PBC. */
-} e_poscalc_t;
-
-/** Collection of \c gmx_ana_poscalc_t structures for the same topology. */
-typedef struct gmx_ana_poscalc_coll_t gmx_ana_poscalc_coll_t;
-/** Data structure for position calculation. */
-typedef struct gmx_ana_poscalc_t gmx_ana_poscalc_t;
-
-struct gmx_ana_index_t;
-struct gmx_ana_pos_t;
-
-/** Converts a string to parameters for gmx_ana_poscalc_create(). */
-int
-gmx_ana_poscalc_type_from_enum(const char *post, e_poscalc_t *type, int *flags);
-/** Creates a list of strings for position enum parameter handling. */
-const char **
-gmx_ana_poscalc_create_type_enum(gmx_bool bAtom);
-
-/** Creates a new position calculation collection object. */
-int
-gmx_ana_poscalc_coll_create(gmx_ana_poscalc_coll_t **pccp);
-/** Sets the topology for a position calculation collection. */
-void
-gmx_ana_poscalc_coll_set_topology(gmx_ana_poscalc_coll_t *pcc, t_topology *top);
-/** Frees memory allocated for a position calculation collection. */
-void
-gmx_ana_poscalc_coll_free(gmx_ana_poscalc_coll_t *pcc);
-/** Prints information about calculations in a position calculation collection. */
-void
-gmx_ana_poscalc_coll_print_tree(FILE *fp, gmx_ana_poscalc_coll_t *pcc);
-
-/** Creates a new position calculation. */
-int
-gmx_ana_poscalc_create(gmx_ana_poscalc_t **pcp, gmx_ana_poscalc_coll_t *pcc,
-                       e_poscalc_t type, int flags);
-/** Creates a new position calculation based on an enum value. */
-int
-gmx_ana_poscalc_create_enum(gmx_ana_poscalc_t **pcp, gmx_ana_poscalc_coll_t *pcc,
-                            const char *post, int flags);
-/** Sets the flags for position calculation. */
-void
-gmx_ana_poscalc_set_flags(gmx_ana_poscalc_t *pc, int flags);
-/** Sets the maximum possible input index group for position calculation. */
-void
-gmx_ana_poscalc_set_maxindex(gmx_ana_poscalc_t *pc, struct gmx_ana_index_t *g);
-/** Initializes positions for position calculation output. */
-void
-gmx_ana_poscalc_init_pos(gmx_ana_poscalc_t *pc, struct gmx_ana_pos_t *p);
-/** Frees the memory allocated for position calculation. */
-void
-gmx_ana_poscalc_free(gmx_ana_poscalc_t *pc);
-/** Returns TRUE if the position calculation requires topology information. */
-gmx_bool
-gmx_ana_poscalc_requires_top(gmx_ana_poscalc_t *pc);
-
-/** Initializes evaluation for a position calculation collection. */
-void
-gmx_ana_poscalc_init_eval(gmx_ana_poscalc_coll_t *pcc);
-/** Initializes a position calculation collection for a new frame. */
-void
-gmx_ana_poscalc_init_frame(gmx_ana_poscalc_coll_t *pcc);
-/** Updates a single COM/COG structure for a frame. */
-void
-gmx_ana_poscalc_update(gmx_ana_poscalc_t *pc,
-                       struct gmx_ana_pos_t *p, struct gmx_ana_index_t *g,
-                       t_trxframe *fr, t_pbc *pbc);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/include/position.h b/include/position.h
deleted file mode 100644 (file)
index 4e27d51..0000000
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- *
- *                This source code is part of
- *
- *                 G   R   O   M   A   C   S
- *
- *          GROningen MAchine for Chemical Simulations
- *
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
- * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
- * Copyright (c) 2001-2009, The GROMACS development team,
- * check out http://www.gromacs.org for more information.
-
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * If you want to redistribute modifications, please consider that
- * scientific software is very special. Version control is crucial -
- * bugs must be traceable. We will be happy to consider code for
- * inclusion in the official distribution, but derived work must not
- * be called official GROMACS. Details are found in the README & COPYING
- * files - if they are missing, get the official version at www.gromacs.org.
- *
- * To help us fund GROMACS development, we humbly ask that you cite
- * the papers on the package - you can find them in the top README file.
- *
- * For more info, check our website at http://www.gromacs.org
- */
-/*! \file
- * \brief API for handling positions.
- */
-#ifndef POSITION_H
-#define POSITION_H
-
-#include "typedefs.h"
-
-#include "indexutil.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*! \brief
- * Stores a set of positions together with their origins.
- */
-typedef struct gmx_ana_pos_t
-{
-    /*! \brief
-     * Number of positions.
-     */
-    int                 nr;
-    /*! \brief
-     * Array of positions.
-     */
-    rvec               *x;
-    /*! \brief
-     * Velocities (can be NULL).
-     */
-    rvec               *v;
-    /*! \brief
-     * Forces (can be NULL).
-     */
-    rvec               *f;
-    /*! \brief
-     * Mapping of the current positions to the original group.
-     *
-     * \see gmx_ana_indexmap_t
-     */
-    gmx_ana_indexmap_t  m;
-    /*! \brief
-     * Pointer to the current evaluation group.
-     */
-    gmx_ana_index_t    *g;
-    /*! \brief
-     * Number of elements allocated for \c x.
-     */
-    int                 nalloc_x;
-} gmx_ana_pos_t;
-
-/** Initializes an empty position structure. */
-void
-gmx_ana_pos_clear(gmx_ana_pos_t *pos);
-/** Ensures that enough memory has been allocated to store positions. */
-void
-gmx_ana_pos_reserve(gmx_ana_pos_t *pos, int n, int isize);
-/** Request memory allocation for velocities. */
-void
-gmx_ana_pos_reserve_velocities(gmx_ana_pos_t *pos);
-/** Request memory allocation for forces. */
-void
-gmx_ana_pos_reserve_forces(gmx_ana_pos_t *pos);
-/** Initializes a \c gmx_ana_pos_t to represent a constant position. */
-void
-gmx_ana_pos_init_const(gmx_ana_pos_t *pos, rvec x);
-/** Frees the memory allocated for position storage. */
-void
-gmx_ana_pos_deinit(gmx_ana_pos_t *pos);
-/** Frees the memory allocated for positions. */
-void
-gmx_ana_pos_free(gmx_ana_pos_t *pos);
-/** Copies the evaluated positions to a preallocated data structure. */
-void
-gmx_ana_pos_copy(gmx_ana_pos_t *dest, gmx_ana_pos_t *src, gmx_bool bFirst);
-
-/** Sets the number of positions in a position structure. */
-void
-gmx_ana_pos_set_nr(gmx_ana_pos_t *pos, int n);
-/** Sets the evaluation group of a position data structure. */
-void
-gmx_ana_pos_set_evalgrp(gmx_ana_pos_t *pos, gmx_ana_index_t *g);
-/** Empties a position data structure with full initialization. */
-void
-gmx_ana_pos_empty_init(gmx_ana_pos_t *pos);
-/** Empties a position data structure. */
-void
-gmx_ana_pos_empty(gmx_ana_pos_t *pos);
-/** Appends a position to a preallocated data structure with full
- * initialization. */
-void
-gmx_ana_pos_append_init(gmx_ana_pos_t *dest, gmx_ana_index_t *g,
-                        gmx_ana_pos_t *src, int i);
-/** Appends a position to a preallocated data structure. */
-void
-gmx_ana_pos_append(gmx_ana_pos_t *dest, gmx_ana_index_t *g,
-                   gmx_ana_pos_t *src, int i, int refid);
-/** Updates position data structure state after appends. */
-void
-gmx_ana_pos_append_finish(gmx_ana_pos_t *pos);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/include/selection.h b/include/selection.h
deleted file mode 100644 (file)
index 0b2fbe8..0000000
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
- *
- *                This source code is part of
- *
- *                 G   R   O   M   A   C   S
- *
- *          GROningen MAchine for Chemical Simulations
- *
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
- * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
- * Copyright (c) 2001-2009, The GROMACS development team,
- * check out http://www.gromacs.org for more information.
-
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * If you want to redistribute modifications, please consider that
- * scientific software is very special. Version control is crucial -
- * bugs must be traceable. We will be happy to consider code for
- * inclusion in the official distribution, but derived work must not
- * be called official GROMACS. Details are found in the README & COPYING
- * files - if they are missing, get the official version at www.gromacs.org.
- *
- * To help us fund GROMACS development, we humbly ask that you cite
- * the papers on the package - you can find them in the top README file.
- *
- * For more info, check our website at http://www.gromacs.org
- */
-/*! \file
- * \brief API for handling selection (the \c gmx_ana_selection_t structure and related functions).
- *
- * There should be no need to use the data structures or call the
- * functions in this file directly unless using the selection routines outside
- * the main trajectory analysis API.
- */
-#ifndef SELECTION_H
-#define SELECTION_H
-
-#include "position.h"
-#include "indexutil.h"
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif
-
-/** Information for a collection of selections. */
-typedef struct gmx_ana_selcollection_t gmx_ana_selcollection_t;
-
-struct gmx_ana_poscalc_coll_t;
-
-/** Defines the type of covered fraction. */
-typedef enum
-{
-    CFRAC_NONE,         /**< No covered fraction (everything covered). */
-    CFRAC_SOLIDANGLE    /**< Fraction of a solid (3D) angle covered. */
-} e_coverfrac_t;
-
-/*! \brief
- * Describes a single selection.
- */
-typedef struct gmx_ana_selection_t
-{
-    /** Name of the selection. */
-    char                   *name;
-    /** The actual selection string. */
-    char                   *selstr;
-    /** Selected positions. */
-    gmx_ana_pos_t           p;
-    /** Masses associated with the positions. */
-    real                   *m;
-    /** Charges associated with the positions. */
-    real                   *q;
-    /** Pointer to the index group that holds the selected atoms. */
-    struct gmx_ana_index_t *g;
-    /** TRUE if the value can change as a function of time. */
-    gmx_bool                    bDynamic;
-    /** Type of the covered fraction. */
-    e_coverfrac_t           cfractype;
-    /** TRUE if the covered fraction depends on the frame. */
-    gmx_bool                    bCFracDyn;
-    /** Covered fraction of the selection for the current frame. */
-    real                    cfrac;
-    /** The average covered fraction (over the trajectory). */
-    real                    avecfrac;
-
-    /*! \brief
-     * Pointer to the root of the selection element tree (internal use only).
-     *
-     * \internal
-     * This field is NULL if the selection has been loaded directly from an
-     * index file.
-     */
-    struct t_selelem       *selelem;
-    /** Original masses of all possible positions (internal use only). */
-    real                   *orgm;
-    /** Original charges of all possible positions (internal use only). */
-    real                   *orgq;
-} gmx_ana_selection_t;
-
-/** Frees the memory allocated for a selection. */
-void
-gmx_ana_selection_free(gmx_ana_selection_t *sel);
-/** Returns the name of a selection. */
-char *
-gmx_ana_selection_name(gmx_ana_selection_t *sel);
-/** Prints out the selection information. */
-void
-gmx_ana_selection_print_info(gmx_ana_selection_t *sel);
-/** Initializes the information for covered fraction. */
-gmx_bool
-gmx_ana_selection_init_coverfrac(gmx_ana_selection_t *sel, e_coverfrac_t type);
-
-/** Creates a new empty selection collection. */
-int
-gmx_ana_selcollection_create(gmx_ana_selcollection_t **sc,
-                             struct gmx_ana_poscalc_coll_t *pcc);
-/** Frees the memory allocated for a selection collection. */
-void
-gmx_ana_selcollection_free(gmx_ana_selcollection_t *sc);
-/** Sets the default reference position handling for a selection collection. */
-void
-gmx_ana_selcollection_set_refpostype(gmx_ana_selcollection_t *sc, const char *type);
-/** Sets the default output position handling for a selection collection. */
-void
-gmx_ana_selcollection_set_outpostype(gmx_ana_selcollection_t *sc,
-                                     const char *type, gmx_bool bMaskOnly);
-/** Request evaluation of velocities for selections. */
-void
-gmx_ana_selcollection_set_veloutput(gmx_ana_selcollection_t *sc,
-                                    gmx_bool bVelOut);
-/** Request evaluation of forces for selections. */
-void
-gmx_ana_selcollection_set_forceoutput(gmx_ana_selcollection_t *sc,
-                                      gmx_bool bForceOut);
-/** Sets the topology for a selection collection. */
-int
-gmx_ana_selcollection_set_topology(gmx_ana_selcollection_t *sc, t_topology *top,
-                                   int natoms);
-/** Returns the number of selections specified by a selection collection. */
-int
-gmx_ana_selcollection_get_count(gmx_ana_selcollection_t *sc);
-/** Returns a selection by index. */
-gmx_ana_selection_t *
-gmx_ana_selcollection_get_selection(gmx_ana_selcollection_t *sc, int i);
-/** Returns TRUE if the collection requires topology information for evaluation. */
-gmx_bool
-gmx_ana_selcollection_requires_top(gmx_ana_selcollection_t *sc);
-/** Prints a human-readable version of the internal selection element tree. */
-void
-gmx_ana_selcollection_print_tree(FILE *fp, gmx_ana_selcollection_t *sc, gmx_bool bValues);
-/** Prints the selection strings into an XVGR file as comments. */
-void
-xvgr_selcollection(FILE *fp, gmx_ana_selcollection_t *sc, 
-                   const output_env_t oenv);
-
-/* In parsetree.c */
-/** Parses selection(s) from standard input. */
-int
-gmx_ana_selcollection_parse_stdin(gmx_ana_selcollection_t *sc, int nr,
-                                  gmx_ana_indexgrps_t *grps,
-                                  gmx_bool bInteractive);
-/** Parses selection(s) from a file. */
-int
-gmx_ana_selcollection_parse_file(gmx_ana_selcollection_t *sc, const char *fnm,
-                                  gmx_ana_indexgrps_t *grps);
-/** Parses selection(s) from a string. */
-int
-gmx_ana_selcollection_parse_str(gmx_ana_selcollection_t *sc, const char *str,
-                                gmx_ana_indexgrps_t *grps);
-
-/* In compiler.c */
-/** Set debugging flag for selection compilation. */
-void
-gmx_ana_selcollection_set_compile_debug(gmx_ana_selcollection_t *sc, gmx_bool bDebug);
-/** Prepares the selections for evaluation and performs some optimizations. */
-int
-gmx_ana_selcollection_compile(gmx_ana_selcollection_t *sc);
-
-/* In evaluate.c */
-/** Evaluates the selection. */
-int
-gmx_ana_selcollection_evaluate(gmx_ana_selcollection_t *sc,
-                               t_trxframe *fr, t_pbc *pbc);
-/** Evaluates the largest possible index groups from dynamic selections. */
-int
-gmx_ana_selcollection_evaluate_fin(gmx_ana_selcollection_t *sc, int nframes);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/include/selmethod.h b/include/selmethod.h
deleted file mode 100644 (file)
index f47dc37..0000000
+++ /dev/null
@@ -1,665 +0,0 @@
-/*
- *
- *                This source code is part of
- *
- *                 G   R   O   M   A   C   S
- *
- *          GROningen MAchine for Chemical Simulations
- *
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
- * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
- * Copyright (c) 2001-2009, The GROMACS development team,
- * check out http://www.gromacs.org for more information.
-
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * If you want to redistribute modifications, please consider that
- * scientific software is very special. Version control is crucial -
- * bugs must be traceable. We will be happy to consider code for
- * inclusion in the official distribution, but derived work must not
- * be called official GROMACS. Details are found in the README & COPYING
- * files - if they are missing, get the official version at www.gromacs.org.
- *
- * To help us fund GROMACS development, we humbly ask that you cite
- * the papers on the package - you can find them in the top README file.
- *
- * For more info, check our website at http://www.gromacs.org
- */
-/*! \page selmethods Custom selection methods
- *
- * Custom selection methods are defined by creating a new instance of 
- * \c gmx_ana_selmethod_t and filling it with the necessary data for handling
- * the selection.
- * The structure contains callback pointers that define the actual behavior
- * of the method.
- * The following sections discuss how the structure should be filled and how
- * to implement the callbacks.
- *
- *
- * \section selmethods_define \c gmx_ana_selmethod_t data structure
- *
- * An example \c gmx_ana_selmethod_t definition could look like this:
- *
- * \code
- * gmx_ana_selmethod_t sm_example = {
- *   "example", GROUP_VALUE, 0,
- *   asize(sm_params_example), sm_params_example,
- *   &init_data_example,
- *    NULL,
- *   &init_example,
- *    NULL,
- *   &free_data_example,
- *   &init_frame_example,
- *   &evaluate_example,
- *    NULL,
- *   {"example from POS_EXPR [cutoff REAL]", 0, NULL},
- * };
- * \endcode
- *
- * The first value defines the name of the method.
- * It is used mostly for informational purposes; the actual name(s) recognized
- * by the selection parser are defined by the call to
- * gmx_ana_selmethod_register() (see \ref selmethods_register).
- *
- * The second value defines the type of the value the method returns.
- * Possible values are
- *  - \ref NO_VALUE : This is allowed only for methods that have the flag
- *    \ref SMETH_MODIFIER set (see \ref selmethods_modifiers).
- *  - \ref INT_VALUE : The method returns one or more integer values.
- *  - \ref REAL_VALUE : The method returns one or more floating-point values.
- *  - \ref STR_VALUE : The method returns one or more strings.
- *  - \ref POS_VALUE : The method returns one or more 3D vectors.
- *  - \ref GROUP_VALUE : The method returns a single index group.
- *
- * The third value gives additional information about the method using
- * a combination of flags.
- * Possible flags are:
- *  - \ref SMETH_REQTOP : If set, the topology information is always loaded
- *    and the \p top pointer passed to the callbacks is guaranteed to be
- *    non-NULL. Should be set if the method requires topology information
- *    for evaluation.
- *  - \ref SMETH_DYNAMIC : If set, the method can only be evaluated dynamically,
- *    i.e., it requires data from the trajectory frame.
- *  - \ref SMETH_MODIFIER : If set, the method is a selection modifier and
- *    not an actual selection method.
- *    For more details, see \ref selmethods_modifiers.
- *
- * There are two additional flags that specify the number of values the
- * method returns. Only one of them can be set at a time.
- * If neither is set, the default behavior is to evaluate a value for each
- * input atom (except for \ref GROUP_VALUE methods, which always return a
- * single group).
- * Other behaviors can be specified with these flags:
- *  - \ref SMETH_SINGLEVAL : If set, the method evaluates to a single value.
- *    This is automatically set if the type is \ref GROUP_VALUE.
- *  - \ref SMETH_VARNUMVAL : If set, the method evaluates to an arbitrary
- *    number of values.
- *    The number of values is determined based on the values given by the user
- *    to the method parameters (see \ref selmethods_params).
- *  .
- * If either of these flags is specified (and the method type is not
- * \ref GROUP_VALUE), the group passed to the evaluation callback should not
- * be used as it can be NULL.
- * Currently, the above flags only work (have been tested) for \ref POS_VALUE
- * methods.
- *
- * There is one additional flag that can only be specified for \ref STR_VALUE
- * methods: \ref SMETH_CHARVAL . It is meant for to ease implementation of
- * methods that evaluate to strings consisting of single characters.
- *
- * The next two values determine the number of parameters and a pointer to
- * the parameter array. The contents of the parameter array are described in
- * \ref selmethods_params. If the method does not take parameters, the first
- * value should be 0 and the second can be NULL.
- * Currently, \ref STR_VALUE methods cannot take parameters, but this limitation
- * should be easy to lift if required.
- *
- * These are followed by function callbacks that determine the
- * actual behavior of the method. Any of these except the evaluation callback
- * can be NULL (the evaluation callback can also be NULL if \ref NO_VALUE is
- * specified for a selection modifier). However, the presence of parameters
- * can require some of the callbacks to be implemented.
- * The details are described in \ref selmethods_callbacks.
- *
- * Finally, there is a data structure that gives help texts for the method.
- *
- * The \c gmx_ana_selmethod_t variable should be declared as a global variable
- * or it should be otherwise ensured that the structure is not freed: only a
- * pointer to the structure is stored by the library.
- *
- *
- * \section selmethods_params Defining parameters
- *
- * Parameters to selection methods are defined in a separate array of
- * \c gmx_ana_selparam_t structures.
- * The order of the parameters does not matter (except possibly for callback
- * implementation), with one important exception:
- * If the method evaluates to a \ref POS_VALUE, the first parameter should 
- * have \ref GROUP_VALUE and be the one that is used to calculate the
- * positions.
- *
- * An example parameter definition:
- * \code
- * static gmx_ana_selparam_t sm_params_example[] = {
- *   {"cutoff", {REAL_VALUE, 1, {NULL}}, NULL, SPAR_OPTIONAL},
- *   {"from",   {POS_VALUE, -1, {NULL}}, NULL, SPAR_DYNAMIC | SPAR_VARNUM},
- * };
- * \endcode
- *
- * The first value gives the name of the parameter.
- * The first parameter can have a NULL name, which means that the value should
- * immediately follow the method name. This can be used to specify methods
- * of the type 'within 5 of ...'.
- *
- * The second value specifies the type of the value that the parameter accepts.
- * \ref NO_VALUE can be used to specify a boolean parameter, other possibilities
- * are the same as for the selection method type.
- *
- * The third value gives the number of values that the parameter accepts.
- * For boolean parameters (\ref NO_VALUE), it should be 0.
- * For parameters with \ref SPAR_VARNUM of \ref SPAR_ATOMVAL, it should be set
- * to -1 for consistency (it is not used).
- * If \ref SPAR_RANGES is specified, it should be either 1 (to accept a single
- * continuous range) or -1 (if combined with \ref SPAR_VARNUM).
- * In all other cases, it should be a positive integer; in most cases, it
- * should be 1.
- *
- * The nest two pointers should always be NULL (they should be initialized in
- * the callbacks), except the first pointer in the case of \ref SPAR_ENUMVAL
- * (see below).
- *
- * The final value gives additional information about the acceptable values
- * for the parameter using a combination of flags.
- * The possible flags are:
- *  - \ref SPAR_OPTIONAL : If set, the user does not need to provide a value
- *    for the parameter. If not set, an error is reported if the parameter
- *    is not specified by the user.
- *  - \ref SPAR_DYNAMIC : If set, the method can handle dynamic values for
- *    the parameter, i.e., the value(s) can be given by an expression that
- *    evaluates to different values for different frames.
- *  - \ref SPAR_RANGES : Can be set only for \ref INT_VALUE and
- *    \ref REAL_VALUE parameters,
- *    and cannot be combined with \ref SPAR_DYNAMIC.
- *    If set, the parameter accepts ranges of values.
- *    The ranges are automatically sorted and compacted such that a minimum
- *    amount of non-overlapping ranges are given for the method.
- *  - \ref SPAR_VARNUM : If set, the parameter can have a variable number
- *    of values. These can be provided by the user as a list of values, or
- *    using a single \ref SMETH_VARNUMVAL (or a single \ref SMETH_SINGLEVAL)
- *    method.
- *  - \ref SPAR_ATOMVAL : If set, the parameter accepts either a single value
- *    or an expression that evaluates to a value for each input atom.
- *    The single input value is treated as if the same value was returned for
- *    each atom.
- *    Cannot be combined with \ref SPAR_RANGES or \ref SPAR_VARNUM.
- *  - \ref SPAR_ENUMVAL : Can only be set for \ref STR_VALUE parameters that
- *    take a single value, and cannot be combined with any other flag than
- *    \ref SPAR_OPTIONAL. If set, the parameter only accepts one of predefined
- *    string values. See \ref SPAR_ENUMVAL documentation for details on how
- *    to specify the acceptable values.
- *
- *
- * \section selmethods_callbacks Implementing callbacks
- *
- * There are eight differen callback functions that can be implemented for
- * selection methods: sel_datafunc(), sel_posfunc(), sel_initfunc(),
- * sel_outinitfunc(), sel_freefunc(), sel_framefunc(), and two update functions.
- * They are in this order in the \c gmx_ana_selmethod_t data structure.
- * In general, any of the callbacks can be NULL, but the presence of
- * parameters or other callbacks imposes some restrictions:
- *  - sel_datafunc() should be provided if the method takes parameters.
- *  - sel_initfunc() should be provided if the method takes
- *    any parameters with the \ref SPAR_VARNUM or \ref SPAR_ATOMVAL flags,
- *    except if those parameters have a \ref POS_VALUE.
- *  - sel_outinitfunc() should be provided for \ref POS_VALUE methods
- *    and \ref SMETH_VARNUMVAL methods.
- *  - sel_freefunc() should be provided if sel_datafunc() and/or
- *    sel_initfunc() allocate any dynamic memory in addition to the data
- *    structure itself.
- *  - sel_updatefunc_pos() only makes sense for methods with \ref SMETH_DYNAMIC
- *    set.
- *  - At least one update function should be provided unless the method type is
- *    \ref NO_VALUE.
- *
- * The documentations for the function pointer types provide more information
- * about how the callbacks should be implemented.
- *
- *
- * \section selmethods_modifiers Selection modifiers
- *
- * Selection modifiers are a special kind of selection methods that can be
- * appended to the end of a selection. They are specified by adding the
- * \ref SMETH_MODIFIER flag to the \c gmx_ana_selmethod_t.
- * They can have two different types:
- *  - \ref POS_VALUE : These modifiers are given the final positions
- *    as an input, and they can make modifications to the selection that are
- *    not possible otherwise (e.g., permute the atoms).
- *    The modifier should implement sel_updatefunc_pos() and also have
- *    one NULL parameter in the beginning of the parameter list that takes
- *    \ref POS_VALUE and is used to give the input positions.
- *  - \ref NO_VALUE : These modifiers do not modify the final selection, but
- *    can be used to implement per-selection options for analysis tools
- *    or to control the default behavior of the selection engine
- *    (currently, such a framework is not implemented, but should be easy to
- *    implement if required).
- *    
- * In addition to restricting the type of the method, selection modifiers
- * do not allow the flags \ref SMETH_SINGLEVAL and \ref SMETH_VARNUMVAL
- * (they would not make sense).
- *
- * Parameters and callbacks should be implemented as with normal selection
- * method, but beware that very little of the functionality has been tested.
- * 
- * \todo
- * The modifier handling could be made more flexible and more generic;
- * the current implementation does not allow many things which would be
- * possible with slight changes in the internals of the library.
- *
- *
- * \section selmethods_register Registering the method
- *
- * After defining the method with \c gmx_ana_selmethod_t, it should be
- * registered with the selection engine.
- * In analysis programs, this can be done by calling
- * gmx_ana_selmethod_register().
- * If adding the method to the library, you should add a pointer to the new
- * method structure into the \c smtable_def array (in \ref selmethod.c
- * "selmethod.c"), and it is registered automatically.
- * In both cases, gmx_ana_selmethod_register() does several checks on the
- * structure and reports any errors or inconsistencies it finds.
- */
-/*! \file
- * \brief API for handling selection methods.
- *
- * There should be no need to use the data structures or call the
- * functions in this file directly unless implementing a custom selection
- * method.
- *
- * Instructions for implementing custom selection methods can be found
- * on a separate page: \ref selmethods
- */
-#ifndef SELMETHOD_H
-#define SELMETHOD_H
-
-#include "typedefs.h"
-
-#include "indexutil.h"
-#include "selparam.h"
-#include "selvalue.h"
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif
-
-struct gmx_ana_pos_t;
-struct gmx_ana_poscalc_coll_t;
-struct gmx_ana_selcollection_t;
-
-/*! \name Selection method flags
- * \anchor selmethod_flags
- */
-/*@{*/
-/*! \brief
- * If set, the method requires topology information.
- */
-#define SMETH_REQTOP     1
-/*! \brief
- * If set, the method can only be evaluated dynamically.
- */
-#define SMETH_DYNAMIC    2
-/*! \brief
- * If set, the method evaluates to a single value.
- *
- * The default is that the method evaluates to a value for each input atom.
- * Cannot be combined with \ref SMETH_VARNUMVAL.
- */
-#define SMETH_SINGLEVAL  4
-/*! \brief
- * If set, the method evaluates to an arbitrary number of values.
- *
- * The default is that the method evaluates to a value for each input atom.
- * Cannot be combined with \ref SMETH_SINGLEVAL or with \ref GROUP_VALUE.
- */
-#define SMETH_VARNUMVAL  8
-/*! \brief
- * If set, the method evaluates to single-character strings.
- *
- * This flag can only be set for \ref STR_VALUE methods. If it is set, the
- * selection engine automatically allocates and frees the required strings.
- * The evaluation function should store the character values as the first
- * character in the strings in the output data structure and should not change
- * the string pointers.
- */
-#define SMETH_CHARVAL    64
-/*! \brief
- * If set, the method is a selection modifier.
- *
- * The method type should be \ref GROUP_VALUE or \ref NO_VALUE .
- * Cannot be combined with \ref SMETH_SINGLEVAL or \ref SMETH_VARNUMVAL .
- */
-#define SMETH_MODIFIER   256
-/*@}*/
-
-/*! \brief
- * Allocates and initializes internal data and parameter values.
- *
- * \param[in]     npar  Number of parameters in \p param.
- * \param[in,out] param Pointer to (a copy of) the method's
- *   \c gmx_ana_selmethod_t::param.
- * \returns       Pointer to method-specific data structure.
- *   This pointer will be passed as the last parameter of all other function
- *   calls.
- *   Should return NULL on error (only error that should occur is out of
- *   memory).
- *
- * Should allocate and initialize any internal data required by the method.
- * Should also initialize the value pointers (\c gmx_ana_selparam_t::val) in
- * \p param to point to variables within the internal data structure,
- * with the exception of parameters that specify the \ref SPAR_VARNUM or
- * the \ref SPAR_ATOMVAL flag (these should be handled in sel_initfunc()).
- * However, parameters with a position value should be initialized.
- * It is also possible to initialize \ref SPAR_ENUMVAL statically outside
- * this function (see \ref SPAR_ENUMVAL).
- * The \c gmx_ana_selparam_t::nvalptr should also be initialized for
- * non-position-valued parameters that have both \ref SPAR_VARNUM and
- * \ref SPAR_DYNAMIC set (it can also be initialized for other parameters if
- * desired, but the same information will be available through other means).
- * For optional parameters, the default values can (and should) be initialized
- * here, as the parameter values are not changed if the parameter is not
- * provided.
- *
- * For boolean parameters (type equals \ref NO_VALUE), the default value
- * should be set here. The user can override the value by giving the parameter
- * either as 'NAME'/'noNAME', or as 'NAME on/off/yes/no'.
- *
- * If the method takes any parameters, this function must be provided.
- */
-typedef void *(*sel_datafunc)(int npar, gmx_ana_selparam_t *param);
-/*! \brief
- * Sets the position calculation collection for the method.
- *
- * \param[in]  pcc   Position calculation collection that the method should use
- *   for position calculations.
- * \param      data  Internal data structure from sel_datafunc().
- *
- * This function should be provided if the method uses the routines from
- * poscalc.h for calculating positions.
- * The pointer \p pcc should then be stored and used for initialization for
- * any position calculation structures.
- */
-typedef void  (*sel_posfunc)(struct gmx_ana_poscalc_coll_t *pcc, void *data);
-/*! \brief
- * Does initialization based on topology and/or parameter values.
- *
- * \param[in]  top   Topology structure
- *   (can be NULL if \ref SMETH_REQTOP is not set).
- * \param[in]  npar  Number of parameters in \p param.
- * \param[in]  param Pointer to (an initialized copy of) the method's
- *   \c gmx_ana_selmethod_t::param.
- * \param      data  Internal data structure from sel_datafunc().
- * \returns    0 on success, a non-zero error code on failure.
- *
- * This function is called after the parameters have been processed:
- * the values of the parameters are stored at the locations set in
- * sel_datafunc().
- * The flags \ref SPAR_DYNAMIC and \ref SPAR_ATOMVAL are cleared before
- * calling the function if the value is static or single-valued, respectively.
- * If a parameter had the \ref SPAR_VARNUM or \ref SPAR_ATOMVAL flag (and
- * is not \ref POS_VALUE), a pointer to the memory allocated for the values is
- * found in \c gmx_ana_selparam_t::val.
- * The pointer should be stored by this function, otherwise the values
- * cannot be accessed.
- * For \ref SPAR_VARNUM parameters, the number of values can be accessed
- * through \c gmx_ana_selparam_t::val. For parameters with \ref SPAR_DYNAMIC,
- * the number is the maximum number of values (the actual number can be
- * accessed in sel_framefunc() and in the update callback through the value
- * pointed by \c gmx_ana_selparam_t::nvalptr).
- * For \ref SPAR_ATOMVAL parameters, \c gmx_ana_selparam_t::val::nr is set to
- * 1 if a single value was provided, otherwise it is set to the maximum number
- * of values possibly passed to the method.
- * The value pointed by \c gmx_ana_selparam_t::nvalptr always contains the same
- * value as \c gmx_ana_selparam_t::val::nr.
- *
- * For dynamic \ref GROUP_VALUE parameters (\ref SPAR_DYNAMIC set), the value
- * will be the largest possible selection that may occur during the
- * evaluation. For other types of dynamic parameters, the values are
- * undefined.
- *
- * If the method takes any parameters with the \ref SPAR_VARNUM or
- * \ref SPAR_ATOMVAL flags, this function must be provided, except if these
- * parameters all have \ref POS_VALUE.
- *
- * This function may be called multiple times for the same method if the
- * method takes parameters with \ref SPAR_ATOMVAL set.
- */
-typedef int   (*sel_initfunc)(t_topology *top, int npar,
-                              gmx_ana_selparam_t *param, void *data);
-/*! \brief
- * Initializes output data structure.
- *
- * \param[in]     top   Topology structure
- *   (can be NULL if \ref SMETH_REQTOP is not set).
- * \param[in,out] out   Output data structure.
- * \param[in]     data  Internal data structure from sel_datafunc().
- * \returns       0 on success, an error code on error.
- *
- * This function is called immediately after sel_initfunc().
- *
- * If the method evaluates to a position (\ref POS_VALUE), this function
- * should be provided, and it should initialize the \c gmx_ana_pos_t data
- * structure pointed by \p out.p (the pointer is guaranteed to be non-NULL).
- * The \p out.p->g pointer should be initialized to the group that is used
- * to evaluate positions in sel_updatefunc() or sel_updatefunc_pos().
- *
- * The function should also be provided for non-position-valued
- * \ref SMETH_VARNUMVAL methods. For these methods, it suffices to set the
- * \p out->nr field to reflect the maximum number of values returned by the
- * method.
- *
- * Currently, this function is not needed for other types of methods.
- *
- * This function may be called multiple times for the same method if the
- * method takes parameters with \ref SPAR_ATOMVAL set.
- */
-typedef int   (*sel_outinitfunc)(t_topology *top, gmx_ana_selvalue_t *out,
-                                 void *data);
-/*! \brief
- * Frees the internal data.
- *
- * \param[in] data Internal data structure from sel_datafunc().
- *
- * This function should be provided if the internal data structure contains
- * dynamically allocated data, and should free any such data.
- * The data structure itself should not be freed; this is handled automatically.
- * If there is no dynamically allocated data within the structure,
- * this function is not needed.
- * Any memory pointers received as values of parameters are managed externally,
- * and should not be freed.
- * Pointers set as the value pointer of \ref SPAR_ENUMVAL parameters should not
- * be freed.
- */
-typedef void  (*sel_freefunc)(void *data);
-
-/*! \brief
- * Initializes the evaluation for a new frame.
- *
- * \param[in]  top  Topology structure
- *   (can be NULL if \ref SMETH_REQTOP is not set).
- * \param[in]  fr   Current frame.
- * \param[in]  pbc  Initialized periodic boundary condition structure,
- *   or NULL if PBC should not be used.
- * \param      data Internal data structure from sel_datafunc().
- * \returns    0 on success, a non-zero error code on failure.
- *
- * This function should be implemented if the selection method needs to
- * do some preprocessing for each frame, and the preprocessing does not
- * depend on the evaluation group.
- * Because \p sel_updatefunc_* can be called more than once for a frame,
- * it is inefficient do the preprocessing there.
- * It is ensured that this function will be called before
- * \p sel_updatefunc_* for each frame, and that it will be called at most
- * once for each frame.
- * For static methods, it is called once, with \p fr and \p pbc set to
- * NULL.
- */
-typedef int   (*sel_framefunc)(t_topology *top, t_trxframe *fr, t_pbc *pbc,
-                               void *data);
-/*! \brief
- * Evaluates a selection method.
- *
- * \param[in]  top  Topology structure
- *   (can be NULL if \ref SMETH_REQTOP is not set).
- * \param[in]  fr   Current frame.
- * \param[in]  pbc  Initialized periodic boundary condition structure,
- *   or NULL if PBC should not be used.
- * \param[in]  g    Index group for which the method should be evaluated.
- * \param[out] out  Output data structure.
- * \param      data Internal data structure from sel_datafunc().
- * \returns    0 on success, a non-zero error code on error.
- *
- * This function should evaluate the method for each atom included in \p g,
- * and write the output to \p out. The pointer in the union \p out->u that
- * corresponds to the type of the method should be used.
- * Enough memory has been allocated to store the output values.
- * The number of values in \p out should also be updated if necessary.
- * However, \ref POS_VALUE or \ref GROUP_VALUE methods should not touch
- * \p out->nr (it should be 1 anyways).
- *
- * For \ref STR_VALUE methods, the pointers stored in \p out->s are discarded
- * without freeing; it is the responsibility of this function to provide
- * pointers that can be discarded without memory leaks.
- */
-typedef int   (*sel_updatefunc)(t_topology *top, t_trxframe *fr, t_pbc *pbc,
-                                gmx_ana_index_t *g, gmx_ana_selvalue_t *out,
-                                void *data);
-/*! \brief
- * Evaluates a selection method using positions.
- *
- * \param[in]  top  Topology structure
- *   (can be NULL if \ref SMETH_REQTOP is not set).
- * \param[in]  fr   Current frame.
- * \param[in]  pbc  Initialized periodic boundary condition structure,
- *   or NULL if PBC should not be used.
- * \param[in]  pos  Positions for which the method should be evaluated.
- * \param[out] out  Output data structure.
- * \param      data Internal data structure from sel_datafunc().
- * \returns    0 on success, a non-zero error code on error.
- *
- * This function should evaluate the method for each position in \p g,
- * and write the output values to \p out. The pointer in the union \p out->u
- * that corresponds to the type of the method should be used.
- * Enough memory has been allocated to store the output values.
- * The number of values in \p out should also be updated if necessary.
- * However, \ref POS_VALUE or \ref GROUP_VALUE methods should not touch
- * \p out->nr (it should be 1 anyways).
- *
- * For \ref STR_VALUE methods, the pointers stored in \p out->s are discarded
- * without freeing; it is the responsibility of this function to provide
- * pointers that can be discarded without memory leaks.
- */
-typedef int   (*sel_updatefunc_pos)(t_topology *top, t_trxframe *fr, t_pbc *pbc,
-                                    struct gmx_ana_pos_t *pos,
-                                    gmx_ana_selvalue_t *out,
-                                    void *data);
-
-/*! \brief
- * Help information for a selection method.
- *
- * If some information is not available, the corresponding field can be set to
- * 0/NULL.
- */
-typedef struct gmx_ana_selmethod_help_t
-{
-    /*! \brief
-     * One-line description of the syntax of the method.
-     *
-     * If NULL, the name of the method is used.
-     */
-    const char         *syntax;
-    /*! \brief
-     * Number of strings in \p help.
-     *
-     * Set to 0 if \p help is NULL.
-     */
-    int                 nlhelp;
-    /*! \brief
-     * Detailed help for the method.
-     *
-     * If there is no help available in addition to \p syntax, this can be set
-     * to NULL.
-     */
-    const char        **help;
-} gmx_ana_selmethod_help_t;
-
-/*! \brief
- * Describes a selection method.
- *
- * Any of the function pointers except the update call can be NULL if the
- * operation is not required or not supported. In this case,
- * corresponding function calls are skipped.
- *
- * See the function pointer type documentation for details of how the
- * functions should be implemented.
- * More details on implementing new selection methods can be found on a 
- * separate page: \ref selmethods.
- */
-typedef struct gmx_ana_selmethod_t
-{
-    /** Name of the method. */
-    const char         *name;
-    /** Type which the method returns. */
-    e_selvalue_t        type;
-    /*! \brief
-     * Flags to specify how the method should be handled.
-     *
-     * See \ref selmethod_flags for allowed values.
-     */
-    int                 flags;
-    /** Number of parameters the method takes. */
-    int                 nparams;
-    /** Pointer to the array of parameter descriptions. */
-    gmx_ana_selparam_t *param;
-
-    /** Function for allocating and initializing internal data and parameters. */
-    sel_datafunc        init_data;
-    /** Function to set the position calculation collection. */
-    sel_posfunc         set_poscoll;
-    /** Function to do initialization based on topology and/or parameter values. */
-    sel_initfunc        init;
-    /** Function to initialize output data structure. */
-    sel_outinitfunc     outinit;
-    /** Function to free the internal data. */
-    sel_freefunc        free;
-
-    /** Function to initialize the calculation for a new frame. */
-    sel_framefunc       init_frame;
-    /** Function to evaluate the value. */
-    sel_updatefunc      update;
-    /** Function to evaluate the value using positions. */
-    sel_updatefunc_pos  pupdate;
-
-    /** Help data for the method. */
-    gmx_ana_selmethod_help_t help;
-} gmx_ana_selmethod_t;
-
-/** Registers a selection method. */
-int
-gmx_ana_selmethod_register(struct gmx_ana_selcollection_t *sc,
-                           const char *name, gmx_ana_selmethod_t *method);
-/** Registers all selection methods in the library. */
-int
-gmx_ana_selmethod_register_defaults(struct gmx_ana_selcollection_t *sc);
-
-/** Finds a parameter from a selection method by name. */
-gmx_ana_selparam_t *
-gmx_ana_selmethod_find_param(const char *name, gmx_ana_selmethod_t *method);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/include/selparam.h b/include/selparam.h
deleted file mode 100644 (file)
index a10b609..0000000
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
- *
- *                This source code is part of
- *
- *                 G   R   O   M   A   C   S
- *
- *          GROningen MAchine for Chemical Simulations
- *
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
- * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
- * Copyright (c) 2001-2009, The GROMACS development team,
- * check out http://www.gromacs.org for more information.
-
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * If you want to redistribute modifications, please consider that
- * scientific software is very special. Version control is crucial -
- * bugs must be traceable. We will be happy to consider code for
- * inclusion in the official distribution, but derived work must not
- * be called official GROMACS. Details are found in the README & COPYING
- * files - if they are missing, get the official version at www.gromacs.org.
- *
- * To help us fund GROMACS development, we humbly ask that you cite
- * the papers on the package - you can find them in the top README file.
- *
- * For more info, check our website at http://www.gromacs.org
- */
-/*! \file
- * \brief API for handling parameters used in selections.
- *
- * There should be no need to use the data structures or call the
- * functions in this file directly unless implementing a custom selection
- * method.
- *
- * More details can be found on the page discussing
- * \ref selmethods "custom selection methods".
- */
-#ifndef SELPARAM_H
-#define SELPARAM_H
-
-#include "typedefs.h"
-
-#include "indexutil.h"
-#include "selvalue.h"
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif
-
-/*! \name Parameter flags
- * \anchor selparam_flags
- */
-/*@{*/
-/*! \brief
- * This flag is set if the user has provided the parameter.
- *
- * This flag is set automatically, and should not be set by the user.
- */
-#define SPAR_SET      1
-/*! \brief
- * If not set, an error is reported if the parameter is not specified by the
- * user.
- */
-#define SPAR_OPTIONAL 2
-/*! \brief
- * If set, the parameter value can be dynamic, i.e., be different for
- * different frames.
- *
- * If set, the parameter value should only be accessed in the update function
- * of \c gmx_ana_selmethod_t.
- * The flag is cleared before sel_initfunc() if the value provided is actually
- * static.
- */
-#define SPAR_DYNAMIC  4
-/*! \brief
- * If set, the parameter value is parsed into sorted ranges.
- *
- * Can only be specified for integer parameters.
- * If specified, the value of the parameter (\c gmx_ana_selparam_t::val)
- * consists of sets of two integers, each specifying a range.
- * The values give the endpoints of the ranges (inclusive).
- * The ranges are sorted and overlapping/continuous ranges are merged into
- * a single range to minimize the number of ranges.
- *
- * If this flag is specified, \c gmx_ana_selparam_t::nval gives the number of
- * ranges. \p gmx_ana_selparam_t::nval should be 1 or \ref SPAR_VARNUM should be
- * specified; other values would lead to unpredictable behavior.
- */
-#define SPAR_RANGES   8
-/*! \brief
- * If set, the parameter can have any number of values.
- *
- * If specified, the data pointer in \c gmx_ana_selparam_t::val should be NULL;
- * the memory is allocated by the parameter parser.
- * The implementation of the method should ensure that the pointer to the
- * allocated memory is stored somewhere in sel_initfunc();
- * otherwise, the memory is lost.
- *
- * The initial value of \c gmx_ana_selparam_t::nval is not used with this flag.
- * Instead, it will give the number of actual values provided by the user
- * after the parameters have been parsed.
- * For consistency, it should be initialized to -1.
- *
- * Cannot be combined with \ref GROUP_VALUE parameters.
- */
-#define SPAR_VARNUM   16
-/*! \brief
- * If set, the parameter can have a separate value for each atom.
- *
- * The flag is cleared before sel_initfunc() if the value provided is actually
- * a single value.
- *
- * Cannot be combined with \ref POS_VALUE or \ref GROUP_VALUE parameters.
- */
-#define SPAR_ATOMVAL  32
-/*! \brief
- * If set, the parameter takes one of a set of predefined strings.
- *
- * Can only be specified for a \ref STR_VALUE parameter that takes a single
- * string.
- * The data pointer in \c gmx_ana_selparam_t::val should be initialized into an
- * array of strings such that the first and last elements are NULL, and the
- * rest give the possible values. For optional values, the second element in
- * the array should give the default value. The string given by the user is
- * matched against the beginnings of the given strings, and if a unique match
- * is found, the first pointer in the array will be initialized to point to
- * the matching string.
- * The data pointer can be initialized as a static array; duplication of the
- * array for multiple instances of the same method is automatically taken care
- * of.
- */
-#define SPAR_ENUMVAL  128
-/*@}*/
-
-/*! \brief
- * Describes a single parameter for a selection method.
- */
-typedef struct gmx_ana_selparam_t
-{
-    /** Name of the parameter. */
-    const char         *name;
-    /*! \brief
-     * The parameter value.
-     *
-     * Type \ref NO_VALUE can be used to define a boolean parameter.
-     * The number of values should be 0 for boolean parameters.
-     *
-     * The value pointer be initialized to NULL in the definition of a
-     * \c gmx_ana_selmethod_t and initialized in the
-     * \c gmx_ana_selmethod_t::init_data call
-     * (see sel_datafunc()).
-     * However, if \ref SPAR_VARNUM is provided and the parameter is not
-     * \ref POS_VALUE, this field should not be initialized. Instead,
-     * sufficient memory is allocated automatically and the pointer should be
-     * stored in \c gmx_ana_selmethod_t::init
-     * (see sel_initfunc()).
-     *
-     * The values cannot be accessed outside these two functions: the compiler
-     * makes a copy of the parameter structure for each instance of the
-     * method, and the original parameter array is not changed.
-     */
-    gmx_ana_selvalue_t  val;
-    /*! \brief
-     * Pointer to store the number of values.
-     *
-     * If not NULL, the number of values for the parameter is stored in the
-     * pointed value.
-     * Should be specified if \ref SPAR_VARNUM and \ref SPAR_DYNAMIC are both
-     * set.
-     *
-     * Should be initialized to NULL in the definition a \c gmx_ana_selmethod_t
-     * and initialized in sel_datafunc().
-     */
-    int                *nvalptr;
-    /*! \brief
-     * Flags that alter the way the parameter is parsed/handled.
-     *
-     * See \ref selparam_flags for allowed values.
-     */
-    int                 flags;
-} gmx_ana_selparam_t;
-
-/** Finds a parameter from an array by name. */
-gmx_ana_selparam_t *
-gmx_ana_selparam_find(const char *name, int nparam, gmx_ana_selparam_t *param);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/include/selvalue.h b/include/selvalue.h
deleted file mode 100644 (file)
index 8460fe8..0000000
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- *
- *                This source code is part of
- *
- *                 G   R   O   M   A   C   S
- *
- *          GROningen MAchine for Chemical Simulations
- *
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
- * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
- * Copyright (c) 2001-2009, The GROMACS development team,
- * check out http://www.gromacs.org for more information.
-
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * If you want to redistribute modifications, please consider that
- * scientific software is very special. Version control is crucial -
- * bugs must be traceable. We will be happy to consider code for
- * inclusion in the official distribution, but derived work must not
- * be called official GROMACS. Details are found in the README & COPYING
- * files - if they are missing, get the official version at www.gromacs.org.
- *
- * To help us fund GROMACS development, we humbly ask that you cite
- * the papers on the package - you can find them in the top README file.
- *
- * For more info, check our website at http://www.gromacs.org
- */
-/*! \file
- * \brief Declaration of \c gmx_ana_selvalue_t.
- *
- * There should be no need to use the data structures in this file directly
- * unless implementing a custom selection routine.
- */
-#ifndef SELVALUE_H
-#define SELVALUE_H
-
-#include "types/simple.h"
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif
-
-/** Defines the value type of a different selection objects. */
-typedef enum
-{
-    NO_VALUE,           /**< No value; either an error condition or an gmx_boolean 
-                             parameter. */
-    INT_VALUE,          /**< One or more integer values. */
-    REAL_VALUE,         /**< One or more real values. */
-    STR_VALUE,          /**< One or more string values. */
-    POS_VALUE,          /**< One or more position values. */
-    GROUP_VALUE         /**< One group of atoms. */
-} e_selvalue_t;
-
-/*! \brief
- * Describes a value of a selection expression or of a selection method
- * parameter.
- *
- * Which field in the union is used depends on the \p type.
- */
-typedef struct gmx_ana_selvalue_t
-{
-    /** Type of the value. */
-    e_selvalue_t                type;
-    /*! \brief
-     * Number of values in the array pointed by the union.
-     *
-     * Note that for position and group values, it is the number of
-     * data structures in the array, not the number of positions or
-     * the number of atoms in the group.
-     */
-    int                         nr;
-    /** Pointer to the value. */
-    union {
-        /*! \brief
-         * Generic pointer for operations that do not need type information.
-         *
-         * Needs to be the first member to be able to use initialized arrays.
-         */
-        void                   *ptr;
-        /** Integer value(s) (type \ref INT_VALUE). */
-        int                    *i;
-        /** Real value(s) (type \ref REAL_VALUE). */
-        real                   *r;
-        /** String value(s) (type \ref STR_VALUE). */
-        char                  **s;
-        /** Structure for the position value(s) (type \ref POS_VALUE). */
-        struct gmx_ana_pos_t   *p;
-        /** Group value (type \ref GROUP_VALUE). */
-        struct gmx_ana_index_t *g;
-        /** Boolean value (only parameters of type \ref NO_VALUE); */
-        gmx_bool                   *b;
-    }                           u;
-    /*! \brief
-     * Number of elements allocated for the value array.
-     */
-    int                         nalloc;
-} gmx_ana_selvalue_t;
-
-/** Initializes an empty selection value structure. */
-void
-_gmx_selvalue_clear(gmx_ana_selvalue_t *val);
-/** Reserve memory for storing selection values. */
-int
-_gmx_selvalue_reserve(gmx_ana_selvalue_t *val, int n);
-/** Sets the memory for storing selection values. */
-int
-_gmx_selvalue_setstore(gmx_ana_selvalue_t *val, void *ptr);
-/** Sets the memory for storing selection values and marks it for automatic freeing. */
-int
-_gmx_selvalue_setstore_alloc(gmx_ana_selvalue_t *val, void *ptr, int nalloc);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/include/string2.h b/include/string2.h
deleted file mode 100644 (file)
index 184c822..0000000
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * 
- *                This source code is part of
- * 
- *                 G   R   O   M   A   C   S
- * 
- *          GROningen MAchine for Chemical Simulations
- * 
- *                        VERSION 3.2.0
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
- * 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.
-
- * 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:
- * Gromacs Runs On Most of All Computer Systems
- */
-/*! \file
- * \brief Generic string handling functions.
- */
-#ifndef _string2_h
-#define _string2_h
-
-/*
- *
- * string2.h
- * David van der Spoel
- *
- */
-
-
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <ctype.h>
-#include <time.h>
-#include <errno.h>
-
-/*#include "typedefs.h"*/
-#include "types/simple.h"
-
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define CONTINUE    '\\'
-#define COMMENTSIGN ';'
-
-int continuing(char *s);
-
-char *fgets2(char *s, int n, FILE *stream);
-
-void strip_comment (char *line);
-
-int break_line (char *line,
-                      char *variable,
-                      char *value);
-
-void upstring (char *str);
-
-void ltrim (char *str);
-
-void rtrim (char *str);
-
-void trim (char *str);
-
-void nice_header (FILE *out,const char *fn);
-
-int gmx_strcasecmp_min(const char *str1, const char *str2);
-int gmx_strncasecmp_min(const char *str1, const char *str2, int n);
-/* This funny version of strcasecmp, is not only case-insensitive,
- * but also ignores '-' and '_'.
- */
-
-int gmx_strcasecmp(const char *str1, const char *str2);
-int gmx_strncasecmp(const char *str1, const char *str2, int n);
-
-char *gmx_strdup(const char *src);
-char *gmx_strndup(const char *src, int n);
-    
-/** Pattern matcing with wildcards. */
-int gmx_wcmatch(const char *pattern, const char *src);
-
-/** Return value for gmx_wcmatch() when there is no match. */
-#define GMX_NO_WCMATCH 1
-
-
-/* this is our implementation of strsep, the thread-safe replacement for
-   strtok */
-char *gmx_strsep(char **stringp, const char *delim);
-
-
-char *wrap_lines(const char *buf,int line_width, int indent,
-                       gmx_bool bIndentFirst);
-/* wraps lines at 'linewidth', indenting all following
- * lines by 'indent' spaces. A temp buffer is allocated and returned,
- * which can be disposed of if no longer needed.
- * If !bIndentFirst, then the first line will not be indented, only 
- * the lines that are created due to wapping.
- */
-
-
-char **split(char sep,char *str);
-/* Implementation of the well-known Perl function split */
-
-gmx_large_int_t str_to_large_int_t(const char *str, char **endptr);
-
-#if ((defined WIN32 || defined _WIN32 || defined WIN64 || defined _WIN64) && !defined __CYGWIN__ && !defined __CYGWIN32__)
-#define snprintf _snprintf
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _string2_h */
diff --git a/include/thread_mpi/CMakeLists.txt b/include/thread_mpi/CMakeLists.txt
deleted file mode 100644 (file)
index a14e8ad..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-# includes: Nothing to build, just installation
-install(DIRECTORY . DESTINATION include/thread_mpi
-
-        PATTERN "Makefile*" EXCLUDE
-        PATTERN "CMake*" EXCLUDE
-        PATTERN "cmake*" EXCLUDE
-        PATTERN "*~" EXCLUDE
-)
-
-
diff --git a/include/thread_mpi/Makefile.am b/include/thread_mpi/Makefile.am
deleted file mode 100644 (file)
index bd95011..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-# Process this file with automake to produce Makefile.in
-#
-# Don't edit - this file is generated automatically from Makefile.am
-#
-
-SUBDIRS = atomic
-
-pkgincludethread_mpidir = ${pkgincludedir}/thread_mpi
-
-pkgincludethread_mpi_HEADERS = \
-       atomic.h       event.h        lock.h         tmpi.h \
-       barrier.h      hwinfo.h       mpi_bindings.h wait.h \
-       collective.h   list.h         threads.h
-
-
diff --git a/include/thread_mpi/atomic/CMakeLists.txt b/include/thread_mpi/atomic/CMakeLists.txt
deleted file mode 100644 (file)
index 8a54324..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-# includes: Nothing to build, just installation
-install(DIRECTORY . DESTINATION include/thread_mpi/atomic
-
-        PATTERN "Makefile*" EXCLUDE
-        PATTERN "CMake*" EXCLUDE
-        PATTERN "cmake*" EXCLUDE
-        PATTERN "*~" EXCLUDE
-)
-
-
diff --git a/include/thread_mpi/atomic/Makefile.am b/include/thread_mpi/atomic/Makefile.am
deleted file mode 100644 (file)
index ca1292b..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-# Process this file with automake to produce Makefile.in
-#
-# Don't edit - this file is generated automatically from Makefile.am
-#
-
-pkgincludethread_mpidir = ${pkgincludedir}/thread_mpi/atomic
-
-pkgincludethread_mpi_HEADERS = \
-       cycles.h         gcc_intrinsics.h gcc_x86.h\
-       gcc.h            gcc_ppc.h        msvc.h\
-       gcc_ia64.h       gcc_spinlock.h   xlc_ppc.h
-
diff --git a/include/trajana.h b/include/trajana.h
deleted file mode 100644 (file)
index 8000a81..0000000
+++ /dev/null
@@ -1,297 +0,0 @@
-/*
- *
- *                This source code is part of
- *
- *                 G   R   O   M   A   C   S
- *
- *          GROningen MAchine for Chemical Simulations
- *
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
- * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
- * Copyright (c) 2001-2009, The GROMACS development team,
- * check out http://www.gromacs.org for more information.
-
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * If you want to redistribute modifications, please consider that
- * scientific software is very special. Version control is crucial -
- * bugs must be traceable. We will be happy to consider code for
- * inclusion in the official distribution, but derived work must not
- * be called official GROMACS. Details are found in the README & COPYING
- * files - if they are missing, get the official version at www.gromacs.org.
- *
- * To help us fund GROMACS development, we humbly ask that you cite
- * the papers on the package - you can find them in the top README file.
- *
- * For more info, check our website at http://www.gromacs.org
- */
-/*! \file
- * \brief Main API of the trajectory analysis library.
- *
- * Contains the API for the core analysis library.
- *
- * \todo
- * Better handling of reference groups.
- * It would be nice to be able to provide a string that would be used in
- * prompting the groups, and also in automatic reporting of what the tool
- * is about to do.
- *
- * Most analysis tools should include trajana.h
- * (which automatically includes indexutil.h, selection.h, position.h)
- * and possibly one or more of the following headers:
- * displacement.h, histogram.h, nbsearch.h.
- * If the tool implements custom selection methods, it should also include
- * selmethod.h (which automatically includes selparam.h and selvalue.h).
- *
- * Other headers (centerofmass.h, poscalc.h) are used internally by the
- * library to calculate positions.
- * Analysis tools should preferably not use the routines in these headers
- * directly, but instead get all positions through selections. This makes
- * them more flexible with a minimal amount of work.
- */
-#ifndef TRAJANA_H
-#define TRAJANA_H
-
-#include "typedefs.h"
-#include "filenm.h"
-#include "readinp.h"
-
-#include "indexutil.h"
-#include "selection.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/** Data structure for trajectory analysis tools. */
-typedef struct gmx_ana_traj_t gmx_ana_traj_t;
-
-/*! \name Flags for gmx_ana_traj_create()
- * \anchor analysis_flags
- * These flags can be used to alter the behavior of the analysis library to
- * suit the analysis tool.
- * They are given to the gmx_ana_traj_create() when creating the 
- * \c gmx_ana_traj_t data structure, and affect the behavior of the other
- * functions in this header.
- */
-/*@{*/
-/*! \brief
- * Force loading of a topology file.
- *
- * If this flag is not specified, the topology file is loaded only if it is
- * provided on the command line explicitly.
- *
- * \see gmx_ana_get_topology()
- */
-#define ANA_REQUIRE_TOP      (1<<0)
-/*! \brief
- * Do no free the coordinates loaded from the topology.
- *
- * If this flag is specified, the coordinates loaded from the topology can
- * be accessed with gmx_ana_get_topconf().
- *
- * \see gmx_ana_get_topconf()
- */
-#define ANA_USE_TOPX         (1<<1)
-/*! \brief
- * Disallows the user from changing PBC handling.
- *
- * If this option is not specified, the analysis program (see gmx_analysisfunc())
- * may be passed a NULL PBC structure, and it should be able to handle such a
- * situation.
- */
-#define ANA_NOUSER_PBC       (1<<4)
-/*! \brief
- * Disallows the user from changing PBC removal.
- */
-#define ANA_NOUSER_RMPBC     (1<<5)
-/*! \brief
- * Disallows dynamic selections.
- *
- * If this flag is specified, an error is reported if the user specifies
- * any dynamic selections.
- */
-#define ANA_NO_DYNSEL        (1<<8)
-/*! \brief
- * Disallows breaking of residues in dynamic selections.
- *
- * Makes it impossible for the user to select atom-based dynamic selections.
- *
- * Only has effect if \ref ANA_NO_DYNSEL is not specified.
- */
-#define ANA_REQUIRE_WHOLE    (1<<9)
-/*! \brief
- * Disables automatic initialization of selection groups.
- *
- * If this flag is specified, parse_trjana_args() does not call
- * gmx_ana_init_selections(), allowing the program to do some initialization
- * before the call.
- * In particular, the program can use gmx_ana_set_nrefgprs() and
- * gmx_ana_set_nanagrps() before calling gmx_ana_init_selections() to
- * control the number of selections to expect.
- * This is useful if the program requires a different number of index groups
- * with different command-line arguments.
- * If the flag is specified, the program should call gmx_ana_init_selections()
- * exactly once after the parse_trjana_args() call.
- */
-#define ANA_USER_SELINIT     (1<<10)
-/*! \brief
- * Allow only atomic positions to be selected.
- *
- * Note that this flag only applies to the analysis groups, not the reference
- * groups. The reference groups should be checked in the analysis program
- * if some limitations are imposed on them.
- */
-#define ANA_ONLY_ATOMPOS     (1<<11)
-/*! \brief
- * Use masks in the positions to convey dynamic information.
- *
- * If this flag is specified, the positions calculated for the selections
- * are calculated always for the same group of atoms, even if the selection is
- * dynamic.
- * Dynamic selections only affect the \p refid field of the indexgroup map
- * given in the positions.
- */
-#define ANA_USE_POSMASK      (1<<12)
-/*! \brief
- * Pass the reference groups to gmx_analysisfunc().
- *
- * If this flag is specified, the reference groups are passed on to
- * gmx_analysisfunc().
- * Similarly, the arrays returned by gmx_ana_get_anagrps() and
- * gmx_ana_get_grpnames() contain the reference groups in the beginning.
- */
-#define ANA_USE_FULLGRPS     (1<<13)
-/*! \brief
- * Dump the parsed and compiled selection trees.
- *
- * This flag is used by internal debugging tools to make
- * gmx_ana_init_selections() dump the selection trees to stderr.
- */
-#define ANA_DEBUG_SELECTION  (1<<16)
-/*@}*/
-
-
-/*! \name Functions for initialization */
-/*@{*/
-
-/** Allocates and initializes data structure for trajectory analysis. */
-int
-gmx_ana_traj_create(gmx_ana_traj_t **data, unsigned long flags);
-/** Frees the memory allocated for trajectory analysis data. */
-void
-gmx_ana_traj_free(gmx_ana_traj_t *d);
-/** Sets additional flags after gmx_ana_traj_create() has been called. */
-int
-gmx_ana_add_flags(gmx_ana_traj_t *d, unsigned long flags);
-/** Sets the number of reference groups required. */
-int
-gmx_ana_set_nrefgrps(gmx_ana_traj_t *d, int nrefgrps);
-/** Sets the number of analysis groups required. */
-int
-gmx_ana_set_nanagrps(gmx_ana_traj_t *d, int nanagrps);
-/** Sets whether PBC are used. */
-int
-gmx_ana_set_pbc(gmx_ana_traj_t *d, gmx_bool bPBC);
-/** Sets whether molecules are made whole. */
-int
-gmx_ana_set_rmpbc(gmx_ana_traj_t *d, gmx_bool bRmPBC);
-/** Sets flags that determine what to read from the trajectory. */
-int
-gmx_ana_set_frflags(gmx_ana_traj_t *d, int frflags);
-/** Parses command-line arguments and performs some initialization. */
-int
-parse_trjana_args(gmx_ana_traj_t *d, int *argc, char *argv[],
-                  unsigned long pca_flags, int nfile, t_filenm fnm[],
-                  int npargs, t_pargs *pa,
-                 int ndesc, const char **desc,
-                  int nbugs, const char **bugs,
-                  output_env_t *oenv);
-/** Initializes selection information. */
-int
-gmx_ana_init_selections(gmx_ana_traj_t *d);
-/** Initializes calculation of covered fractions for selections. */
-int
-gmx_ana_init_coverfrac(gmx_ana_traj_t *d, e_coverfrac_t type);
-
-/** Returns whether PBC should be used. */
-gmx_bool
-gmx_ana_has_pbc(gmx_ana_traj_t *d);
-/** Gets the topology information. */
-int
-gmx_ana_get_topology(gmx_ana_traj_t *d, gmx_bool bReq, t_topology **top, gmx_bool *bTop);
-/** Gets the configuration from the topology. */
-int
-gmx_ana_get_topconf(gmx_ana_traj_t *d, rvec **x, matrix box, int *ePBC);
-/** Gets the first frame to be analyzed. */
-int
-gmx_ana_get_first_frame(gmx_ana_traj_t *d, t_trxframe **fr);
-
-/** Gets the total number of selections provided by the user. */
-int
-gmx_ana_get_ngrps(gmx_ana_traj_t *d, int *ngrps);
-/** Gets the number of analysis groups provided by the user. */
-int
-gmx_ana_get_nanagrps(gmx_ana_traj_t *d, int *nanagrps);
-/** Gets the selection object for a reference selection. */
-int
-gmx_ana_get_refsel(gmx_ana_traj_t *d, int i, gmx_ana_selection_t **sel);
-/** Gets the selection object for a reference selection. */
-int
-gmx_ana_get_anagrps(gmx_ana_traj_t *d, gmx_ana_selection_t ***sel);
-/** Gets an array of names for the selections. */
-int
-gmx_ana_get_grpnames(gmx_ana_traj_t *d, char ***grpnames);
-/** Gets the selection collection object that contains all the selections. */
-int
-gmx_ana_get_selcollection(gmx_ana_traj_t *d, gmx_ana_selcollection_t **sc);
-/** Prints the selection strings into an XVGR file as comments. */
-int
-xvgr_selections(FILE *out, gmx_ana_traj_t *d);
-
-/*@}*/
-
-
-/*! \name Functions for reading and analyzing the trajectory
- */
-/*@{*/
-
-/*! \brief
- * Function pointer type for frame analysis functions.
- *
- * \param[in] top  Topology structure.
- * \param[in] fr   Current frame.
- * \param[in] pbc  Initialized PBC structure for this frame.
- * \param[in] nr   Number of selections in the \p sel array.
- * \param[in] sel  Array of selections.
- * \param     data User data as provided to gmx_ana_do().
- * \returns   0 on success, a non-zero error code on error.
- *
- * This function is called by gmx_ana_do() for each frame that
- * needs to be analyzed.
- * Positions to be analyzed can be found in the \p sel array.
- * The selection array \p sel also provides information about the atoms that
- * have been used to evaluate the positions.
- * If a non-zero value is returned, gmx_ana_do() immediately exits and returns
- * the same value to the caller.
- */
-typedef int (*gmx_analysisfunc)(t_topology *top, t_trxframe *fr, t_pbc *pbc,
-                               int nr, gmx_ana_selection_t *sel[], void *data);
-
-/** Loops through all frames in the trajectory. */
-int
-gmx_ana_do(gmx_ana_traj_t *d, int flags, gmx_analysisfunc analyze, void *data);
-/** Gets the total number of frames analyzed. */
-int
-gmx_ana_get_nframes(gmx_ana_traj_t *d, int *nframes);
-
-/*@}*/
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/include/types/.cvsignore b/include/types/.cvsignore
deleted file mode 100644 (file)
index b840c21..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-Makefile.in
-Makefile
\ No newline at end of file
diff --git a/include/types/Makefile.am b/include/types/Makefile.am
deleted file mode 100644 (file)
index 99b3f56..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-## Process this file with automake to produce Makefile.in
-#
-# Don't edit - this file is generated automatically from Makefile.am
-#
-pkgincludetypesdir = ${pkgincludedir}/types
-
-pkgincludetypes_HEADERS = \
-       atoms.h         forcerec.h      ifunc.h         oenv.h          \
-       mdatom.h        simple.h        block.h         constr.h        \
-       energy.h        graph.h         inputrec.h      nblist.h        \
-       ns.h            nsgrid.h        symtab.h        commrec.h       \
-       enums.h         group.h         ishift.h        \
-       topology.h      fcdata.h        filenm.h        idef.h          \
-       matrix.h        nrnb.h          trx.h           state.h         \
-       pbc.h           qmmmrec.h       shellfc.h       genborn.h
-
diff --git a/include/types/enums.h b/include/types/enums.h
deleted file mode 100644 (file)
index a12c307..0000000
+++ /dev/null
@@ -1,252 +0,0 @@
-/*
- * 
- *                This source code is part of
- * 
- *                 G   R   O   M   A   C   S
- * 
- *          GROningen MAchine for Chemical Simulations
- * 
- *                        VERSION 3.2.0
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
- * 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.
-
- * 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:
- * GRoups of Organic Molecules in ACtion for Science
- */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* note: these enums should correspond to the names in gmxlib/names.c */
-
-enum {
-  epbcXYZ, epbcNONE, epbcXY, epbcSCREW, epbcNR
-};
-
-enum {
-  etcNO, etcBERENDSEN, etcNOSEHOOVER, etcYES, etcANDERSEN, etcANDERSENINTERVAL, etcVRESCALE, etcNR
-}; /* yes is an alias for berendsen */
-
-enum {
-  epcNO, epcBERENDSEN, epcPARRINELLORAHMAN, epcISOTROPIC, epcMTTK, epcNR
-}; /* isotropic is an alias for berendsen */
-
-/* trotter decomposition extended variable parts */
-enum {
-  etrtNONE, etrtNHC, etrtBAROV, etrtBARONHC, etrtNHC2, etrtBAROV2, etrtBARONHC2, 
-  etrtVELOCITY1, etrtVELOCITY2, etrtPOSITION, etrtSKIPALL, etrtNR
-};
-
-/* sequenced parts of the trotter decomposition */
-enum {
-  ettTSEQ0,  ettTSEQ1,  ettTSEQ2,  ettTSEQ3,  ettTSEQ4, ettTSEQMAX
-};
-
-enum {
-  epctISOTROPIC, epctSEMIISOTROPIC, epctANISOTROPIC,
-  epctSURFACETENSION, epctNR
-};
-
-enum {
-  erscNO, erscALL, erscCOM, erscNR
-};
-
-/*
- * eelNOTUSED1 used to be GB, but to enable generalized born with different
- * forms of electrostatics (RF, switch, etc.) in the future it is now selected
- * separately (through the implicit_solvent option).
- */
-enum {
-  eelCUT,     eelRF,     eelGRF,   eelPME,  eelEWALD,  eelPPPM, 
-  eelPOISSON, eelSWITCH, eelSHIFT, eelUSER, eelGB_NOTUSED, eelRF_NEC, eelENCADSHIFT, 
-  eelPMEUSER, eelPMESWITCH, eelPMEUSERSWITCH, eelRF_ZERO, eelNR
-};
-
-/* Ewald geometry */
-enum { 
-  eewg3D, eewg3DC, eewgNR
-};
-
-#define EEL_RF(e) ((e) == eelRF || (e) == eelGRF || (e) == eelRF_NEC || (e) == eelRF_ZERO )
-
-#define EEL_PME(e)  ((e) == eelPME || (e) == eelPMESWITCH || (e) == eelPMEUSER || (e) == eelPMEUSERSWITCH)
-#define EEL_FULL(e) (EEL_PME(e) || (e) == eelPPPM || (e) == eelPOISSON || (e) == eelEWALD)
-
-#define EEL_SWITCHED(e) ((e) == eelSWITCH || (e) == eelSHIFT || (e) == eelENCADSHIFT || (e) == eelPMESWITCH || (e) == eelPMEUSERSWITCH)
-
-#define EEL_IS_ZERO_AT_CUTOFF(e) (EEL_SWITCHED(e) || (e) == eelRF_ZERO)
-
-#define EEL_MIGHT_BE_ZERO_AT_CUTOFF(e) (EEL_IS_ZERO_AT_CUTOFF(e) || (e) == eelUSER || (e) == eelPMEUSER)
-
-enum {
-  evdwCUT, evdwSWITCH, evdwSHIFT, evdwUSER, evdwENCADSHIFT, evdwNR
-};
-
-#define EVDW_SWITCHED(e) ((e) == evdwSWITCH || (e) == evdwSHIFT || (e) == evdwENCADSHIFT)
-
-#define EVDW_IS_ZERO_AT_CUTOFF(e) EVDW_SWITCHED(e)
-
-#define EVDW_MIGHT_BE_ZERO_AT_CUTOFF(e) (EVDW_IS_ZERO_AT_CUTOFF(e) || (e) == evdwUSER)
-
-enum { 
-  ensGRID, ensSIMPLE, ensNR
-};
-
-/* eiVV is normal velocity verlet -- eiVVAK uses 1/2*(KE(t-dt/2)+KE(t+dt/2)) as the kinetic energy, and the half step kinetic
-   energy for temperature control */
-
-enum {
-  eiMD, eiSteep, eiCG, eiBD, eiSD2, eiNM, eiLBFGS, eiTPI, eiTPIC, eiSD1, eiVV, eiVVAK, eiNR
-};
-#define EI_VV(e) ((e) == eiVV || (e) == eiVVAK)
-#define EI_SD(e) ((e) == eiSD1 || (e) == eiSD2)
-#define EI_RANDOM(e) (EI_SD(e) || (e) == eiBD)
-/*above integrators may not conserve momenta*/
-#define EI_DYNAMICS(e) ((e) == eiMD || EI_SD(e) || (e) == eiBD || EI_VV(e))
-#define EI_ENERGY_MINIMIZATION(e) ((e) == eiSteep || (e) == eiCG || (e) == eiLBFGS)
-#define EI_TPI(e) ((e) == eiTPI || (e) == eiTPIC)
-
-#define EI_STATE_VELOCITY(e) ((e) == eiMD || EI_VV(e) || EI_SD(e))
-
-enum {
-  econtLINCS, econtSHAKE, econtNR
-};
-
-enum {
-  edrNone, edrSimple, edrEnsemble, edrNR
-};
-
-enum {
-  edrwConservative, edrwEqual, edrwNR
-};
-
-/* Combination rule things */
-enum { 
-  eCOMB_NONE, eCOMB_GEOMETRIC, eCOMB_ARITHMETIC, eCOMB_GEOM_SIG_EPS, eCOMB_NR 
-};
-
-/* NBF selection */
-enum { 
-  eNBF_NONE, eNBF_LJ, eNBF_BHAM, eNBF_NR 
-};
-
-/* FEP selection */
-enum {
-  efepNO, efepYES, efepNR
-};
-
-/* separate_dhdl_file selection */
-enum
-{
-    /* NOTE: YES is the first one. Do NOT interpret this one as a gmx_bool */
-    sepdhdlfileYES, sepdhdlfileNO, sepdhdlfileNR
-};
-
-/* dhdl_derivatives selection */
-enum
-{
-    /* NOTE: YES is the first one. Do NOT interpret this one as a gmx_bool */
-    dhdlderivativesYES, dhdlderivativesNO, dhdlderivativesNR
-};
-
-/* Solvent model */
-enum {
-  esolNO, esolSPC, esolTIP4P, esolNR
-};
-
-/* Dispersion correction */
-enum {
-  edispcNO, edispcEnerPres, edispcEner, edispcAllEnerPres, edispcAllEner, edispcNR
-}; 
-
-/* Shell types, for completion stuff */
-enum {
-  eshellCSH, eshellBASH, eshellZSH, eshellNR
-}; 
-
-/* Center of mass motion selection */
-enum { 
-  ecmLINEAR, ecmANGULAR, ecmNO, ecmNR 
-};
-
-/* New version of simulated annealing */
-enum { 
-  eannNO, eannSINGLE, eannPERIODIC, eannNR 
-};
-
-/* Implicit solvent algorithms */
-enum { 
-       eisNO, eisGBSA, eisNR 
-};
-
-/* Algorithms for calculating GB radii */
-enum { 
-  egbSTILL, egbHCT, egbOBC, egbNR 
-};
-
-enum {
-  esaAPPROX, esaNO, esaSTILL, esaNR
-};
-
-/* Wall types */
-enum {
-  ewt93, ewt104, ewtTABLE, ewt126, ewtNR
-};
-
-/* Pull stuff */
-enum {
-  epullNO, epullUMBRELLA, epullCONSTRAINT, epullCONST_F, epullNR
-};
-
-enum {
-  epullgDIST, epullgDIR, epullgCYL, epullgPOS, epullgDIRPBC, epullgNR
-};
-
-#define PULL_CYL(pull) ((pull)->eGeom == epullgCYL)
-
-/* QMMM */
-enum {
-  eQMmethodAM1, eQMmethodPM3, eQMmethodRHF, 
-  eQMmethodUHF, eQMmethodDFT, eQMmethodB3LYP, eQMmethodMP2, eQMmethodCASSCF, eQMmethodB3LYPLAN,
-  eQMmethodDIRECT, eQMmethodNR
-};
-
-enum {
-  eQMbasisSTO3G, eQMbasisSTO3G2, eQMbasis321G, 
-  eQMbasis321Gp, eQMbasis321dGp, eQMbasis621G,
-  eQMbasis631G, eQMbasis631Gp, eQMbasis631dGp, 
-  eQMbasis6311G, eQMbasisNR
-};
-
-enum {
-  eQMMMschemenormal,eQMMMschemeoniom,eQMMMschemeNR
-};
-
-enum {
-  eMultentOptName, eMultentOptNo, eMultentOptLast, eMultentOptNR
-};
-
-#ifdef __cplusplus
-}
-#endif
-
diff --git a/include/types/inputrec.h b/include/types/inputrec.h
deleted file mode 100644 (file)
index 7c99363..0000000
+++ /dev/null
@@ -1,312 +0,0 @@
-/*
- * 
- *                This source code is part of
- * 
- *                 G   R   O   M   A   C   S
- * 
- *          GROningen MAchine for Chemical Simulations
- * 
- *                        VERSION 3.2.0
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
- * 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.
-
- * 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:
- * GRoups of Organic Molecules in ACtion for Science
- */
-#ifndef _inputrec_h_
-#define _inputrec_h_
-
-
-#include "simple.h"
-#include "../sysstuff.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-typedef struct {
-  int  n;              /* Number of terms                              */
-  real *a;             /* Coeffients (V / nm )                         */
-  real *phi;           /* Phase angles                                 */
-} t_cosines;
-
-typedef struct {
-  real E0;              /* Field strength (V/nm)                        */
-  real omega;           /* Frequency (1/ps)                             */
-  real t0;              /* Centre of the Gaussian pulse (ps)            */
-  real sigma;           /* Width of the Gaussian pulse (FWHM) (ps)      */
-} t_efield;
-
-#define EGP_EXCL  (1<<0)
-#define EGP_TABLE (1<<1)
-
-typedef struct {
-  int     ngtc;                  /* # T-Coupl groups                        */
-  int     nhchainlength;         /* # of nose-hoover chains per group       */
-  int     ngacc;                 /* # Accelerate groups                     */
-  int     ngfrz;                 /* # Freeze groups                         */
-  int     ngener;               /* # Ener groups                           */
-  real    *nrdf;                /* Nr of degrees of freedom in a group     */
-  real    *ref_t;               /* Coupling temperature        per group   */
-  int     *annealing;            /* No/simple/periodic SA for each group    */
-  int     *anneal_npoints;       /* Number of annealing time points per grp */    
-  real    **anneal_time;         /* For ea. group: Time points              */
-  real    **anneal_temp;         /* For ea. grp: Temperature at these times */
-                                 /* Final temp after all intervals is ref_t */ 
-  real    *tau_t;               /* Tau coupling time                       */
-  rvec    *acc;                         /* Acceleration per group                  */
-  ivec    *nFreeze;             /* Freeze the group in each direction ?    */
-  int     *egp_flags;            /* Exclusions/tables of energy group pairs */
-
-  /* QMMM stuff */
-  int     ngQM;         /* nr of QM groups                              */
-  int     *QMmethod;    /* Level of theory in the QM calculation        */
-  int     *QMbasis;     /* Basisset in the QM calculation               */
-  int     *QMcharge;    /* Total charge in the QM region                */
-  int     *QMmult;      /* Spin multiplicicty in the QM region          */
-  gmx_bool    *bSH;         /* surface hopping (diabatic hop only)          */
-  int     *CASorbitals; /* number of orbiatls in the active space       */
-  int     *CASelectrons;/* number of electrons in the active space      */
-  real    *SAon;        /* at which gap (A.U.) the SA is switched on    */
-  real    *SAoff;
-  int     *SAsteps;     /* in how many steps SA goes from 1-1 to 0.5-0.5*/
-  gmx_bool    *bOPT;
-  gmx_bool    *bTS;
-} t_grpopts;
-
-enum { epgrppbcNONE, epgrppbcREFAT, epgrppbcCOS };
-
-typedef struct {
-  int        nat;      /* Number of atoms in the pull group */
-  atom_id    *ind;     /* The global atoms numbers */
-  int        nat_loc;  /* Number of local pull atoms */
-  int        nalloc_loc; /* Allocation size for ind_loc and weight_loc */ 
-  atom_id    *ind_loc; /* Local pull indices */
-  int        nweight;  /* The number of weights (0 or nat) */
-  real       *weight;  /* Weights (use all 1 when weight==NULL) */
-  real       *weight_loc; /* Weights for the local indices */
-  int        epgrppbc; /* The type of pbc for this pull group, see enum above */
-  atom_id    pbcatom;  /* The reference atom for pbc (global number) */
-  rvec       vec;      /* The pull vector, direction or position */
-  rvec       init;     /* Initial reference displacement */
-  real       rate;     /* Rate of motion (nm/ps) */
-  real       k;        /* force constant */
-  real       kB;       /* force constant for state B */
-  real       wscale;   /* scaling factor for the weights: sum w m/sum w w m */
-  real       invtm;    /* inverse total mass of the group: 1/wscale sum w m */
-  dvec       x;        /* center of mass before update */
-  dvec       xp;       /* center of mass after update before constraining */
-  dvec       dr;       /* The distance from the reference group */
-  double     f_scal;   /* Scalar force for directional pulling */
-  dvec       f;        /* force due to the pulling/constraining */
-} t_pullgrp; 
-
-typedef struct {
-  int        ngrp;        /* number of groups */
-  int        eGeom;       /* pull geometry */
-  ivec       dim;         /* used to select components for constraint */
-  real       cyl_r1;      /* radius of cylinder for dynamic COM */
-  real       cyl_r0;      /* radius of cylinder including switch length */
-  real       constr_tol;  /* absolute tolerance for constraints in (nm) */
-  int        nstxout;     /* Output frequency for pull x */
-  int        nstfout;     /* Output frequency for pull f */
-  int        ePBC;        /* the boundary conditions */
-  int        npbcdim;     /* do pbc in dims 0 <= dim < npbcdim */
-  gmx_bool       bRefAt;      /* do we need reference atoms for a group COM ? */
-  int        cosdim;      /* dimension for cosine weighting, -1 if none */
-  gmx_bool       bVirial;     /* do we need to add the pull virial? */
-  t_pullgrp  *grp;        /* groups to pull/restrain/etc/ */
-  t_pullgrp  *dyna;       /* dynamic groups for use with local constraints */
-  rvec       *rbuf;       /* COM calculation buffer */
-  dvec       *dbuf;       /* COM calculation buffer */
-  double     *dbuf_cyl;   /* cylinder ref. groups COM calculation buffer */
-
-  FILE       *out_x;      /* output file for pull data */
-  FILE       *out_f;      /* output file for pull data */
-} t_pull;
-
-typedef struct {
-  int  eI;              /* Integration method                          */
-  gmx_large_int_t nsteps;      /* number of steps to be taken                  */
-  int  simulation_part; /* Used in checkpointing to separate chunks */
-  gmx_large_int_t init_step;   /* start at a stepcount >0 (used w. tpbconv)    */
-  int  nstcalcenergy;  /* fequency of energy calc. and T/P coupl. upd. */
-  int  ns_type;                /* which ns method should we use?               */
-  int  nstlist;                /* number of steps before pairlist is generated */
-  int  ndelta;         /* number of cells per rlong                    */
-  int  nstcomm;                /* number of steps after which center of mass   */
-                        /* motion is removed                           */
-  int  comm_mode;       /* Center of mass motion removal algorithm      */
-  int nstcheckpoint;    /* checkpointing frequency                      */
-  int nstlog;          /* number of steps after which print to logfile */
-  int nstxout;         /* number of steps after which X is output      */
-  int nstvout;         /* id. for V                                    */
-  int nstfout;         /* id. for F                                    */
-  int nstenergy;       /* number of steps after which energies printed */
-  int nstxtcout;       /* id. for compressed trj (.xtc)                */
-  double init_t;       /* initial time (ps)                            */
-  double delta_t;      /* time step (ps)                               */
-  real xtcprec;         /* precision of xtc file                        */
-  int  nkx,nky,nkz;     /* number of k vectors in each spatial dimension*/
-                        /* for fourier methods for long range electrost.*/
-  int  pme_order;       /* interpolation order for PME                  */
-  real ewald_rtol;      /* Real space tolerance for Ewald, determines   */
-                        /* the real/reciprocal space relative weight    */
-  int  ewald_geometry;  /* normal/3d ewald, or pseudo-2d LR corrections */
-  real epsilon_surface; /* Epsilon for PME dipole correction            */
-  gmx_bool bOptFFT;         /* optimize the fft plan at start               */
-  int  ePBC;           /* Type of periodic boundary conditions         */
-  int  bPeriodicMols;   /* Periodic molecules                           */
-  gmx_bool bContinuation;   /* Continuation run: starting state is correct     */
-  int  etc;            /* temperature coupling                         */
-  int  nsttcouple;      /* interval in steps for temperature coupling   */
-  int  epc;            /* pressure coupling                            */
-  int  epct;           /* pressure coupling type                       */
-  int  nstpcouple;      /* interval in steps for pressure coupling      */
-  real tau_p;          /* pressure coupling time (ps)                  */
-  tensor ref_p;                /* reference pressure (kJ/(mol nm^3))           */
-  tensor compress;     /* compressability ((mol nm^3)/kJ)              */
-  int  refcoord_scaling;/* How to scale absolute reference coordinates  */
-  rvec posres_com;      /* The COM of the posres atoms                  */
-  rvec posres_comB;     /* The B-state COM of the posres atoms          */
-  int  andersen_seed;   /* Random seed for Andersen thermostat.         */
-  real rlist;          /* short range pairlist cut-off (nm)            */
-  real rlistlong;      /* long range pairlist cut-off (nm)             */
-  real rtpi;            /* Radius for test particle insertion           */
-  int  coulombtype;    /* Type of electrostatics treatment             */
-  real rcoulomb_switch; /* Coulomb switch range start (nm)             */
-  real rcoulomb;        /* Coulomb cutoff (nm)                         */
-  real epsilon_r;       /* relative dielectric constant                 */ 
-  real epsilon_rf;      /* relative dielectric constant of the RF       */ 
-  int  implicit_solvent;/* No (=explicit water), or GBSA solvent models */
-  int  gb_algorithm;    /* Algorithm to use for calculation Born radii  */
-  int  nstgbradii;      /* Frequency of updating Generalized Born radii */
-  real rgbradii;        /* Cutoff for GB radii calculation              */
-  real gb_saltconc;     /* Salt concentration (M) for GBSA models       */
-  real gb_epsilon_solvent; /* dielectric coeff. of implicit solvent     */
-  real gb_obc_alpha;    /* 1st scaling factor for Bashford-Case GB      */
-  real gb_obc_beta;     /* 2nd scaling factor for Bashford-Case GB      */
-  real gb_obc_gamma;    /* 3rd scaling factor for Bashford-Case GB      */
-  real gb_dielectric_offset; /* Dielectric offset for Still/HCT/OBC     */
-  int  sa_algorithm;    /* Algorithm for SA part of GBSA                */
-  real sa_surface_tension; /* Energy factor for SA part of GBSA */
-  int  vdwtype;         /* Type of Van der Waals treatment              */
-  real rvdw_switch;     /* Van der Waals switch range start (nm)        */
-  real rvdw;               /* Van der Waals cutoff (nm)                */
-  int  eDispCorr;       /* Perform Long range dispersion corrections    */
-  real tabext;          /* Extension of the table beyond the cut-off,   *
-                        * as well as the table length for 1-4 interac. */
-  real shake_tol;      /* tolerance for shake                          */
-  int  efep;                   /* free energy interpolation no/yes             */
-  double init_lambda;  /* initial value for perturbation variable      */
-  double delta_lambda; /* change of lambda per time step (1/dt)        */
-  int  n_flambda;       /* The number of foreign lambda points          */
-  double *flambda;      /* The foreign lambda values                    */
-  real sc_alpha;        /* free energy soft-core parameter              */
-  int  sc_power;        /* lambda power for soft-core interactions      */
-  real sc_sigma;        /* free energy soft-core sigma when c6 or c12=0 */
-  real sc_sigma_min;    /* minimum FE sc sigma (default: =sg_sigma)     */
-  int  nstdhdl;         /* The frequency for writing to dhdl.xvg        */
-  int  separate_dhdl_file; /* whether to write a separate dhdl.xvg file 
-                              note: NOT a gmx_bool, but an enum */
-  int  dhdl_derivatives;/* whether to calculate+write dhdl derivatives 
-                              note: NOT a gmx_bool, but an enum */
-  int  dh_hist_size;    /* The maximum size for the dH histogram        */
-  double dh_hist_spacing; /* The spacing for the dH histogram           */
-  int  eDisre;          /* Type of distance restraining                 */
-  real dr_fc;              /* force constant for ta_disre                      */
-  int  eDisreWeighting; /* type of weighting of pairs in one restraints        */
-  gmx_bool bDisreMixed;     /* Use comb of time averaged and instan. viol's    */
-  int  nstdisreout;     /* frequency of writing pair distances to enx   */ 
-  real dr_tau;             /* time constant for memory function in disres      */
-  real orires_fc;          /* force constant for orientational restraints  */
-  real orires_tau;         /* time constant for memory function in orires      */
-  int  nstorireout;     /* frequency of writing tr(SD) to enx           */ 
-  real dihre_fc;        /* force constant for dihedral restraints      */
-  real em_stepsize;        /* The stepsize for updating                        */
-  real em_tol;             /* The tolerance                            */
-  int  niter;           /* Number of iterations for convergence of      */
-                        /* steepest descent in relax_shells             */
-  real fc_stepsize;     /* Stepsize for directional minimization        */
-                        /* in relax_shells                              */
-  int  nstcgsteep;      /* number of steps after which a steepest       */
-                        /* descents step is done while doing cg         */
-  int  nbfgscorr;       /* Number of corrections to the hessian to keep */
-  int  eConstrAlg;      /* Type of constraint algorithm                 */
-  int  nProjOrder;      /* Order of the LINCS Projection Algorithm      */
-  real LincsWarnAngle;  /* If bond rotates more than %g degrees, warn   */
-  int  nLincsIter;      /* Number of iterations in the final Lincs step */
-  gmx_bool bShakeSOR;       /* Use successive overrelaxation for shake      */
-  real bd_fric;         /* Friction coefficient for BD (amu/ps)         */
-  int  ld_seed;         /* Random seed for SD and BD                    */
-  int  nwall;           /* The number of walls                          */
-  int  wall_type;       /* The type of walls                            */
-  real wall_r_linpot;   /* The potentail is linear for r<=wall_r_linpot */
-  int  wall_atomtype[2];/* The atom type for walls                      */
-  real wall_density[2]; /* Number density for walls                     */
-  real wall_ewald_zfac; /* Scaling factor for the box for Ewald         */
-  int  ePull;           /* Type of pulling: no, umbrella or constraint  */
-  t_pull *pull;         /* The data for center of mass pulling          */
-  real cos_accel;       /* Acceleration for viscosity calculation       */
-  tensor deform;        /* Triclinic deformation velocities (nm/ps)     */
-  int  userint1;        /* User determined parameters                   */
-  int  userint2;
-  int  userint3;
-  int  userint4;
-  real userreal1;
-  real userreal2;
-  real userreal3;
-  real userreal4;
-  t_grpopts opts;      /* Group options                                */
-  t_cosines ex[DIM];   /* Electric field stuff (spatial part)          */
-  t_cosines et[DIM];   /* Electric field stuff (time part)             */
-  gmx_bool bQMMM;           /* QM/MM calculation                            */ 
-  int  QMconstraints;   /* constraints on QM bonds                      */
-  int  QMMMscheme;      /* Scheme: ONIOM or normal                      */
-  real scalefactor;     /* factor for scaling the MM charges in QM calc.*/
-} t_inputrec;
-
-#define DEFORM(ir) ((ir).deform[XX][XX]!=0 || (ir).deform[YY][YY]!=0 || (ir).deform[ZZ][ZZ]!=0 || (ir).deform[YY][XX]!=0 || (ir).deform[ZZ][XX]!=0 || (ir).deform[ZZ][YY]!=0)
-
-#define DYNAMIC_BOX(ir) ((ir).epc!=epcNO || (ir).eI==eiTPI || DEFORM(ir))
-
-#define PRESERVE_SHAPE(ir) ((ir).epc != epcNO && (ir).deform[XX][XX] == 0 && ((ir).epct == epctISOTROPIC || (ir).epct == epctSEMIISOTROPIC))
-
-#define NEED_MUTOT(ir) (((ir).coulombtype==eelEWALD || EEL_PME((ir).coulombtype)) && ((ir).ewald_geometry==eewg3DC || (ir).epsilon_surface!=0))
-
-#define IR_TWINRANGE(ir) ((ir).rlist > 0 && ((ir).rlistlong == 0 || (ir).rlistlong > (ir).rlist))
-
-#define IR_ELEC_FIELD(ir) ((ir).ex[XX].n > 0 || (ir).ex[YY].n > 0 || (ir).ex[ZZ].n > 0)
-
-#define IR_EXCL_FORCES(ir) (EEL_FULL((ir).coulombtype) || (EEL_RF((ir).coulombtype) && (ir).coulombtype != eelRF_NEC) || (ir).implicit_solvent != eisNO)
-/* use pointer definitions of ir here, since that's what's usually used in the code */
-#define IR_NVT_TROTTER(ir) ((((ir)->eI == eiVV) || ((ir)->eI == eiVVAK)) && ((ir)->etc == etcNOSEHOOVER))
-
-#define IR_NPT_TROTTER(ir) ((((ir)->eI == eiVV) || ((ir)->eI == eiVVAK)) && ((ir)->epc == epcMTTK))
-
-#ifdef __cplusplus
-}
-#endif
-
-
-#endif
diff --git a/include/vec.h b/include/vec.h
deleted file mode 100644 (file)
index 139a9c4..0000000
+++ /dev/null
@@ -1,877 +0,0 @@
-/*
- * 
- *                This source code is part of
- * 
- *                 G   R   O   M   A   C   S
- * 
- *          GROningen MAchine for Chemical Simulations
- * 
- *                        VERSION 3.2.0
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
- * 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.
-
- * 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:
- * Gromacs Runs On Most of All Computer Systems
- */
-#ifndef _vec_h
-#define _vec_h
-
-/*
-  collection of in-line ready operations:
-  
-  lookup-table optimized scalar operations:
-  real gmx_invsqrt(real x)
-  void vecinvsqrt(real in[],real out[],int n)
-  void vecrecip(real in[],real out[],int n)
-  real sqr(real x)
-  double dsqr(double x)
-  
-  vector operations:
-  void rvec_add(const rvec a,const rvec b,rvec c)  c = a + b
-  void dvec_add(const dvec a,const dvec b,dvec c)  c = a + b
-  void ivec_add(const ivec a,const ivec b,ivec c)  c = a + b
-  void rvec_inc(rvec a,const rvec b)               a += b
-  void dvec_inc(dvec a,const dvec b)               a += b
-  void ivec_inc(ivec a,const ivec b)               a += b
-  void rvec_sub(const rvec a,const rvec b,rvec c)  c = a - b
-  void dvec_sub(const dvec a,const dvec b,dvec c)  c = a - b
-  void rvec_dec(rvec a,rvec b)                     a -= b
-  void copy_rvec(const rvec a,rvec b)              b = a (reals)
-  void copy_dvec(const dvec a,dvec b)              b = a (reals)
-  void copy_ivec(const ivec a,ivec b)              b = a (integers)
-  void ivec_sub(const ivec a,const ivec b,ivec c)  c = a - b
-  void svmul(real a,rvec v1,rvec v2)               v2 = a * v1
-  void dsvmul(double a,dvec v1,dvec v2)            v2 = a * v1
-  void clear_rvec(rvec a)                          a = 0
-  void clear_dvec(dvec a)                          a = 0
-  void clear_ivec(rvec a)                          a = 0
-  void clear_rvecs(int n,rvec v[])
-  real iprod(rvec a,rvec b)                        = a . b (inner product)
-  double diprod(dvec a,dvec b)                     = a . b (inner product)
-  real iiprod(ivec a,ivec b)                       = a . b (integers)
-  real norm2(rvec a)                               = | a |^2 ( = x*y*z )
-  double dnorm2(dvec a)                            = | a |^2 ( = x*y*z )
-  real norm(rvec a)                                = | a |
-  double dnorm(dvec a)                             = | a |
-  void cprod(rvec a,rvec b,rvec c)                 c = a x b (cross product)
-  void dprod(rvec a,rvec b,rvec c)                 c = a x b (cross product)
-  void dprod(rvec a,rvec b,rvec c)                 c = a * b (direct product)
-  real cos_angle(rvec a,rvec b)
-  real cos_angle_no_table(rvec a,rvec b)
-  real distance2(rvec v1, rvec v2)                 = | v2 - v1 |^2
-  void unitv(rvec src,rvec dest)                   dest = src / |src|
-  void unitv_no_table(rvec src,rvec dest)          dest = src / |src|
-  
-  matrix (3x3) operations:
-    ! indicates that dest should not be the same as a, b or src
-    the _ur0 varieties work on matrices that have only zeros
-    in the upper right part, such as box matrices, these varieties
-    could produce less rounding errors, not due to the operations themselves,
-    but because the compiler can easier recombine the operations
-  void copy_mat(matrix a,matrix b)                 b = a
-  void clear_mat(matrix a)                        a = 0
-  void mmul(matrix a,matrix b,matrix dest)     !  dest = a . b
-  void mmul_ur0(matrix a,matrix b,matrix dest)     dest = a . b
-  void transpose(matrix src,matrix dest)       !  dest = src*
-  void tmmul(matrix a,matrix b,matrix dest)    !  dest = a* . b
-  void mtmul(matrix a,matrix b,matrix dest)    !  dest = a . b*
-  real det(matrix a)                              = det(a)
-  void m_add(matrix a,matrix b,matrix dest)       dest = a + b
-  void m_sub(matrix a,matrix b,matrix dest)       dest = a - b
-  void msmul(matrix m1,real r1,matrix dest)       dest = r1 * m1
-  void m_inv_ur0(matrix src,matrix dest)           dest = src^-1
-  void m_inv(matrix src,matrix dest)           !  dest = src^-1
-  void mvmul(matrix a,rvec src,rvec dest)      !  dest = a . src
-  void mvmul_ur0(matrix a,rvec src,rvec dest)      dest = a . src
-  void tmvmul_ur0(matrix a,rvec src,rvec dest)     dest = a* . src
-  real trace(matrix m)                             = trace(m)
-*/
-
-#include "types/simple.h"
-#include "maths.h"
-#include "typedefs.h"
-#include "sysstuff.h"
-#include "macros.h"
-#include "gmx_fatal.h"
-#include "mpelogging.h"
-#include "physics.h"
-
-#ifdef __cplusplus
-extern "C" {
-#elif 0
-} /* avoid screwing up indentation */
-#endif
-
-
-#define EXP_LSB         0x00800000
-#define EXP_MASK        0x7f800000
-#define EXP_SHIFT       23
-#define FRACT_MASK      0x007fffff
-#define FRACT_SIZE      11              /* significant part of fraction */
-#define FRACT_SHIFT     (EXP_SHIFT-FRACT_SIZE)
-#define EXP_ADDR(val)   (((val)&EXP_MASK)>>EXP_SHIFT)
-#define FRACT_ADDR(val) (((val)&(FRACT_MASK|EXP_LSB))>>FRACT_SHIFT)
-
-#define PR_VEC(a)       a[XX],a[YY],a[ZZ]
-
-#ifdef GMX_SOFTWARE_INVSQRT
-extern const unsigned int *  gmx_invsqrt_exptab;
-extern const unsigned int *  gmx_invsqrt_fracttab;
-#endif
-
-
-typedef union 
-{
-  unsigned int bval;
-  float fval;
-} t_convert;
-
-
-#ifdef GMX_SOFTWARE_INVSQRT
-static real gmx_invsqrt(real x)
-{
-  const real  half=0.5;
-  const real  three=3.0;
-  t_convert   result,bit_pattern;
-  unsigned int exp,fract;
-  real        lu;
-  real        y;
-#ifdef GMX_DOUBLE
-  real        y2;
-#endif
-  bit_pattern.fval=x;
-  exp   = EXP_ADDR(bit_pattern.bval);
-  fract = FRACT_ADDR(bit_pattern.bval);
-  result.bval=gmx_invsqrt_exptab[exp] | gmx_invsqrt_fracttab[fract];
-  lu    = result.fval;
-  
-  y=(half*lu*(three-((x*lu)*lu)));
-#ifdef GMX_DOUBLE
-  y2=(half*y*(three-((x*y)*y)));
-  
-  return y2;                    /* 10 Flops */
-#else
-  return y;                     /* 5  Flops */
-#endif
-}
-#define INVSQRT_DONE 
-#endif /* gmx_invsqrt */
-
-#ifdef GMX_POWERPC_SQRT
-static real gmx_invsqrt(real x)
-{
-  const real  half=0.5;
-  const real  three=3.0;
-  t_convert   result,bit_pattern;
-  unsigned int exp,fract;
-  real        lu;
-  real        y;
-#ifdef GMX_DOUBLE
-  real        y2;
-#endif
-
-  lu = __frsqrte((double)x);
-
-  y=(half*lu*(three-((x*lu)*lu)));
-
-#if (GMX_POWERPC_SQRT==2)
-  /* Extra iteration required */
-  y=(half*y*(three-((x*y)*y)));
-#endif
-
-#ifdef GMX_DOUBLE
-  y2=(half*y*(three-((x*y)*y)));
-
-  return y2;                    /* 10 Flops */
-#else
-  return y;                     /* 5  Flops */
-#endif
-}
-#define INVSQRT_DONE
-#endif /* powerpc_invsqrt */
-
-
-#ifndef INVSQRT_DONE
-#define gmx_invsqrt(x) (1.0f/sqrt(x))
-#endif
-
-
-
-
-
-static real sqr(real x)
-{
-  return (x*x);
-}
-
-static gmx_inline double dsqr(double x)
-{
-  return (x*x);
-}
-
-/* Maclaurin series for sinh(x)/x, useful for NH chains and MTTK pressure control 
-   Here, we compute it to 10th order, which might be overkill, 8th is probably enough, 
-   but it's not very much more expensive. */
-
-static gmx_inline real series_sinhx(real x) 
-{
-  real x2 = x*x;
-  return (1 + (x2/6.0)*(1 + (x2/20.0)*(1 + (x2/42.0)*(1 + (x2/72.0)*(1 + (x2/110.0))))));
-}
-
-void vecinvsqrt(real in[],real out[],int n);
-/* Perform out[i]=1.0/sqrt(in[i]) for n elements */
-
-
-void vecrecip(real in[],real out[],int n);
-/* Perform out[i]=1.0/(in[i]) for n elements */
-
-/* Note: If you need a fast version of vecinvsqrt 
- * and/or vecrecip, call detectcpu() and run the SSE/3DNow/SSE2/Altivec
- * versions if your hardware supports it.
- *
- * To use those routines, your memory HAS TO BE CACHE-ALIGNED.
- * Use snew_aligned(ptr,size,32) to allocate and sfree_aligned to free.
- */
-
-
-static gmx_inline void rvec_add(const rvec a,const rvec b,rvec c)
-{
-  real x,y,z;
-  
-  x=a[XX]+b[XX];
-  y=a[YY]+b[YY];
-  z=a[ZZ]+b[ZZ];
-  
-  c[XX]=x;
-  c[YY]=y;
-  c[ZZ]=z;
-}
-
-static gmx_inline void dvec_add(const dvec a,const dvec b,dvec c)
-{
-  double x,y,z;
-  
-  x=a[XX]+b[XX];
-  y=a[YY]+b[YY];
-  z=a[ZZ]+b[ZZ];
-  
-  c[XX]=x;
-  c[YY]=y;
-  c[ZZ]=z;
-}
-
-static gmx_inline void ivec_add(const ivec a,const ivec b,ivec c)
-{
-  int x,y,z;
-  
-  x=a[XX]+b[XX];
-  y=a[YY]+b[YY];
-  z=a[ZZ]+b[ZZ];
-  
-  c[XX]=x;
-  c[YY]=y;
-  c[ZZ]=z;
-}
-
-static gmx_inline void rvec_inc(rvec a,const rvec b)
-{
-  real x,y,z;
-  
-  x=a[XX]+b[XX];
-  y=a[YY]+b[YY];
-  z=a[ZZ]+b[ZZ];
-  
-  a[XX]=x;
-  a[YY]=y;
-  a[ZZ]=z;
-}
-
-static gmx_inline void dvec_inc(dvec a,const dvec b)
-{
-  double x,y,z;
-
-  x=a[XX]+b[XX];
-  y=a[YY]+b[YY];
-  z=a[ZZ]+b[ZZ];
-
-  a[XX]=x;
-  a[YY]=y;
-  a[ZZ]=z;
-}
-
-static gmx_inline void rvec_sub(const rvec a,const rvec b,rvec c)
-{
-  real x,y,z;
-  
-  x=a[XX]-b[XX];
-  y=a[YY]-b[YY];
-  z=a[ZZ]-b[ZZ];
-  
-  c[XX]=x;
-  c[YY]=y;
-  c[ZZ]=z;
-}
-
-static gmx_inline void dvec_sub(const dvec a,const dvec b,dvec c)
-{
-  double x,y,z;
-  
-  x=a[XX]-b[XX];
-  y=a[YY]-b[YY];
-  z=a[ZZ]-b[ZZ];
-  
-  c[XX]=x;
-  c[YY]=y;
-  c[ZZ]=z;
-}
-
-static gmx_inline void rvec_dec(rvec a,const rvec b)
-{
-  real x,y,z;
-  
-  x=a[XX]-b[XX];
-  y=a[YY]-b[YY];
-  z=a[ZZ]-b[ZZ];
-  
-  a[XX]=x;
-  a[YY]=y;
-  a[ZZ]=z;
-}
-
-static gmx_inline void copy_rvec(const rvec a,rvec b)
-{
-  b[XX]=a[XX];
-  b[YY]=a[YY];
-  b[ZZ]=a[ZZ];
-}
-
-static gmx_inline void copy_rvecn(rvec *a,rvec *b,int startn, int endn)
-{
-  int i;
-  for (i=startn;i<endn;i++) {
-    b[i][XX]=a[i][XX];
-    b[i][YY]=a[i][YY];
-    b[i][ZZ]=a[i][ZZ];
-  }
-}
-
-static gmx_inline void copy_dvec(const dvec a,dvec b)
-{
-  b[XX]=a[XX];
-  b[YY]=a[YY];
-  b[ZZ]=a[ZZ];
-}
-
-static gmx_inline void copy_ivec(const ivec a,ivec b)
-{
-  b[XX]=a[XX];
-  b[YY]=a[YY];
-  b[ZZ]=a[ZZ];
-}
-
-static gmx_inline void ivec_sub(const ivec a,const ivec b,ivec c)
-{
-  int x,y,z;
-  
-  x=a[XX]-b[XX];
-  y=a[YY]-b[YY];
-  z=a[ZZ]-b[ZZ];
-  
-  c[XX]=x;
-  c[YY]=y;
-  c[ZZ]=z;
-}
-
-static gmx_inline void copy_mat(matrix a,matrix b)
-{
-  copy_rvec(a[XX],b[XX]);
-  copy_rvec(a[YY],b[YY]);
-  copy_rvec(a[ZZ],b[ZZ]);
-}
-
-static gmx_inline void svmul(real a,const rvec v1,rvec v2)
-{
-  v2[XX]=a*v1[XX];
-  v2[YY]=a*v1[YY];
-  v2[ZZ]=a*v1[ZZ];
-}
-
-static gmx_inline void dsvmul(double a,const dvec v1,dvec v2)
-{
-  v2[XX]=a*v1[XX];
-  v2[YY]=a*v1[YY];
-  v2[ZZ]=a*v1[ZZ];
-}
-
-static gmx_inline real distance2(const rvec v1,const rvec v2)
-{
-  return sqr(v2[XX]-v1[XX]) + sqr(v2[YY]-v1[YY]) + sqr(v2[ZZ]-v1[ZZ]);
-}
-
-static gmx_inline void clear_rvec(rvec a)
-{
-  /* The ibm compiler has problems with inlining this 
-   * when we use a const real variable
-   */
-  a[XX]=0.0;
-  a[YY]=0.0;
-  a[ZZ]=0.0;
-}
-
-static gmx_inline void clear_dvec(dvec a)
-{
-  /* The ibm compiler has problems with inlining this 
-   * when we use a const real variable
-   */
-  a[XX]=0.0;
-  a[YY]=0.0;
-  a[ZZ]=0.0;
-}
-
-static gmx_inline void clear_ivec(ivec a)
-{
-  a[XX]=0;
-  a[YY]=0;
-  a[ZZ]=0;
-}
-
-static gmx_inline void clear_rvecs(int n,rvec v[])
-{
-/*  memset(v[0],0,DIM*n*sizeof(v[0][0])); */
-  int i;
-
-  GMX_MPE_LOG(ev_clear_rvecs_start);
-    
-  for(i=0; (i<n); i++) 
-    clear_rvec(v[i]);
-    
-  GMX_MPE_LOG(ev_clear_rvecs_finish);  
-}
-
-static gmx_inline void clear_mat(matrix a)
-{
-/*  memset(a[0],0,DIM*DIM*sizeof(a[0][0])); */
-  
-  const real nul=0.0;
-  
-  a[XX][XX]=a[XX][YY]=a[XX][ZZ]=nul;
-  a[YY][XX]=a[YY][YY]=a[YY][ZZ]=nul;
-  a[ZZ][XX]=a[ZZ][YY]=a[ZZ][ZZ]=nul;
-}
-
-static gmx_inline real iprod(const rvec a,const rvec b)
-{
-  return (a[XX]*b[XX]+a[YY]*b[YY]+a[ZZ]*b[ZZ]);
-}
-
-static gmx_inline double diprod(const dvec a,const dvec b)
-{
-  return (a[XX]*b[XX]+a[YY]*b[YY]+a[ZZ]*b[ZZ]);
-}
-
-static gmx_inline int iiprod(const ivec a,const ivec b)
-{
-  return (a[XX]*b[XX]+a[YY]*b[YY]+a[ZZ]*b[ZZ]);
-}
-
-static gmx_inline real norm2(const rvec a)
-{
-  return a[XX]*a[XX]+a[YY]*a[YY]+a[ZZ]*a[ZZ];
-}
-
-static gmx_inline double dnorm2(const dvec a)
-{
-  return a[XX]*a[XX]+a[YY]*a[YY]+a[ZZ]*a[ZZ];
-}
-
-static gmx_inline real norm(const rvec a)
-{
-  return (real)sqrt(a[XX]*a[XX]+a[YY]*a[YY]+a[ZZ]*a[ZZ]);
-}
-
-static gmx_inline double dnorm(const dvec a)
-{
-  return sqrt(a[XX]*a[XX]+a[YY]*a[YY]+a[ZZ]*a[ZZ]);
-}
-
-/* WARNING:
- * Do _not_ use these routines to calculate the angle between two vectors
- * as acos(cos_angle(u,v)). While it might seem obvious, the acos function
- * is very flat close to -1 and 1, which will lead to accuracy-loss.
- * Instead, use the new gmx_angle() function directly.
- */
-static gmx_inline real 
-cos_angle(const rvec a,const rvec b)
-{
-  /* 
-   *                  ax*bx + ay*by + az*bz
-   * cos-vec (a,b) =  ---------------------
-   *                      ||a|| * ||b||
-   */
-  real   cosval;
-  int    m;
-  double aa,bb,ip,ipa,ipb,ipab; /* For accuracy these must be double! */
-  
-  ip=ipa=ipb=0.0;
-  for(m=0; (m<DIM); m++) {             /* 18           */
-    aa   = a[m];
-    bb   = b[m];
-    ip  += aa*bb;
-    ipa += aa*aa;
-    ipb += bb*bb;
-  }
-  ipab = ipa*ipb;
-  if (ipab > 0)
-    cosval = ip*gmx_invsqrt(ipab);             /*  7           */
-  else 
-    cosval = 1;
-                                       /* 25 TOTAL     */
-  if (cosval > 1.0) 
-    return  1.0; 
-  if (cosval <-1.0) 
-    return -1.0;
-  
-  return cosval;
-}
-
-/* WARNING:
- * Do _not_ use these routines to calculate the angle between two vectors
- * as acos(cos_angle(u,v)). While it might seem obvious, the acos function
- * is very flat close to -1 and 1, which will lead to accuracy-loss.
- * Instead, use the new gmx_angle() function directly.
- */
-static gmx_inline real 
-cos_angle_no_table(const rvec a,const rvec b)
-{
-  /* This version does not need the invsqrt lookup table */
-  real   cosval;
-  int    m;
-  double aa,bb,ip,ipa,ipb; /* For accuracy these must be double! */
-  
-  ip=ipa=ipb=0.0;
-  for(m=0; (m<DIM); m++) {             /* 18           */
-    aa   = a[m];
-    bb   = b[m];
-    ip  += aa*bb;
-    ipa += aa*aa;
-    ipb += bb*bb;
-  }
-  cosval=ip/sqrt(ipa*ipb);             /* 12           */
-                                       /* 30 TOTAL     */
-  if (cosval > 1.0) 
-    return  1.0; 
-  if (cosval <-1.0) 
-    return -1.0;
-  
-  return cosval;
-}
-
-
-static gmx_inline void cprod(const rvec a,const rvec b,rvec c)
-{
-  c[XX]=a[YY]*b[ZZ]-a[ZZ]*b[YY];
-  c[YY]=a[ZZ]*b[XX]-a[XX]*b[ZZ];
-  c[ZZ]=a[XX]*b[YY]-a[YY]*b[XX];
-}
-
-static gmx_inline void dcprod(const dvec a,const dvec b,dvec c)
-{
-  c[XX]=a[YY]*b[ZZ]-a[ZZ]*b[YY];
-  c[YY]=a[ZZ]*b[XX]-a[XX]*b[ZZ];
-  c[ZZ]=a[XX]*b[YY]-a[YY]*b[XX];
-}
-
-/* This routine calculates the angle between a & b without any loss of accuracy close to 0/PI.
- * If you only need cos(theta), use the cos_angle() routines to save a few cycles.
- * This routine is faster than it might appear, since atan2 is accelerated on many CPUs (e.g. x86).
- */
-static gmx_inline real 
-gmx_angle(const rvec a, const rvec b)
-{
-    rvec w;
-    real wlen,s;
-    
-    cprod(a,b,w);
-    
-    wlen  = norm(w);
-    s     = iprod(a,b);
-    
-    return atan2(wlen,s);
-}
-
-static gmx_inline void mmul_ur0(matrix a,matrix b,matrix dest)
-{
-  dest[XX][XX]=a[XX][XX]*b[XX][XX];
-  dest[XX][YY]=0.0;
-  dest[XX][ZZ]=0.0;
-  dest[YY][XX]=a[YY][XX]*b[XX][XX]+a[YY][YY]*b[YY][XX];
-  dest[YY][YY]=                    a[YY][YY]*b[YY][YY];
-  dest[YY][ZZ]=0.0;
-  dest[ZZ][XX]=a[ZZ][XX]*b[XX][XX]+a[ZZ][YY]*b[YY][XX]+a[ZZ][ZZ]*b[ZZ][XX];
-  dest[ZZ][YY]=                    a[ZZ][YY]*b[YY][YY]+a[ZZ][ZZ]*b[ZZ][YY];
-  dest[ZZ][ZZ]=                                        a[ZZ][ZZ]*b[ZZ][ZZ];
-}
-
-static gmx_inline void mmul(matrix a,matrix b,matrix dest)
-{
-  dest[XX][XX]=a[XX][XX]*b[XX][XX]+a[XX][YY]*b[YY][XX]+a[XX][ZZ]*b[ZZ][XX];
-  dest[YY][XX]=a[YY][XX]*b[XX][XX]+a[YY][YY]*b[YY][XX]+a[YY][ZZ]*b[ZZ][XX];
-  dest[ZZ][XX]=a[ZZ][XX]*b[XX][XX]+a[ZZ][YY]*b[YY][XX]+a[ZZ][ZZ]*b[ZZ][XX];
-  dest[XX][YY]=a[XX][XX]*b[XX][YY]+a[XX][YY]*b[YY][YY]+a[XX][ZZ]*b[ZZ][YY];
-  dest[YY][YY]=a[YY][XX]*b[XX][YY]+a[YY][YY]*b[YY][YY]+a[YY][ZZ]*b[ZZ][YY];
-  dest[ZZ][YY]=a[ZZ][XX]*b[XX][YY]+a[ZZ][YY]*b[YY][YY]+a[ZZ][ZZ]*b[ZZ][YY];
-  dest[XX][ZZ]=a[XX][XX]*b[XX][ZZ]+a[XX][YY]*b[YY][ZZ]+a[XX][ZZ]*b[ZZ][ZZ];
-  dest[YY][ZZ]=a[YY][XX]*b[XX][ZZ]+a[YY][YY]*b[YY][ZZ]+a[YY][ZZ]*b[ZZ][ZZ];
-  dest[ZZ][ZZ]=a[ZZ][XX]*b[XX][ZZ]+a[ZZ][YY]*b[YY][ZZ]+a[ZZ][ZZ]*b[ZZ][ZZ];
-}
-
-static gmx_inline void transpose(matrix src,matrix dest)
-{
-  dest[XX][XX]=src[XX][XX];
-  dest[YY][XX]=src[XX][YY];
-  dest[ZZ][XX]=src[XX][ZZ];
-  dest[XX][YY]=src[YY][XX];
-  dest[YY][YY]=src[YY][YY];
-  dest[ZZ][YY]=src[YY][ZZ];
-  dest[XX][ZZ]=src[ZZ][XX];
-  dest[YY][ZZ]=src[ZZ][YY];
-  dest[ZZ][ZZ]=src[ZZ][ZZ];
-}
-
-static gmx_inline void tmmul(matrix a,matrix b,matrix dest)
-{
-  /* Computes dest=mmul(transpose(a),b,dest) - used in do_pr_pcoupl */
-  dest[XX][XX]=a[XX][XX]*b[XX][XX]+a[YY][XX]*b[YY][XX]+a[ZZ][XX]*b[ZZ][XX];
-  dest[XX][YY]=a[XX][XX]*b[XX][YY]+a[YY][XX]*b[YY][YY]+a[ZZ][XX]*b[ZZ][YY];
-  dest[XX][ZZ]=a[XX][XX]*b[XX][ZZ]+a[YY][XX]*b[YY][ZZ]+a[ZZ][XX]*b[ZZ][ZZ];
-  dest[YY][XX]=a[XX][YY]*b[XX][XX]+a[YY][YY]*b[YY][XX]+a[ZZ][YY]*b[ZZ][XX];
-  dest[YY][YY]=a[XX][YY]*b[XX][YY]+a[YY][YY]*b[YY][YY]+a[ZZ][YY]*b[ZZ][YY];
-  dest[YY][ZZ]=a[XX][YY]*b[XX][ZZ]+a[YY][YY]*b[YY][ZZ]+a[ZZ][YY]*b[ZZ][ZZ];
-  dest[ZZ][XX]=a[XX][ZZ]*b[XX][XX]+a[YY][ZZ]*b[YY][XX]+a[ZZ][ZZ]*b[ZZ][XX];
-  dest[ZZ][YY]=a[XX][ZZ]*b[XX][YY]+a[YY][ZZ]*b[YY][YY]+a[ZZ][ZZ]*b[ZZ][YY];
-  dest[ZZ][ZZ]=a[XX][ZZ]*b[XX][ZZ]+a[YY][ZZ]*b[YY][ZZ]+a[ZZ][ZZ]*b[ZZ][ZZ];
-}
-
-static gmx_inline void mtmul(matrix a,matrix b,matrix dest)
-{
-  /* Computes dest=mmul(a,transpose(b),dest) - used in do_pr_pcoupl */
-  dest[XX][XX]=a[XX][XX]*b[XX][XX]+a[XX][YY]*b[XX][YY]+a[XX][ZZ]*b[XX][ZZ];
-  dest[XX][YY]=a[XX][XX]*b[YY][XX]+a[XX][YY]*b[YY][YY]+a[XX][ZZ]*b[YY][ZZ];
-  dest[XX][ZZ]=a[XX][XX]*b[ZZ][XX]+a[XX][YY]*b[ZZ][YY]+a[XX][ZZ]*b[ZZ][ZZ];
-  dest[YY][XX]=a[YY][XX]*b[XX][XX]+a[YY][YY]*b[XX][YY]+a[YY][ZZ]*b[XX][ZZ];
-  dest[YY][YY]=a[YY][XX]*b[YY][XX]+a[YY][YY]*b[YY][YY]+a[YY][ZZ]*b[YY][ZZ];
-  dest[YY][ZZ]=a[YY][XX]*b[ZZ][XX]+a[YY][YY]*b[ZZ][YY]+a[YY][ZZ]*b[ZZ][ZZ];
-  dest[ZZ][XX]=a[ZZ][XX]*b[XX][XX]+a[ZZ][YY]*b[XX][YY]+a[ZZ][ZZ]*b[XX][ZZ];
-  dest[ZZ][YY]=a[ZZ][XX]*b[YY][XX]+a[ZZ][YY]*b[YY][YY]+a[ZZ][ZZ]*b[YY][ZZ];
-  dest[ZZ][ZZ]=a[ZZ][XX]*b[ZZ][XX]+a[ZZ][YY]*b[ZZ][YY]+a[ZZ][ZZ]*b[ZZ][ZZ];
-}
-
-static gmx_inline real det(matrix a)
-{
-  return ( a[XX][XX]*(a[YY][YY]*a[ZZ][ZZ]-a[ZZ][YY]*a[YY][ZZ])
-         -a[YY][XX]*(a[XX][YY]*a[ZZ][ZZ]-a[ZZ][YY]*a[XX][ZZ])
-         +a[ZZ][XX]*(a[XX][YY]*a[YY][ZZ]-a[YY][YY]*a[XX][ZZ]));
-}
-
-static gmx_inline void m_add(matrix a,matrix b,matrix dest)
-{
-  dest[XX][XX]=a[XX][XX]+b[XX][XX];
-  dest[XX][YY]=a[XX][YY]+b[XX][YY];
-  dest[XX][ZZ]=a[XX][ZZ]+b[XX][ZZ];
-  dest[YY][XX]=a[YY][XX]+b[YY][XX];
-  dest[YY][YY]=a[YY][YY]+b[YY][YY];
-  dest[YY][ZZ]=a[YY][ZZ]+b[YY][ZZ];
-  dest[ZZ][XX]=a[ZZ][XX]+b[ZZ][XX];
-  dest[ZZ][YY]=a[ZZ][YY]+b[ZZ][YY];
-  dest[ZZ][ZZ]=a[ZZ][ZZ]+b[ZZ][ZZ];
-}
-
-static gmx_inline void m_sub(matrix a,matrix b,matrix dest)
-{
-  dest[XX][XX]=a[XX][XX]-b[XX][XX];
-  dest[XX][YY]=a[XX][YY]-b[XX][YY];
-  dest[XX][ZZ]=a[XX][ZZ]-b[XX][ZZ];
-  dest[YY][XX]=a[YY][XX]-b[YY][XX];
-  dest[YY][YY]=a[YY][YY]-b[YY][YY];
-  dest[YY][ZZ]=a[YY][ZZ]-b[YY][ZZ];
-  dest[ZZ][XX]=a[ZZ][XX]-b[ZZ][XX];
-  dest[ZZ][YY]=a[ZZ][YY]-b[ZZ][YY];
-  dest[ZZ][ZZ]=a[ZZ][ZZ]-b[ZZ][ZZ];
-}
-
-static gmx_inline void msmul(matrix m1,real r1,matrix dest)
-{
-  dest[XX][XX]=r1*m1[XX][XX];
-  dest[XX][YY]=r1*m1[XX][YY];
-  dest[XX][ZZ]=r1*m1[XX][ZZ];
-  dest[YY][XX]=r1*m1[YY][XX];
-  dest[YY][YY]=r1*m1[YY][YY];
-  dest[YY][ZZ]=r1*m1[YY][ZZ];
-  dest[ZZ][XX]=r1*m1[ZZ][XX];
-  dest[ZZ][YY]=r1*m1[ZZ][YY];
-  dest[ZZ][ZZ]=r1*m1[ZZ][ZZ];
-}
-
-static gmx_inline void m_inv_ur0(matrix src,matrix dest)
-{
-  double tmp = src[XX][XX]*src[YY][YY]*src[ZZ][ZZ];
-  if (fabs(tmp) <= 100*GMX_REAL_MIN)
-    gmx_fatal(FARGS,"Can not invert matrix, determinant is zero");
-
-  dest[XX][XX] = 1/src[XX][XX];
-  dest[YY][YY] = 1/src[YY][YY];
-  dest[ZZ][ZZ] = 1/src[ZZ][ZZ];
-  dest[ZZ][XX] = (src[YY][XX]*src[ZZ][YY]*dest[YY][YY]
-                 - src[ZZ][XX])*dest[XX][XX]*dest[ZZ][ZZ];
-  dest[YY][XX] = -src[YY][XX]*dest[XX][XX]*dest[YY][YY];
-  dest[ZZ][YY] = -src[ZZ][YY]*dest[YY][YY]*dest[ZZ][ZZ];
-  dest[XX][YY] = 0.0;
-  dest[XX][ZZ] = 0.0;
-  dest[YY][ZZ] = 0.0;
-}
-
-static gmx_inline void m_inv(matrix src,matrix dest)
-{
-  const real smallreal = (real)1.0e-24;
-  const real largereal = (real)1.0e24;
-  real  deter,c,fc;
-
-  deter = det(src);
-  c     = (real)1.0/deter;
-  fc    = (real)fabs(c);
-  
-  if ((fc <= smallreal) || (fc >= largereal)) 
-    gmx_fatal(FARGS,"Can not invert matrix, determinant = %e",deter);
-
-  dest[XX][XX]= c*(src[YY][YY]*src[ZZ][ZZ]-src[ZZ][YY]*src[YY][ZZ]);
-  dest[XX][YY]=-c*(src[XX][YY]*src[ZZ][ZZ]-src[ZZ][YY]*src[XX][ZZ]);
-  dest[XX][ZZ]= c*(src[XX][YY]*src[YY][ZZ]-src[YY][YY]*src[XX][ZZ]);
-  dest[YY][XX]=-c*(src[YY][XX]*src[ZZ][ZZ]-src[ZZ][XX]*src[YY][ZZ]);
-  dest[YY][YY]= c*(src[XX][XX]*src[ZZ][ZZ]-src[ZZ][XX]*src[XX][ZZ]);
-  dest[YY][ZZ]=-c*(src[XX][XX]*src[YY][ZZ]-src[YY][XX]*src[XX][ZZ]);
-  dest[ZZ][XX]= c*(src[YY][XX]*src[ZZ][YY]-src[ZZ][XX]*src[YY][YY]);
-  dest[ZZ][YY]=-c*(src[XX][XX]*src[ZZ][YY]-src[ZZ][XX]*src[XX][YY]);
-  dest[ZZ][ZZ]= c*(src[XX][XX]*src[YY][YY]-src[YY][XX]*src[XX][YY]);
-}
-
-static gmx_inline void mvmul(matrix a,const rvec src,rvec dest)
-{
-  dest[XX]=a[XX][XX]*src[XX]+a[XX][YY]*src[YY]+a[XX][ZZ]*src[ZZ];
-  dest[YY]=a[YY][XX]*src[XX]+a[YY][YY]*src[YY]+a[YY][ZZ]*src[ZZ];
-  dest[ZZ]=a[ZZ][XX]*src[XX]+a[ZZ][YY]*src[YY]+a[ZZ][ZZ]*src[ZZ];
-}
-
-static gmx_inline void mvmul_ur0(matrix a,const rvec src,rvec dest)
-{
-  dest[ZZ]=a[ZZ][XX]*src[XX]+a[ZZ][YY]*src[YY]+a[ZZ][ZZ]*src[ZZ];
-  dest[YY]=a[YY][XX]*src[XX]+a[YY][YY]*src[YY];
-  dest[XX]=a[XX][XX]*src[XX];
-}
-
-static gmx_inline void tmvmul_ur0(matrix a,const rvec src,rvec dest)
-{
-  dest[XX]=a[XX][XX]*src[XX]+a[YY][XX]*src[YY]+a[ZZ][XX]*src[ZZ];
-  dest[YY]=                  a[YY][YY]*src[YY]+a[ZZ][YY]*src[ZZ];
-  dest[ZZ]=                                    a[ZZ][ZZ]*src[ZZ];
-}
-
-static gmx_inline void unitv(const rvec src,rvec dest)
-{
-  real linv;
-  
-  linv=gmx_invsqrt(norm2(src));
-  dest[XX]=linv*src[XX];
-  dest[YY]=linv*src[YY];
-  dest[ZZ]=linv*src[ZZ];
-}
-
-static gmx_inline void unitv_no_table(const rvec src,rvec dest)
-{
-  real linv;
-  
-  linv=1.0/sqrt(norm2(src));
-  dest[XX]=linv*src[XX];
-  dest[YY]=linv*src[YY];
-  dest[ZZ]=linv*src[ZZ];
-}
-
-static void calc_lll(rvec box,rvec lll)
-{
-  lll[XX] = 2.0*M_PI/box[XX];
-  lll[YY] = 2.0*M_PI/box[YY];
-  lll[ZZ] = 2.0*M_PI/box[ZZ];
-}
-
-static gmx_inline real trace(matrix m)
-{
-  return (m[XX][XX]+m[YY][YY]+m[ZZ][ZZ]);
-}
-
-static gmx_inline real _divide(real a,real b,const char *file,int line)
-{
-    if (fabs(b) <= GMX_REAL_MIN) 
-        gmx_fatal(FARGS,"Dividing by zero, file %s, line %d",file,line);
-    return a/b;
-}
-
-static gmx_inline int _mod(int a,int b,char *file,int line)
-{
-  if(b==0)
-    gmx_fatal(FARGS,"Modulo zero, file %s, line %d",file,line);
-  return a % b;
-}
-
-/* Operations on multidimensional rvecs, used e.g. in edsam.c */
-static void m_rveccopy(int dim, rvec *a, rvec *b)
-{
-    /* b = a */
-    int i;
-
-    for (i=0; i<dim; i++)
-        copy_rvec(a[i],b[i]);
-} 
-
-/*computer matrix vectors from base vectors and angles */
-static void matrix_convert(matrix box, rvec vec, rvec angle)
-{
-    svmul(DEG2RAD,angle,angle);
-    box[XX][XX] = vec[XX];
-    box[YY][XX] = vec[YY]*cos(angle[ZZ]);
-    box[YY][YY] = vec[YY]*sin(angle[ZZ]);
-    box[ZZ][XX] = vec[ZZ]*cos(angle[YY]);
-    box[ZZ][YY] = vec[ZZ]
-                         *(cos(angle[XX])-cos(angle[YY])*cos(angle[ZZ]))/sin(angle[ZZ]);
-    box[ZZ][ZZ] = sqrt(sqr(vec[ZZ])
-                       -box[ZZ][XX]*box[ZZ][XX]-box[ZZ][YY]*box[ZZ][YY]);
-}
-
-#define divide(a,b) _divide((a),(b),__FILE__,__LINE__)
-#define mod(a,b)    _mod((a),(b),__FILE__,__LINE__)
-
-#ifdef __cplusplus
-}
-#endif
-
-
-#endif /* _vec_h */
diff --git a/man/.cvsignore b/man/.cvsignore
deleted file mode 100644 (file)
index 3dda729..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-Makefile.in
-Makefile
diff --git a/man/man1/.cvsignore b/man/man1/.cvsignore
deleted file mode 100644 (file)
index 282522d..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-Makefile
-Makefile.in
diff --git a/scripts/.cvsignore b/scripts/.cvsignore
deleted file mode 100644 (file)
index 282522d..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-Makefile
-Makefile.in
diff --git a/scripts/.gitignore b/scripts/.gitignore
new file mode 100644 (file)
index 0000000..a478607
--- /dev/null
@@ -0,0 +1,2 @@
+GMXRC
+GMXRC.*
diff --git a/share/.cvsignore b/share/.cvsignore
deleted file mode 100644 (file)
index 282522d..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-Makefile
-Makefile.in
diff --git a/share/html/.cvsignore b/share/html/.cvsignore
deleted file mode 100644 (file)
index 282522d..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-Makefile
-Makefile.in
diff --git a/share/html/images/.cvsignore b/share/html/images/.cvsignore
deleted file mode 100644 (file)
index 282522d..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-Makefile
-Makefile.in
diff --git a/share/html/online/.cvsignore b/share/html/online/.cvsignore
deleted file mode 100644 (file)
index 282522d..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-Makefile
-Makefile.in
diff --git a/share/template/.cvsignore b/share/template/.cvsignore
deleted file mode 100644 (file)
index 282522d..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-Makefile
-Makefile.in
diff --git a/share/template/.gitignore b/share/template/.gitignore
new file mode 100644 (file)
index 0000000..5fda576
--- /dev/null
@@ -0,0 +1,3 @@
+template
+gromacs
+Makefile.*-*
diff --git a/share/top/.cvsignore b/share/top/.cvsignore
deleted file mode 100644 (file)
index 282522d..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-Makefile
-Makefile.in
index d4db5123b1f7795788a41226340ce04b467ec228..5d8bb04c6e3090a7c605bdfcde47b2b31ae38712 100644 (file)
 �����،ߑ�߈��߆��ߜ��ߍ���ߐ�ߞ�ߚ����������׸�����߸��������
 �ߓ���ߋ�߈����ߋ���߶ߙ���ߓ���߶ߛ�ߌ���������׼���߼�������
 ���߶ߗ���ߚ���������ߓ�����ߋ���ߚ���������ߚ����׻���߯������
+�����ߐ�ߜ�����������ߞ��ߋ��ߌ������߲�ߌ������ߖ�߈�������ߑ�����ߜ��������ײ�������
 ��،ߊ����ߜ���ߋ���ߐ���߆��ߞ��߶ߔ����״���߽����
 ��������ߘ����ߙ������ߓ����ߐ�ߓ�����ߐ����׽����ߺ���߯����
diff --git a/share/tutor/.cvsignore b/share/tutor/.cvsignore
deleted file mode 100644 (file)
index 282522d..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-Makefile
-Makefile.in
diff --git a/share/tutor/gmxdemo/.cvsignore b/share/tutor/gmxdemo/.cvsignore
deleted file mode 100644 (file)
index 282522d..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-Makefile
-Makefile.in
diff --git a/share/tutor/methanol/.cvsignore b/share/tutor/methanol/.cvsignore
deleted file mode 100644 (file)
index 282522d..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-Makefile
-Makefile.in
diff --git a/share/tutor/mixed/.cvsignore b/share/tutor/mixed/.cvsignore
deleted file mode 100644 (file)
index 282522d..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-Makefile
-Makefile.in
diff --git a/share/tutor/nmr1/.cvsignore b/share/tutor/nmr1/.cvsignore
deleted file mode 100644 (file)
index 282522d..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-Makefile
-Makefile.in
diff --git a/share/tutor/nmr2/.cvsignore b/share/tutor/nmr2/.cvsignore
deleted file mode 100644 (file)
index 282522d..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-Makefile
-Makefile.in
diff --git a/share/tutor/speptide/.cvsignore b/share/tutor/speptide/.cvsignore
deleted file mode 100644 (file)
index 282522d..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-Makefile
-Makefile.in
diff --git a/share/tutor/water/.cvsignore b/share/tutor/water/.cvsignore
deleted file mode 100644 (file)
index 282522d..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-Makefile
-Makefile.in
diff --git a/src/.cvsignore b/src/.cvsignore
deleted file mode 100644 (file)
index 98a0226..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-Makefile
-Makefile.in
-stamp-h.in
-stamp-h
-config.h
-config.h.in
index e802e652df282e88f0f70f763f03b69a86fcce59..d89435364ee004385ec5dfa783140efcb839b3ce 100644 (file)
@@ -1,9 +1,8 @@
 configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.cmakein ${CMAKE_CURRENT_BINARY_DIR}/config.h)
 
-
-add_subdirectory(gmxlib)
-add_subdirectory(mdlib)
+add_subdirectory(gromacs)
 add_subdirectory(kernel)
+add_subdirectory(programs)
 
 if(NOT GMX_FAHCORE)
   add_subdirectory(tools)
index 6b51da84d4f6af7397cb6e3220cc936a732fd0c4..2380b240c98ccd15a3c5a0ade5c9fca0dd6bd7e0 100644 (file)
@@ -10,6 +10,9 @@
 #pragma warning (disable : 4090)
 #endif
 
+/* Source directory for accessing test data */
+#define SOURCE_DIR "@CMAKE_SOURCE_DIR@"
+
 /* Name of package (translate from cmake to autoconf macro name) */
 #define PACKAGE  "@PROJECT_NAME@"
 
diff --git a/src/contrib/.cvsignore b/src/contrib/.cvsignore
deleted file mode 100644 (file)
index eccc86b..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-Makefile
-Makefile.in
-.deps
-.libs
\ No newline at end of file
diff --git a/src/gmxlib/.cvsignore b/src/gmxlib/.cvsignore
deleted file mode 100644 (file)
index eccc86b..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-Makefile
-Makefile.in
-.deps
-.libs
\ No newline at end of file
diff --git a/src/gmxlib/.gitignore b/src/gmxlib/.gitignore
deleted file mode 100644 (file)
index ca9a96b..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-.deps
-.libs
-version.c
diff --git a/src/gmxlib/CMakeLists.txt b/src/gmxlib/CMakeLists.txt
deleted file mode 100644 (file)
index 42def36..0000000
+++ /dev/null
@@ -1,155 +0,0 @@
-include_directories(${CMAKE_CURRENT_SOURCE_DIR})
-
-
-# add target that generates version.c every time a make is run
-# only do this if we generate the version
-if(USE_VERSION_H)
-    add_custom_target(gmx_version ALL
-            COMMAND ${CMAKE_COMMAND} 
-                -D Git_EXECUTABLE="${Git_EXECUTABLE}"
-                -D Git_VERSION="${Git_VERSION}"
-                -D PROJECT_VERSION="${PROJECT_VERSION}"
-                -D PROJECT_SOURCE_DIR="${PROJECT_SOURCE_DIR}"
-                -D VERSION_C_CMAKEIN="${CMAKE_SOURCE_DIR}/src/gmxlib/version.c.cmakein"
-                -D VERSION_C_OUT="${CMAKE_CURRENT_BINARY_DIR}/version.c"
-                -P ${CMAKE_SOURCE_DIR}/cmake/gmxGenerateVersionInfo.cmake 
-            WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/src/gmxlib 
-            DEPENDS ${CMAKE_SOURCE_DIR}/src/gmxlib/version.c.cmakein
-            COMMENT "Generating version information")
-endif()
-
-# The nonbonded directory contains subdirectories that are only
-# conditionally built, so we cannot use a GLOB_RECURSE here.
-file(GLOB GMXLIB_SOURCES *.c 
-     selection/*.c trajana/*.c
-     statistics/*.c nonbonded/*.c nonbonded/nb_kernel_c/*.c)
-
-# This source file is generated
-file(GLOB VERSION_SOURCE version.c)
-
-if(VERSION_SOURCE)
-       list(REMOVE_ITEM GMXLIB_SOURCES ${VERSION_SOURCE})
-endif(VERSION_SOURCE)
-
-# add version.c to the list of sources and tell cmake that it is generated
-if(USE_VERSION_H)
-LIST(APPEND GMXLIB_SOURCES ${CMAKE_CURRENT_BINARY_DIR}/version.c) # auto-generated
-set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/version.c 
-                PROPERTIES GENERATED true)
-endif()
-
-if(GMX_DOUBLE)
-  set(SSETYPE sse2)
-else()
-  set(SSETYPE sse)
-endif()
-
-if(GMX_IA32_ASM)
-  file(GLOB GMX_SSEKERNEL_C_SRC   nonbonded/nb_kernel_ia32_${SSETYPE}/*.c)
-  if(GMX_ASM_USEASM-NASM)
-    file(GLOB GMX_SSEKERNEL_ASM_SRC nonbonded/nb_kernel_ia32_${SSETYPE}/*intel_syntax*.s)    
-  else()
-    file(GLOB GMX_SSEKERNEL_ASM_SRC nonbonded/nb_kernel_ia32_${SSETYPE}/*${SSETYPE}.s nonbonded/nb_kernel_ia32_${SSETYPE}/*asm.s)
-  endif()
-endif(GMX_IA32_ASM)
-
-if(GMX_X86_64_ASM)
-  file(GLOB GMX_SSEKERNEL_C_SRC   nonbonded/nb_kernel_x86_64_${SSETYPE}/*.c)
-  if(GMX_ASM_USEASM-NASM)
-    file(GLOB GMX_SSEKERNEL_ASM_SRC nonbonded/nb_kernel_x86_64_${SSETYPE}/*intel_syntax*.s)
-  else()
-    file(GLOB GMX_SSEKERNEL_ASM_SRC nonbonded/nb_kernel_x86_64_${SSETYPE}/*${SSETYPE}.s nonbonded/nb_kernel_x86_64_${SSETYPE}/*asm.s)
-  endif()
-endif(GMX_X86_64_ASM)
-
-if(GMX_FORTRAN)
-  if (GMX_DOUBLE)
-    file(GLOB FORTRAN_SOURCES nonbonded/nb_kernel_f77_double/*.[cf])
-  else(GMX_DOUBLE)
-    file(GLOB FORTRAN_SOURCES nonbonded/nb_kernel_f77_single/*.[cf])
-  endif(GMX_DOUBLE)
-endif(GMX_FORTRAN)
-
-if(GMX_POWER6)
-  file(GLOB FORTRAN_SOURCES nonbonded/nb_kernel_power6/*.[cF])
-endif(GMX_POWER6)
-
-if(GMX_BLUEGENE)
-  file(GLOB GMX_BLUEGENE_C_SRC nonbonded/nb_kernel_bluegene/*.c)
-endif(GMX_BLUEGENE)
-
-if(GMX_PPC_ALTIVEC)
-  file(GLOB GMX_PPC_ALTIVEC_SRC nonbonded/nb_kernel_ppc_altivec/*.c)
-endif(GMX_PPC_ALTIVEC)
-
-if(NOT GMX_EXTERNAL_BLAS)
-  file(GLOB BLAS_SOURCES gmx_blas/*.c)
-endif(NOT GMX_EXTERNAL_BLAS)
-
-if(NOT GMX_EXTERNAL_LAPACK)
-  file(GLOB LAPACK_SOURCES gmx_lapack/*.c)
-endif(NOT GMX_EXTERNAL_LAPACK)
-
-# This would be the standard way to include thread_mpi, but we want libgmx
-# to link the functions directly
-#if(GMX_THREADS)
-#    add_subdirectory(thread_mpi)
-#endif(GMX_THREADS)
-#target_link_libraries(gmx ${GMX_EXTRA_LIBRARIES} ${THREAD_MPI_LIB})
-
-# Files called xxx_test.c are test drivers with a main() function for module xxx.c,
-# so they should not be included in the library
-file(GLOB_RECURSE NOT_GMXLIB_SOURCES *_test.c *\#*)
-list(REMOVE_ITEM GMXLIB_SOURCES ${NOT_GMXLIB_SOURCES})  
-# Selection has test_ instead of _test.  Removing here for special case, perhaps make general?
-if(GMX_FAHCORE)
-    file(GLOB SELECTION_TEST selection/test*)
-    list(REMOVE_ITEM GMXLIB_SOURCES ${SELECTION_TEST})
-endif(GMX_FAHCORE)
-
-# only fiddle with assembly kernels if we're not doing OpenMM build
-if(NOT GMX_OPENMM) 
-if(GMX_ASM_USEASM-NASM)
-  enable_language(ASM-NASM)
-
-  # if NASM is used, we need a special build command for windows...
-  FOREACH(SRC ${GMX_SSEKERNEL_ASM_SRC})
-    GET_FILENAME_COMPONENT(FILE_BASE ${SRC} NAME_WE)
-    SET(OBJ ${CMAKE_CURRENT_BINARY_DIR}/${FILE_BASE}${CMAKE_C_OUTPUT_EXTENSION})
-
-    ADD_CUSTOM_COMMAND(OUTPUT ${OBJ}
-                       MAIN_DEPENDENCY ${SRC}
-                       COMMAND ${CMAKE_ASM-NASM_COMPILER} -f ${CMAKE_ASM-NASM_OBJECT_FORMAT} -o ${OBJ} ${SRC})
-
-    SET(ALL_ASM_OBJS ${ALL_ASM_OBJS} ${OBJ})
-  ENDFOREACH(SRC ${GMX_SSEKERNEL_ASM_SRC})
-  set(GMX_SSEKERNEL_ASM_SRC ${ALL_ASM_OBJS})
-
-else(GMX_ASM_USEASM-NASM)
-
-  enable_language(ASM-ATT)
-  SET(CMAKE_ASM-ATT_COMPILER ${CMAKE_C_COMPILER})
-  if(GMX_IA32_ASM)
-    set_source_files_properties(${GMX_SSEKERNEL_ASM_SRC} PROPERTIES COMPILE_FLAGS "-c -m32")
-  else()
-    set_source_files_properties(${GMX_SSEKERNEL_ASM_SRC} PROPERTIES COMPILE_FLAGS "-c -m64")
-  endif()
-
-endif(GMX_ASM_USEASM-NASM)
-endif(NOT GMX_OPENMM)
-
-add_library(gmx ${GMXLIB_SOURCES} ${BLAS_SOURCES} ${LAPACK_SOURCES} ${GMX_SSEKERNEL_C_SRC} ${GMX_SSEKERNEL_ASM_SRC} ${FORTRAN_SOURCES} ${GMX_BLUEGENE_C_SRC} ${GMX_PPC_ALTIVEC_SRC} ${THREAD_MPI_SRC})
-target_link_libraries(gmx ${GMX_EXTRA_LIBRARIES}  ${THREAD_LIB})
-if(USE_VERSION_H)
-       add_dependencies(gmx gmx_version) 
-endif()
-set_target_properties(gmx PROPERTIES OUTPUT_NAME "gmx${GMX_LIBS_SUFFIX}" SOVERSION ${SOVERSION} INSTALL_NAME_DIR "${LIB_INSTALL_DIR}")
-
-install(TARGETS gmx DESTINATION ${LIB_INSTALL_DIR} COMPONENT libraries)
-
-configure_file(${CMAKE_CURRENT_SOURCE_DIR}/libgmx.pc.cmakein ${CMAKE_CURRENT_BINARY_DIR}/libgmx.pc @ONLY)
-install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libgmx.pc
-        DESTINATION ${LIB_INSTALL_DIR}/pkgconfig
-        RENAME "libgmx${GMX_LIBS_SUFFIX}.pc"
-        COMPONENT development)
-
diff --git a/src/gmxlib/Makefile.am b/src/gmxlib/Makefile.am
deleted file mode 100644 (file)
index ce33235..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-
-## Process this file with automake to produce Makefile.in
-# Note: Makefile is automatically generated from Makefile.in by the configure
-# script, and Makefile.in is generated from Makefile.am by automake.
-
-if !GMX_EXTERNAL_BLAS
-  BLAS_DIR       = gmx_blas
-  BLAS_LIBOBJS   = gmx_blas/libblas.la       
-endif
-
-if !GMX_EXTERNAL_LAPACK
-  LAPACK_DIR     = gmx_lapack
-  LAPACK_LIBOBJS = gmx_lapack/liblapack.la
-endif
-
-if THREAD_PARALLEL
-    THREAD_MPI_LIBOBJS = thread_mpi/libthread_mpi.la 
-    THREAD_MPI_DIR     = thread_mpi
-endif
-
-
-SUBDIRS = nonbonded selection statistics trajana $(THREAD_MPI_DIR) \
-         $(BLAS_DIR) $(LAPACK_DIR)
-
-AM_CPPFLAGS= -I$(top_srcdir)/include -DGMXLIBDIR=\"$(datadir)/top\"
-
-lib_LTLIBRARIES = libgmx@LIBSUFFIX@.la
-
-#
-# Use a utility library for all the nonbonded kernels and wrapper routines.
-#
-libgmx@LIBSUFFIX@_la_LIBADD =       nonbonded/libnonbonded.la         \
-                                   selection/libselection.la \
-                                   statistics/libstatistics.la \
-                                   trajana/libtrajana.la \
-                                   $(THREAD_MPI_LIBOBJS) \
-                                   $(BLAS_LIBOBJS) $(LAPACK_LIBOBJS)
-
-libgmx@LIBSUFFIX@_la_DEPENDENCIES = nonbonded/libnonbonded.la         \
-                                   selection/libselection.la \
-                                   statistics/libstatistics.la \
-                                   trajana/libtrajana.la \
-                                   $(THREAD_MPI_LIBOBJS) \
-                                   $(BLAS_LIBOBJS) $(LAPACK_LIBOBJS)
-
-#      
-#
-libgmx@LIBSUFFIX@_la_LDFLAGS = -no-undefined -version-info @SHARED_VERSION_INFO@ @DLOPEN_LIBS@ $(PTHREAD_LIBS)
-
-libgmx@LIBSUFFIX@_la_SOURCES = \
-       3dview.c        atomprop.c      bondfree.c      \
-       calcgrid.c      calch.c         chargegroup.c   checkpoint.c    \
-       confio.c        copyrite.c      disre.c         do_fit.c        \
-       enxio.c         ewald_util.c    ffscanf.c       \
-       filenm.c        futil.c         gbutil.c        gmx_fatal.c     \
-       gmx_sort.c      gmxcpp.c \
-       gmxfio.c        ifunc.c         index.c         inputrec.c      \
-       cinvsqrtdata.c  \
-       invblock.c      macros.c        orires.c        sparsematrix.c  \
-       main.c          maths.c         matio.c         mshift.c        \
-       mtop_util.c     mtxio.c         mvdata.c        names.c         \
-       network.c       nrama.c         nrjac.c         nrnb.c          \
-       pargs.c         pbc.c           pdbio.c         princ.c         \
-       rando.c         random.c        gmx_random.c    rbin.c          \
-       readinp.c       replace.c       rmpbc.c         shift_util.c    \
-       sortwater.c     smalloc.c       statutil.c      sfactor.c       \
-       strdb.c         string2.c       symtab.c        \
-       topsort.c       tpxio.c         \
-       trnio.c         trxio.c         txtdump.c       typedefs.c      \
-       viewit.c        warninp.c       \
-       wgms.c          wman.c          writeps.c       \
-       xdrd.c          xtcio.c         xvgr.c          replace.h       \
-       libxdrf.c       gmx_arpack.c    gmx_matrix.c            \
-       dihres.c        gmx_random_gausstable.h gmxfio_int.h\
-       tcontrol.c      splitter.c      gmx_cyclecounter.c              \
-       gmx_system_xdr.c md5.c vmdio.c vmddlopen.c      sighandler.c    \
-       oenv.c          gmxfio_rw.c     gmxfio_asc.c    gmxfio_bin.c    \
-       gmxfio_xdr.c
-
-pkgconfigdir = ${libdir}/pkgconfig
-pkgconfig_DATA = libgmx@LIBSUFFIX@.pc
-
-# clean all libtool libraries, since the target names might have changed
-CLEANFILES     = *.la *~ \\\#* innerc.c innerf.f mkinl
-
-if USE_VERSION_H
-#version.c contains generated git version information
-libgmx@LIBSUFFIX@_la_SOURCES += version.c
-CLEANFILES += version.c
-#The empty target FORCE forces make to run the command every time. But
-#version.c is only changed if the version actually has changed, and hence
-#rebuilds are only triggered when they are needed.
-version.c: FORCE
-       $(top_srcdir)/src/gmxlib/genversion.sh @VERSION@ $(top_srcdir)
-FORCE:
-endif
-
-EXTRA_DIST = version.h libgmx.pc.cmakein
diff --git a/src/gmxlib/gmx_blas/.gitignore b/src/gmxlib/gmx_blas/.gitignore
deleted file mode 100644 (file)
index 96381e2..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-.libs
-.deps
diff --git a/src/gmxlib/gmx_blas/Makefile.am b/src/gmxlib/gmx_blas/Makefile.am
deleted file mode 100644 (file)
index d25cb1d..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-# Convenience library for optional built-in BLAS routines - not installed.
-
-AM_CPPFLAGS= -I$(top_srcdir)/include 
-
-
-noinst_LTLIBRARIES = libblas.la
-
-libblas_la_SOURCES =   \
-       dasum.c         dcopy.c         dgemm.c         dger.c          \
-       drot.c          dswap.c         dsyr2.c         dtrmm.c         \
-       dtrsm.c         daxpy.c         ddot.c          dgemv.c         \
-       dnrm2.c         dscal.c         dsymv.c         dsyr2k.c        \
-       dtrmv.c         idamax.c                                        \
-       sasum.c         scopy.c         sgemm.c         sger.c          \
-       srot.c          sswap.c         ssyr2.c         strmm.c         \
-       strsm.c         saxpy.c         sdot.c          sgemv.c         \
-       snrm2.c         sscal.c         ssymv.c         ssyr2k.c        \
-       strmv.c         isamax.c                                        
-
-EXTRA_DIST = blas_copyright
-
-CLEANFILES     = *.la *~ \\\#* 
diff --git a/src/gmxlib/gmx_lapack/Makefile.am b/src/gmxlib/gmx_lapack/Makefile.am
deleted file mode 100644 (file)
index 3d18bf3..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-# Convenience library for optional built-in LAPACK routines - not installed.
-
-AM_CPPFLAGS= -I$(top_srcdir)/include
-
-
-noinst_LTLIBRARIES = liblapack.la
-
-liblapack_la_SOURCES = \
-       dbdsdc.c dgetf2.c dlamrg.c dlarnv.c dlasd0.c dlasda.c dlasq6.c \
-       dorgl2.c dormqr.c dbdsqr.c dgetrf.c dlange.c dlasd1.c dtrtri.c \
-       dlasdq.c dlasr.c  dorglq.c dormtr.c dgebd2.c dlabrd.c dlanst.c \
-       dlasd2.c dlasdt.c dlasrt.c dorgqr.c dstebz.c dgebrd.c dsytrd.c \
-       dlacpy.c dlapy2.c dlasd3.c dlaset.c dlassq.c dorm2l.c dgetrs.c \
-       dstegr.c dgelq2.c dlae2.c  dlasd4.c dlasq1.c dtrti2.c dgetri.c \
-       dlasv2.c dorm2r.c dstein.c dgelqf.c dlaebz.c dlarf.c  dlartg.c \
-       dlasd5.c dlasq2.c dlaswp.c dormbr.c dsterf.c dgeqr2.c dlaed6.c \
-       dlarfb.c dlaruv.c dlasd6.c dlasq3.c dlatrd.c dorml2.c dstevr.c \
-       dgeqrf.c dlagtf.c dlarfg.c dlas2.c  dlasd7.c dlasq4.c dorg2r.c \
-       dormlq.c dsytd2.c dgesdd.c dlagts.c dlarft.c dlascl.c dlasd8.c \
-       dlasq5.c dorgbr.c dormql.c dlaev2.c dsteqr.c dsyevr.c dlasrt2.c \
-       dlansy.c                                                        \
-       dlar1vx.c         dlarrbx.c         dlarrex.c         dlarrfx.c \
-       dlarrvx.c \
-       sbdsdc.c sgetf2.c slamrg.c slarnv.c slasd0.c slasda.c slasq6.c \
-       sorgl2.c sormqr.c sbdsqr.c sgetrf.c slange.c slasd1.c ssytrd.c \
-       slasdq.c slasr.c  sorglq.c sormtr.c sgebd2.c slabrd.c slanst.c \
-       slasd2.c slasdt.c slasrt.c sorgqr.c sstebz.c sgebrd.c sgetrs.c \
-       slacpy.c slapy2.c slasd3.c slaset.c slassq.c sorm2l.c sgetri.c \
-       sstegr.c sgelq2.c slae2.c  slasd4.c slasq1.c strti2.c strtri.c \
-       slasv2.c sorm2r.c sstein.c sgelqf.c slaebz.c slarf.c  slartg.c \
-       slasd5.c slasq2.c slaswp.c sormbr.c ssterf.c sgeqr2.c slaed6.c \
-       slarfb.c slaruv.c slasd6.c slasq3.c slatrd.c sorml2.c sstevr.c \
-       sgeqrf.c slagtf.c slarfg.c slas2.c  slasd7.c slasq4.c sorg2r.c \
-       sormlq.c ssytd2.c sgesdd.c slagts.c slarft.c slascl.c slasd8.c \
-       slasq5.c sorgbr.c sormql.c slaev2.c ssteqr.c ssyevr.c slasrt2.c \
-       slansy.c                                                        \
-       slar1vx.c         slarrbx.c         slarrex.c         slarrfx.c \
-        slarrvx.c \
-       ilasrt2.c lapack_limits.h
-
-EXTRA_DIST = lapack_copyright
-
-CLEANFILES     = *.la *~ \\\#* 
diff --git a/src/gmxlib/libgmx.pc.cmakein b/src/gmxlib/libgmx.pc.cmakein
deleted file mode 100644 (file)
index ef01693..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-libdir=@LIB_INSTALL_DIR@
-includedir=@INCL_INSTALL_DIR@
-
-Name: libgmx
-Description: Gromacs default lib
-URL: http://www.gromacs.org
-Version: @PROJECT_VERSION@
-Requires:
-Libs.private: -lm @CMAKE_THREAD_LIBS_INIT@
-Libs: -L${libdir} -lgmx@LIBSUFFIX@
-Cflags: -I${includedir} @PKG_CFLAGS@
-
diff --git a/src/gmxlib/libgmx.pc.in b/src/gmxlib/libgmx.pc.in
deleted file mode 100644 (file)
index e954f89..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-prefix=@prefix@
-exec_prefix=@exec_prefix@
-libdir=@libdir@
-includedir=@includedir@
-
-Name: libgmx
-Description: Gromacs default lib
-URL: http://www.gromacs.org
-Version: @VERSION@
-Requires:
-Libs: -L${libdir} -lgmx@LIBSUFFIX@ @PTHREAD_CFLAGS@ @PTHREAD_LIBS@ -lm
-Cflags: -I${includedir} @PTHREAD_CFLAGS@ @PKG_CFLAGS@ 
-
diff --git a/src/gmxlib/mvdata.c b/src/gmxlib/mvdata.c
deleted file mode 100644 (file)
index e25baaf..0000000
+++ /dev/null
@@ -1,568 +0,0 @@
-/* -*- mode: c; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; c-file-style: "stroustrup"; -*-
- * 
- *                This source code is part of
- * 
- *                 G   R   O   M   A   C   S
- * 
- *          GROningen MAchine for Chemical Simulations
- * 
- *                        VERSION 3.2.0
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
- * 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.
-
- * 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:
- * GROningen Mixture of Alchemy and Childrens' Stories
- */
-/* This file is completely threadsafe - keep it that way! */
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <sysstuff.h>
-#include <string.h>
-#include "typedefs.h"
-#include "main.h"
-#include "mvdata.h"
-#include "network.h"
-#include "smalloc.h"
-#include "gmx_fatal.h"
-#include "symtab.h"
-#include "vec.h"
-#include "tgroup.h"
-
-#define   block_bc(cr,   d) gmx_bcast(     sizeof(d),     &(d),(cr))
-/* Probably the test for (nr) > 0 in the next macro is only needed
- * on BlueGene(/L), where IBM's MPI_Bcast will segfault after
- * dereferencing a null pointer, even when no data is to be transferred. */
-#define  nblock_bc(cr,nr,d) { if ((nr) > 0) gmx_bcast((nr)*sizeof((d)[0]), (d),(cr)); }
-#define    snew_bc(cr,d,nr) { if (!MASTER(cr)) snew((d),(nr)); }
-/* Dirty macro with bAlloc not as an argument */
-#define nblock_abc(cr,nr,d) { if (bAlloc) snew((d),(nr)); nblock_bc(cr,(nr),(d)); }
-
-static void bc_string(const t_commrec *cr,t_symtab *symtab,char ***s)
-{
-  int handle;
-  
-  if (MASTER(cr)) {
-    handle = lookup_symtab(symtab,*s);
-  }
-  block_bc(cr,handle);
-  if (!MASTER(cr)) {
-    *s = get_symtab_handle(symtab,handle);
-  }
-}
-
-static void bc_strings(const t_commrec *cr,t_symtab *symtab,int nr,char ****nm)
-{
-  int  i;
-  int  *handle;
-  char ***NM;
-
-  snew(handle,nr);
-  if (MASTER(cr)) {
-    NM = *nm;
-    for(i=0; (i<nr); i++)
-      handle[i] = lookup_symtab(symtab,NM[i]);
-  }
-  nblock_bc(cr,nr,handle);
-
-  if (!MASTER(cr)) {
-    snew_bc(cr,*nm,nr);
-    NM = *nm;
-    for (i=0; (i<nr); i++) 
-      (*nm)[i] = get_symtab_handle(symtab,handle[i]);
-  }
-  sfree(handle);
-}
-
-static void bc_strings_resinfo(const t_commrec *cr,t_symtab *symtab,
-                              int nr,t_resinfo *resinfo)
-{
-  int  i;
-  int  *handle;
-
-  snew(handle,nr);
-  if (MASTER(cr)) {
-    for(i=0; (i<nr); i++)
-      handle[i] = lookup_symtab(symtab,resinfo[i].name);
-  }
-  nblock_bc(cr,nr,handle);
-
-  if (!MASTER(cr)) {
-    for (i=0; (i<nr); i++) 
-      resinfo[i].name = get_symtab_handle(symtab,handle[i]);
-  }
-  sfree(handle);
-}
-
-static void bc_symtab(const t_commrec *cr,t_symtab *symtab)
-{
-  int i,nr,len;
-  t_symbuf *symbuf;
-
-  block_bc(cr,symtab->nr);
-  nr = symtab->nr;
-  snew_bc(cr,symtab->symbuf,1);
-  symbuf = symtab->symbuf;
-  symbuf->bufsize = nr;
-  snew_bc(cr,symbuf->buf,nr);
-  for (i=0; i<nr; i++) {
-    if (MASTER(cr))
-      len = strlen(symbuf->buf[i]) + 1;
-    block_bc(cr,len);
-    snew_bc(cr,symbuf->buf[i],len);
-    nblock_bc(cr,len,symbuf->buf[i]);
-  }
-}
-
-static void bc_block(const t_commrec *cr,t_block *block)
-{
-  block_bc(cr,block->nr);
-  snew_bc(cr,block->index,block->nr+1);
-  nblock_bc(cr,block->nr+1,block->index);
-}
-
-static void bc_blocka(const t_commrec *cr,t_blocka *block)
-{
-  block_bc(cr,block->nr);
-  snew_bc(cr,block->index,block->nr+1);
-  nblock_bc(cr,block->nr+1,block->index);
-  block_bc(cr,block->nra);
-  if (block->nra) {
-    snew_bc(cr,block->a,block->nra);
-    nblock_bc(cr,block->nra,block->a);
-  }
-}
-
-static void bc_grps(const t_commrec *cr,t_grps grps[])
-{
-  int i;
-  
-  for(i=0; (i<egcNR); i++) {
-    block_bc(cr,grps[i].nr);
-    snew_bc(cr,grps[i].nm_ind,grps[i].nr);
-    nblock_bc(cr,grps[i].nr,grps[i].nm_ind);
-  }
-}
-
-static void bc_atoms(const t_commrec *cr,t_symtab *symtab,t_atoms *atoms)
-{
-  int dummy;
-
-  block_bc(cr,atoms->nr);
-  snew_bc(cr,atoms->atom,atoms->nr);
-  nblock_bc(cr,atoms->nr,atoms->atom);
-  bc_strings(cr,symtab,atoms->nr,&atoms->atomname);
-  block_bc(cr,atoms->nres);
-  snew_bc(cr,atoms->resinfo,atoms->nres);
-  nblock_bc(cr,atoms->nres,atoms->resinfo);
-  bc_strings_resinfo(cr,symtab,atoms->nres,atoms->resinfo);
-  /* QMMM requires atomtypes to be known on all nodes as well */
-  bc_strings(cr,symtab,atoms->nr,&atoms->atomtype);
-  bc_strings(cr,symtab,atoms->nr,&atoms->atomtypeB);
-}
-
-static void bc_groups(const t_commrec *cr,t_symtab *symtab,
-                     int natoms,gmx_groups_t *groups)
-{
-  int dummy;
-  int g,n;
-
-  bc_grps(cr,groups->grps);
-  block_bc(cr,groups->ngrpname);
-  bc_strings(cr,symtab,groups->ngrpname,&groups->grpname);
-  for(g=0; g<egcNR; g++) {
-    if (MASTER(cr)) {
-      if (groups->grpnr[g]) {
-       n = natoms;
-      } else {
-       n = 0;
-      }
-    }
-    block_bc(cr,n);
-    if (n == 0) {
-      groups->grpnr[g] = NULL;
-    } else {
-      snew_bc(cr,groups->grpnr[g],n);
-      nblock_bc(cr,n,groups->grpnr[g]);
-    }
-  }
-  if (debug) fprintf(debug,"after bc_groups\n");
-}
-
-void bcast_state_setup(const t_commrec *cr,t_state *state)
-{
-  block_bc(cr,state->natoms);
-  block_bc(cr,state->ngtc);
-  block_bc(cr,state->nnhpres);
-  block_bc(cr,state->nhchainlength);
-  block_bc(cr,state->nrng);
-  block_bc(cr,state->nrngi);
-  block_bc(cr,state->flags);
-}
-
-void bcast_state(const t_commrec *cr,t_state *state,gmx_bool bAlloc)
-{
-  int i,nnht,nnhtp;
-
-  bcast_state_setup(cr,state);
-
-  nnht = (state->ngtc)*(state->nhchainlength); 
-  nnhtp = (state->nnhpres)*(state->nhchainlength); 
-
-  if (MASTER(cr)) {
-    bAlloc = FALSE;
-  }
-  if (bAlloc) {
-    state->nalloc = state->natoms;
-  }
-  for(i=0; i<estNR; i++) {
-    if (state->flags & (1<<i)) {
-      switch (i) {
-      case estLAMBDA:  block_bc(cr,state->lambda); break;
-      case estBOX:     block_bc(cr,state->box); break;
-      case estBOX_REL: block_bc(cr,state->box_rel); break;
-      case estBOXV:    block_bc(cr,state->boxv); break;
-      case estPRES_PREV: block_bc(cr,state->pres_prev); break;
-      case estSVIR_PREV: block_bc(cr,state->svir_prev); break;
-      case estFVIR_PREV: block_bc(cr,state->fvir_prev); break;
-      case estNH_XI:   nblock_abc(cr,nnht,state->nosehoover_xi); break;
-      case estNH_VXI:  nblock_abc(cr,nnht,state->nosehoover_vxi); break;
-      case estNHPRES_XI:   nblock_abc(cr,nnhtp,state->nhpres_xi); break;
-      case estNHPRES_VXI:  nblock_abc(cr,nnhtp,state->nhpres_vxi); break;
-      case estTC_INT:  nblock_abc(cr,state->ngtc,state->therm_integral); break;
-      case estVETA:    block_bc(cr,state->veta); break;
-      case estVOL0:    block_bc(cr,state->vol0); break;
-      case estX:       nblock_abc(cr,state->natoms,state->x); break;
-      case estV:       nblock_abc(cr,state->natoms,state->v); break;
-      case estSDX:     nblock_abc(cr,state->natoms,state->sd_X); break;
-      case estCGP:     nblock_abc(cr,state->natoms,state->cg_p); break;
-         case estLD_RNG:  if(state->nrngi == 1) nblock_abc(cr,state->nrng,state->ld_rng); break;
-         case estLD_RNGI: if(state->nrngi == 1) nblock_abc(cr,state->nrngi,state->ld_rngi); break;
-      case estDISRE_INITF: block_bc(cr,state->hist.disre_initf); break;
-      case estDISRE_RM3TAV:
-          block_bc(cr,state->hist.ndisrepairs);
-          nblock_abc(cr,state->hist.ndisrepairs,state->hist.disre_rm3tav);
-          break;
-      case estORIRE_INITF: block_bc(cr,state->hist.orire_initf); break;
-      case estORIRE_DTAV:
-          block_bc(cr,state->hist.norire_Dtav);
-          nblock_abc(cr,state->hist.norire_Dtav,state->hist.orire_Dtav);
-          break;
-      default:
-          gmx_fatal(FARGS,
-                    "Communication is not implemented for %s in bcast_state",
-                    est_names[i]);
-      }
-    }
-  }
-}
-
-static void bc_ilists(const t_commrec *cr,t_ilist *ilist)
-{
-  int ftype;
-
-  /* Here we only communicate the non-zero length ilists */
-  if (MASTER(cr)) {
-    for(ftype=0; ftype<F_NRE; ftype++) {
-      if (ilist[ftype].nr > 0) {
-       block_bc(cr,ftype);
-       block_bc(cr,ilist[ftype].nr);
-       nblock_bc(cr,ilist[ftype].nr,ilist[ftype].iatoms);
-      }
-    }
-    ftype = -1;
-    block_bc(cr,ftype);
-  } else {
-    for(ftype=0; ftype<F_NRE; ftype++) {
-      ilist[ftype].nr = 0;
-    }
-    do {
-      block_bc(cr,ftype);
-      if (ftype >= 0) {
-       block_bc(cr,ilist[ftype].nr);
-       snew_bc(cr,ilist[ftype].iatoms,ilist[ftype].nr);
-       nblock_bc(cr,ilist[ftype].nr,ilist[ftype].iatoms);
-      }
-    } while (ftype >= 0);
-  }
-
-  if (debug) fprintf(debug,"after bc_ilists\n");
-}
-
-static void bc_idef(const t_commrec *cr,t_idef *idef)
-{
-  block_bc(cr,idef->ntypes);
-  block_bc(cr,idef->atnr);
-  snew_bc(cr,idef->functype,idef->ntypes);
-  snew_bc(cr,idef->iparams,idef->ntypes);
-  nblock_bc(cr,idef->ntypes,idef->functype);
-  nblock_bc(cr,idef->ntypes,idef->iparams);
-  block_bc(cr,idef->fudgeQQ);
-  bc_ilists(cr,idef->il);
-  block_bc(cr,idef->ilsort);
-}
-
-static void bc_cmap(const t_commrec *cr, gmx_cmap_t *cmap_grid)
-{
-       int i,j,nelem,ngrid;
-       
-       block_bc(cr,cmap_grid->ngrid);
-       block_bc(cr,cmap_grid->grid_spacing);
-       
-       ngrid = cmap_grid->ngrid;
-       nelem = cmap_grid->grid_spacing * cmap_grid->grid_spacing;
-       
-       if(ngrid>0)
-       {
-               snew_bc(cr,cmap_grid->cmapdata,ngrid);
-               
-               for(i=0;i<ngrid;i++)
-               {
-                       snew_bc(cr,cmap_grid->cmapdata[i].cmap,4*nelem);
-                       nblock_bc(cr,4*nelem,cmap_grid->cmapdata[i].cmap);
-               }
-       }
-}
-
-static void bc_ffparams(const t_commrec *cr,gmx_ffparams_t *ffp)
-{
-  int i;
-  
-  block_bc(cr,ffp->ntypes);
-  block_bc(cr,ffp->atnr);
-  snew_bc(cr,ffp->functype,ffp->ntypes);
-  snew_bc(cr,ffp->iparams,ffp->ntypes);
-  nblock_bc(cr,ffp->ntypes,ffp->functype);
-  nblock_bc(cr,ffp->ntypes,ffp->iparams);
-  block_bc(cr,ffp->reppow);
-  block_bc(cr,ffp->fudgeQQ);
-  bc_cmap(cr,&ffp->cmap_grid);
-}
-
-static void bc_grpopts(const t_commrec *cr,t_grpopts *g)
-{
-    int i,n;
-    
-    block_bc(cr,g->ngtc);
-    block_bc(cr,g->ngacc);
-    block_bc(cr,g->ngfrz);
-    block_bc(cr,g->ngener);
-    snew_bc(cr,g->nrdf,g->ngtc);
-    snew_bc(cr,g->tau_t,g->ngtc);
-    snew_bc(cr,g->ref_t,g->ngtc);
-    snew_bc(cr,g->acc,g->ngacc);
-    snew_bc(cr,g->nFreeze,g->ngfrz);
-    snew_bc(cr,g->egp_flags,g->ngener*g->ngener);
-    
-    nblock_bc(cr,g->ngtc,g->nrdf);
-    nblock_bc(cr,g->ngtc,g->tau_t);
-    nblock_bc(cr,g->ngtc,g->ref_t);
-    nblock_bc(cr,g->ngacc,g->acc);
-    nblock_bc(cr,g->ngfrz,g->nFreeze);
-    nblock_bc(cr,g->ngener*g->ngener,g->egp_flags);
-    snew_bc(cr,g->annealing,g->ngtc);
-    snew_bc(cr,g->anneal_npoints,g->ngtc);
-    snew_bc(cr,g->anneal_time,g->ngtc);
-    snew_bc(cr,g->anneal_temp,g->ngtc);
-    nblock_bc(cr,g->ngtc,g->annealing);
-    nblock_bc(cr,g->ngtc,g->anneal_npoints);
-    for(i=0;(i<g->ngtc); i++) {
-        n = g->anneal_npoints[i];
-        if (n > 0) {
-         snew_bc(cr,g->anneal_time[i],n);
-         snew_bc(cr,g->anneal_temp[i],n);
-         nblock_bc(cr,n,g->anneal_time[i]);
-         nblock_bc(cr,n,g->anneal_temp[i]);
-        }
-    }
-    
-    /* QMMM stuff, see inputrec */
-    block_bc(cr,g->ngQM);
-    snew_bc(cr,g->QMmethod,g->ngQM);
-    snew_bc(cr,g->QMbasis,g->ngQM);
-    snew_bc(cr,g->QMcharge,g->ngQM);
-    snew_bc(cr,g->QMmult,g->ngQM);
-    snew_bc(cr,g->bSH,g->ngQM);
-    snew_bc(cr,g->CASorbitals,g->ngQM);
-    snew_bc(cr,g->CASelectrons,g->ngQM);
-    snew_bc(cr,g->SAon,g->ngQM);
-    snew_bc(cr,g->SAoff,g->ngQM);
-    snew_bc(cr,g->SAsteps,g->ngQM);
-    
-    if (g->ngQM)
-    {
-        nblock_bc(cr,g->ngQM,g->QMmethod);
-        nblock_bc(cr,g->ngQM,g->QMbasis);
-        nblock_bc(cr,g->ngQM,g->QMcharge);
-        nblock_bc(cr,g->ngQM,g->QMmult);
-        nblock_bc(cr,g->ngQM,g->bSH);
-        nblock_bc(cr,g->ngQM,g->CASorbitals);
-        nblock_bc(cr,g->ngQM,g->CASelectrons);
-        nblock_bc(cr,g->ngQM,g->SAon);
-        nblock_bc(cr,g->ngQM,g->SAoff);
-        nblock_bc(cr,g->ngQM,g->SAsteps);
-        /* end of QMMM stuff */
-    }
-}
-
-static void bc_cosines(const t_commrec *cr,t_cosines *cs)
-{
-  block_bc(cr,cs->n);
-  snew_bc(cr,cs->a,cs->n);
-  snew_bc(cr,cs->phi,cs->n);
-  if (cs->n > 0) {
-    nblock_bc(cr,cs->n,cs->a);
-    nblock_bc(cr,cs->n,cs->phi);
-  }
-}
-
-static void bc_pullgrp(const t_commrec *cr,t_pullgrp *pgrp)
-{
-  block_bc(cr,*pgrp);
-  if (pgrp->nat > 0) {
-    snew_bc(cr,pgrp->ind,pgrp->nat);
-    nblock_bc(cr,pgrp->nat,pgrp->ind);
-  }
-  if (pgrp->nweight > 0) {
-    snew_bc(cr,pgrp->weight,pgrp->nweight);
-    nblock_bc(cr,pgrp->nweight,pgrp->weight);
-  }
-}
-
-static void bc_pull(const t_commrec *cr,t_pull *pull)
-{
-  int g;
-
-  block_bc(cr,*pull);
-  snew_bc(cr,pull->grp,pull->ngrp+1);
-  for(g=0; g<pull->ngrp+1; g++)
-  {
-      bc_pullgrp(cr,&pull->grp[g]);
-  }
-}
-
-static void bc_inputrec(const t_commrec *cr,t_inputrec *inputrec)
-{
-  gmx_bool bAlloc=TRUE;
-  int i;
-  
-  block_bc(cr,*inputrec);
-  snew_bc(cr,inputrec->flambda,inputrec->n_flambda);
-  nblock_bc(cr,inputrec->n_flambda,inputrec->flambda);
-  bc_grpopts(cr,&(inputrec->opts));
-  if (inputrec->ePull != epullNO) {
-    snew_bc(cr,inputrec->pull,1);
-    bc_pull(cr,inputrec->pull);
-  }
-  for(i=0; (i<DIM); i++) {
-    bc_cosines(cr,&(inputrec->ex[i]));
-    bc_cosines(cr,&(inputrec->et[i]));
-  }
-}
-
-static void bc_moltype(const t_commrec *cr,t_symtab *symtab,
-                      gmx_moltype_t *moltype)
-{
-  bc_string(cr,symtab,&moltype->name);
-  bc_atoms(cr,symtab,&moltype->atoms);
-  if (debug) fprintf(debug,"after bc_atoms\n");
-
-  bc_ilists(cr,moltype->ilist);
-  bc_block(cr,&moltype->cgs);
-  bc_blocka(cr,&moltype->excls);
-}
-
-static void bc_molblock(const t_commrec *cr,gmx_molblock_t *molb)
-{
-  gmx_bool bAlloc=TRUE;
-  
-  block_bc(cr,molb->type);
-  block_bc(cr,molb->nmol);
-  block_bc(cr,molb->natoms_mol);
-  block_bc(cr,molb->nposres_xA);
-  if (molb->nposres_xA > 0) {
-    snew_bc(cr,molb->posres_xA,molb->nposres_xA);
-    nblock_bc(cr,molb->nposres_xA*DIM,molb->posres_xA[0]);
-  }
-  block_bc(cr,molb->nposres_xB);
-  if (molb->nposres_xB > 0) {
-    snew_bc(cr,molb->posres_xB,molb->nposres_xB);
-    nblock_bc(cr,molb->nposres_xB*DIM,molb->posres_xB[0]);
-  }
-  if (debug) fprintf(debug,"after bc_molblock\n");
-}
-
-static void bc_atomtypes(const t_commrec *cr, t_atomtypes *atomtypes)
-{
-  int nr;
-
-  block_bc(cr,atomtypes->nr);
-
-  nr = atomtypes->nr;
-
-  snew_bc(cr,atomtypes->radius,nr);
-  snew_bc(cr,atomtypes->vol,nr);
-  snew_bc(cr,atomtypes->surftens,nr);
-  snew_bc(cr,atomtypes->gb_radius,nr);
-  snew_bc(cr,atomtypes->S_hct,nr);
-
-  nblock_bc(cr,nr,atomtypes->radius);
-  nblock_bc(cr,nr,atomtypes->vol);
-  nblock_bc(cr,nr,atomtypes->surftens);
-  nblock_bc(cr,nr,atomtypes->gb_radius);
-  nblock_bc(cr,nr,atomtypes->S_hct);
-}
-
-
-void bcast_ir_mtop(const t_commrec *cr,t_inputrec *inputrec,gmx_mtop_t *mtop)
-{
-  int i; 
-  if (debug) fprintf(debug,"in bc_data\n");
-  bc_inputrec(cr,inputrec);
-  if (debug) fprintf(debug,"after bc_inputrec\n");
-  bc_symtab(cr,&mtop->symtab);
-  if (debug) fprintf(debug,"after bc_symtab\n");
-  bc_string(cr,&mtop->symtab,&mtop->name);
-  if (debug) fprintf(debug,"after bc_name\n");
-
-  bc_ffparams(cr,&mtop->ffparams);
-
-  block_bc(cr,mtop->nmoltype);
-  snew_bc(cr,mtop->moltype,mtop->nmoltype);
-  for(i=0; i<mtop->nmoltype; i++) {
-    bc_moltype(cr,&mtop->symtab,&mtop->moltype[i]);
-  }
-
-  block_bc(cr,mtop->nmolblock);
-  snew_bc(cr,mtop->molblock,mtop->nmolblock);
-  for(i=0; i<mtop->nmolblock; i++) {
-    bc_molblock(cr,&mtop->molblock[i]);
-  }
-
-  block_bc(cr,mtop->natoms);
-
-  bc_atomtypes(cr,&mtop->atomtypes);
-
-  bc_block(cr,&mtop->mols);
-  bc_groups(cr,&mtop->symtab,mtop->natoms,&mtop->groups);
-}
diff --git a/src/gmxlib/names.c b/src/gmxlib/names.c
deleted file mode 100644 (file)
index 4f6c186..0000000
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * 
- *                This source code is part of
- * 
- *                 G   R   O   M   A   C   S
- * 
- *          GROningen MAchine for Chemical Simulations
- * 
- *                        VERSION 3.2.0
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
- * 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.
-
- * 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:
- * GROningen Mixture of Alchemy and Childrens' Stories
- */
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include "typedefs.h"
-#include "names.h"
-
-/* note: these arrays should correspond to enums in include/types/enums.h */
-
-const char *epbc_names[epbcNR+1]=
-{
-  "xyz", "no", "xy", "screw", NULL
-};
-
-const char *ens_names[ensNR+1]=
-{
-  "Grid","Simple", NULL
-};
-
-const char *ei_names[eiNR+1]=
-{
-  "md", "steep", "cg", "bd", "sd", "nm", "l-bfgs", "tpi", "tpic", "sd1", "md-vv", "md-vv-avek",NULL 
-};
-
-const char *bool_names[BOOL_NR+1]=
-{
-  "FALSE","TRUE", NULL
-};
-
-const char *yesno_names[BOOL_NR+1]=
-{
-  "no","yes", NULL
-};
-
-const char *ptype_str[eptNR+1] = {
-  "Atom", "Nucleus", "Shell", "Bond", "VSite", NULL
-};
-
-const char *eel_names[eelNR+1] = {
-  "Cut-off", "Reaction-Field", "Generalized-Reaction-Field",
-  "PME", "Ewald", "PPPM", "Poisson", "Switch", "Shift", "User", 
-  "Generalized-Born", "Reaction-Field-nec", "Encad-shift", 
-  "PME-User", "PME-Switch", "PME-User-Switch", 
-  "Reaction-Field-zero", NULL
-};
-
-const char *eewg_names[eewgNR+1] = {
-  "3d", "3dc", NULL
-};
-
-const char *evdw_names[evdwNR+1] = {
-  "Cut-off", "Switch", "Shift", "User", "Encad-shift", NULL
-};
-
-const char *econstr_names[econtNR+1] = {
-  "Lincs", "Shake", NULL
-};
-
-const char *egrp_nm[egNR+1] = { 
-  "Coul-SR","LJ-SR","Buck-SR", "Coul-LR", "LJ-LR", "Buck-LR",
-  "Coul-14", "LJ-14", NULL
-};
-
-const char *etcoupl_names[etcNR+1] = {
-  "No", "Berendsen", "Nose-Hoover", "yes", "Andersen", "Andersen-interval", "V-rescale", NULL
-}; /* yes is alias for berendsen */
-
-const char *epcoupl_names[epcNR+1] = {
-  "No", "Berendsen", "Parrinello-Rahman", "Isotropic", "MTTK", NULL
-}; /* isotropic is alias for berendsen */
-
-const char *epcoupltype_names[epctNR+1] = {
-  "Isotropic", "Semiisotropic", "Anisotropic", "Surface-Tension", NULL
-};
-
-const char *erefscaling_names[erscNR+1] = {
-  "No", "All", "COM", NULL
-};
-
-const char *edisre_names[edrNR+1] = {
-  "No", "Simple", "Ensemble", NULL
-};
-
-const char *edisreweighting_names[edrwNR+1] = {
-  "Conservative", "Equal", NULL
-};
-
-const char *enbf_names[eNBF_NR+1] = {
-  "", "LJ", "Buckingham", NULL
-};
-
-const char *ecomb_names[eCOMB_NR+1] = {
-  "", "Geometric", "Arithmetic", "GeomSigEps", NULL
-};
-
-const char *gtypes[egcNR+1] = {
-  "T-Coupling", "Energy Mon.", "Acceleration", "Freeze",
-  "User1", "User2", "VCM", "XTC", "Or. Res. Fit", "QMMM", NULL
-};
-
-const char *efep_names[efepNR+1] = {
-  "no", "yes", NULL
-};
-
-const char *separate_dhdl_file_names[sepdhdlfileNR+1] = {
-  "yes", "no", NULL
-};
-
-const char *dhdl_derivatives_names[dhdlderivativesNR+1] = {
-  "yes", "no", NULL
-};
-
-const char *esol_names[esolNR+1] = {
-  "No", "SPC", "TIP4p", NULL
-};
-
-const char *enlist_names[enlistNR+1] = {
-  "Atom-Atom", "SPC-Atom", "SPC-SPC", "TIP4p-Atom", "TIP4p-TIP4p", "CG-CG", NULL
-};
-
-const char *edispc_names[edispcNR+1] = {
-  "No", "EnerPres", "Ener", "AllEnerPres", "AllEner", NULL
-};
-
-const char *ecm_names[ecmNR+1] = { 
-  "Linear", "Angular", "None", NULL 
-};
-
-const char *eann_names[eannNR+1] = {
-  "No", "Single", "Periodic", NULL
-};
-
-const char *eis_names[eisNR+1] = {
-       "No", "GBSA", NULL
-};
-
-const char *egb_names[egbNR+1] = {
-  "Still", "HCT", "OBC", NULL
-};
-
-const char *esa_names[esaNR+1] = {
-  "Ace-approximation", "None", "Still", NULL
-};
-
-const char *ewt_names[ewtNR+1] = {
-  "9-3", "10-4", "table", "12-6", NULL
-};
-
-const char *epull_names[epullNR+1] = { 
-  "no", "umbrella", "constraint", "constant_force", NULL
-};
-
-const char *epullg_names[epullgNR+1] = { 
-  "distance", "direction", "cylinder", "position", "direction_periodic", NULL
-};
-
-const char *eQMmethod_names[eQMmethodNR+1] = {
-  "AM1", "PM3", "RHF",
-  "UHF", "DFT", "B3LYP", "MP2", "CASSCF","B3LYPLAN",
-  "DIRECT", NULL
-};
-
-const char *eQMbasis_names[eQMbasisNR+1] = {
-  "STO3G", "STO-3G", "3-21G",
-  "3-21G*", "3-21+G*", "6-21G",
-  "6-31G", "6-31G*", "6-31+G*",
-  "6-311G", NULL
-};
-
-const char *eQMMMscheme_names[eQMMMschemeNR+1] = {
-  "normal", "ONIOM", NULL
-};
-
-const char *eMultentOpt_names[eMultentOptNR+1] = {
-  "multiple_entries", "no", "use_last", NULL
-};
-
diff --git a/src/gmxlib/network.c b/src/gmxlib/network.c
deleted file mode 100644 (file)
index 219d335..0000000
+++ /dev/null
@@ -1,682 +0,0 @@
-/*
- * 
- *                This source code is part of
- * 
- *                 G   R   O   M   A   C   S
- * 
- *          GROningen MAchine for Chemical Simulations
- * 
- *                        VERSION 3.2.0
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
- * 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.
-
- * 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:
- * GROningen Mixture of Alchemy and Childrens' Stories
- */
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <string.h>
-#include "gmx_fatal.h"
-#include "main.h"
-#include "smalloc.h"
-#include "network.h"
-#include "copyrite.h"
-#include "statutil.h"
-#include "ctype.h"
-#include "macros.h"
-
-#ifdef GMX_LIB_MPI
-#include <mpi.h>
-#endif
-
-#ifdef GMX_THREADS
-#include "tmpi.h"
-#endif
-
-#include "mpelogging.h"
-
-/* The source code in this file should be thread-safe. 
-      Please keep it that way. */
-
-gmx_bool gmx_mpi_initialized(void)
-{
-  int n;
-#ifndef GMX_MPI
-  return 0;
-#else
-  MPI_Initialized(&n);
-  
-  return n;
-#endif
-}
-
-int gmx_setup(int *argc,char **argv,int *nnodes)
-{
-#ifndef GMX_MPI
-  gmx_call("gmx_setup");
-  return 0;
-#else
-  char   buf[256];
-  int    resultlen;               /* actual length of node name      */
-  int    i,flag;
-  int  mpi_num_nodes;
-  int  mpi_my_rank;
-  char mpi_hostname[MPI_MAX_PROCESSOR_NAME];
-
-  /* Call the MPI routines */
-#ifdef GMX_LIB_MPI
-#ifdef GMX_FAHCORE
-  (void) fah_MPI_Init(argc,&argv);
-#else
-  (void) MPI_Init(argc,&argv);
-#endif
-#endif
-  (void) MPI_Comm_size( MPI_COMM_WORLD, &mpi_num_nodes );
-  (void) MPI_Comm_rank( MPI_COMM_WORLD, &mpi_my_rank );
-  (void) MPI_Get_processor_name( mpi_hostname, &resultlen );
-
-
-#ifdef USE_MPE
-  /* MPE logging routines. Get event IDs from MPE: */
-  /* General events */
-  ev_timestep1               = MPE_Log_get_event_number( );
-  ev_timestep2               = MPE_Log_get_event_number( );
-  ev_force_start             = MPE_Log_get_event_number( );
-  ev_force_finish            = MPE_Log_get_event_number( );
-  ev_do_fnbf_start           = MPE_Log_get_event_number( );
-  ev_do_fnbf_finish          = MPE_Log_get_event_number( );
-  ev_ns_start                = MPE_Log_get_event_number( );
-  ev_ns_finish               = MPE_Log_get_event_number( );
-  ev_calc_bonds_start        = MPE_Log_get_event_number( );
-  ev_calc_bonds_finish       = MPE_Log_get_event_number( );
-  ev_global_stat_start       = MPE_Log_get_event_number( );
-  ev_global_stat_finish      = MPE_Log_get_event_number( );
-  ev_virial_start            = MPE_Log_get_event_number( );
-  ev_virial_finish           = MPE_Log_get_event_number( );
-  
-  /* Shift related events */
-  ev_shift_start             = MPE_Log_get_event_number( );
-  ev_shift_finish            = MPE_Log_get_event_number( );
-  ev_unshift_start           = MPE_Log_get_event_number( );
-  ev_unshift_finish          = MPE_Log_get_event_number( );
-  ev_mk_mshift_start         = MPE_Log_get_event_number( );
-  ev_mk_mshift_finish        = MPE_Log_get_event_number( );
-  
-  /* PME related events */
-  ev_pme_start               = MPE_Log_get_event_number( );
-  ev_pme_finish              = MPE_Log_get_event_number( );
-  ev_spread_on_grid_start    = MPE_Log_get_event_number( );
-  ev_spread_on_grid_finish   = MPE_Log_get_event_number( );
-  ev_sum_qgrid_start         = MPE_Log_get_event_number( );
-  ev_sum_qgrid_finish        = MPE_Log_get_event_number( );
-  ev_gmxfft3d_start          = MPE_Log_get_event_number( );
-  ev_gmxfft3d_finish         = MPE_Log_get_event_number( );
-  ev_solve_pme_start         = MPE_Log_get_event_number( );
-  ev_solve_pme_finish        = MPE_Log_get_event_number( );
-  ev_gather_f_bsplines_start = MPE_Log_get_event_number( );
-  ev_gather_f_bsplines_finish= MPE_Log_get_event_number( );
-  ev_reduce_start            = MPE_Log_get_event_number( );
-  ev_reduce_finish           = MPE_Log_get_event_number( );
-  ev_rscatter_start          = MPE_Log_get_event_number( );
-  ev_rscatter_finish         = MPE_Log_get_event_number( );
-  ev_alltoall_start          = MPE_Log_get_event_number( );
-  ev_alltoall_finish         = MPE_Log_get_event_number( );
-  ev_pmeredist_start         = MPE_Log_get_event_number( );
-  ev_pmeredist_finish        = MPE_Log_get_event_number( );
-  ev_init_pme_start          = MPE_Log_get_event_number( );      
-  ev_init_pme_finish         = MPE_Log_get_event_number( );
-  ev_send_coordinates_start  = MPE_Log_get_event_number( );
-  ev_send_coordinates_finish = MPE_Log_get_event_number( );
-  ev_update_fr_start         = MPE_Log_get_event_number( );
-  ev_update_fr_finish        = MPE_Log_get_event_number( );
-  ev_clear_rvecs_start       = MPE_Log_get_event_number( );
-  ev_clear_rvecs_finish      = MPE_Log_get_event_number( ); 
-  ev_update_start            = MPE_Log_get_event_number( ); 
-  ev_update_finish           = MPE_Log_get_event_number( ); 
-  ev_output_start            = MPE_Log_get_event_number( ); 
-  ev_output_finish           = MPE_Log_get_event_number( ); 
-  ev_sum_lrforces_start      = MPE_Log_get_event_number( ); 
-  ev_sum_lrforces_finish     = MPE_Log_get_event_number( ); 
-  ev_sort_start              = MPE_Log_get_event_number( );
-  ev_sort_finish             = MPE_Log_get_event_number( );
-  ev_sum_qgrid_start         = MPE_Log_get_event_number( );
-  ev_sum_qgrid_finish        = MPE_Log_get_event_number( );
-  
-  /* Essential dynamics related events */
-  ev_edsam_start             = MPE_Log_get_event_number( );
-  ev_edsam_finish            = MPE_Log_get_event_number( );
-  ev_get_coords_start        = MPE_Log_get_event_number( );
-  ev_get_coords_finish       = MPE_Log_get_event_number( );
-  ev_ed_apply_cons_start     = MPE_Log_get_event_number( );
-  ev_ed_apply_cons_finish    = MPE_Log_get_event_number( );
-  ev_fit_to_reference_start  = MPE_Log_get_event_number( );
-  ev_fit_to_reference_finish = MPE_Log_get_event_number( );
-  
-  /* describe events: */
-  if ( mpi_my_rank == 0 ) 
-  {
-    /* General events */
-    MPE_Describe_state(ev_timestep1,               ev_timestep2,                "timestep START",  "magenta" );
-    MPE_Describe_state(ev_force_start,             ev_force_finish,             "force",           "cornflower blue" );
-    MPE_Describe_state(ev_do_fnbf_start,           ev_do_fnbf_finish,           "do_fnbf",         "navy" );
-    MPE_Describe_state(ev_ns_start,                ev_ns_finish,                "neighbor search", "tomato" );
-    MPE_Describe_state(ev_calc_bonds_start,        ev_calc_bonds_finish,        "bonded forces",   "slate blue" );
-    MPE_Describe_state(ev_global_stat_start,       ev_global_stat_finish,       "global stat",     "firebrick3");
-    MPE_Describe_state(ev_update_fr_start,         ev_update_fr_finish,         "update forcerec", "goldenrod");
-    MPE_Describe_state(ev_clear_rvecs_start,       ev_clear_rvecs_finish,       "clear rvecs",     "bisque");
-    MPE_Describe_state(ev_update_start,            ev_update_finish,            "update",          "cornsilk");
-    MPE_Describe_state(ev_output_start,            ev_output_finish,            "output",          "black");
-    MPE_Describe_state(ev_virial_start,            ev_virial_finish,            "calc_virial",     "thistle4");
-    
-    /* PME related events */
-    MPE_Describe_state(ev_pme_start,               ev_pme_finish,               "doing PME",       "grey" );
-    MPE_Describe_state(ev_spread_on_grid_start,    ev_spread_on_grid_finish,    "spread",          "dark orange" );   
-    MPE_Describe_state(ev_sum_qgrid_start,         ev_sum_qgrid_finish,         "sum qgrid",       "slate blue");
-    MPE_Describe_state(ev_gmxfft3d_start,          ev_gmxfft3d_finish,          "fft3d",           "snow2" );   
-    MPE_Describe_state(ev_solve_pme_start,         ev_solve_pme_finish,         "solve PME",       "indian red" );   
-    MPE_Describe_state(ev_gather_f_bsplines_start, ev_gather_f_bsplines_finish, "bsplines",        "light sea green" );   
-    MPE_Describe_state(ev_reduce_start,            ev_reduce_finish,            "reduce",          "cyan1" );
-    MPE_Describe_state(ev_rscatter_start,          ev_rscatter_finish,          "rscatter",        "cyan3" );
-    MPE_Describe_state(ev_alltoall_start,          ev_alltoall_finish,          "alltoall",        "LightCyan4" );
-    MPE_Describe_state(ev_pmeredist_start,         ev_pmeredist_finish,         "pmeredist",       "thistle" );
-    MPE_Describe_state(ev_init_pme_start,          ev_init_pme_finish,          "init PME",        "snow4");
-    MPE_Describe_state(ev_send_coordinates_start,  ev_send_coordinates_finish,  "send_coordinates","blue");
-    MPE_Describe_state(ev_sum_lrforces_start,      ev_sum_lrforces_finish,      "sum_LRforces",    "lime green");
-    MPE_Describe_state(ev_sort_start,              ev_sort_finish,              "sort pme atoms",  "brown");
-    MPE_Describe_state(ev_sum_qgrid_start,         ev_sum_qgrid_finish,         "sum charge grid", "medium orchid");
-    
-    /* Shift related events */
-    MPE_Describe_state(ev_shift_start,             ev_shift_finish,             "shift",           "orange");
-    MPE_Describe_state(ev_unshift_start,           ev_unshift_finish,           "unshift",         "dark orange");    
-    MPE_Describe_state(ev_mk_mshift_start,         ev_mk_mshift_finish,         "mk_mshift",       "maroon");
-        
-    /* Essential dynamics related events */
-    MPE_Describe_state(ev_edsam_start,             ev_edsam_finish,             "EDSAM",           "deep sky blue");
-    MPE_Describe_state(ev_get_coords_start,        ev_get_coords_finish,        "ED get coords",   "steel blue");
-    MPE_Describe_state(ev_ed_apply_cons_start,     ev_ed_apply_cons_finish,     "ED apply constr", "forest green");
-    MPE_Describe_state(ev_fit_to_reference_start,  ev_fit_to_reference_finish,  "ED fit to ref",   "lavender");
-       
-  }
-  MPE_Init_log();
-#endif
-#ifdef GMX_LIB_MPI 
-  fprintf(stderr,"NNODES=%d, MYRANK=%d, HOSTNAME=%s\n",
-         mpi_num_nodes,mpi_my_rank,mpi_hostname);
-#endif
-  
-  *nnodes=mpi_num_nodes;
-  
-  return mpi_my_rank;
-#endif
-}
-
-int  gmx_node_num(void)
-{
-#ifndef GMX_MPI
-  return 1;
-#else
-  int i;
-  (void) MPI_Comm_size(MPI_COMM_WORLD, &i);
-  return i;
-#endif
-}
-
-int gmx_node_rank(void)
-{
-#ifndef GMX_MPI
-  return 0;
-#else
-  int i;
-  (void) MPI_Comm_rank(MPI_COMM_WORLD, &i);
-  return i;
-#endif
-}
-
-void gmx_setup_nodecomm(FILE *fplog,t_commrec *cr)
-{
-  gmx_nodecomm_t *nc;
-  int  n,rank,resultlen,hostnum,i,j,ng,ni;
-#ifdef GMX_MPI
-  char mpi_hostname[MPI_MAX_PROCESSOR_NAME],num[MPI_MAX_PROCESSOR_NAME];
-#endif
-
-  /* Many MPI implementations do not optimize MPI_Allreduce
-   * (and probably also other global communication calls)
-   * for multi-core nodes connected by a network.
-   * We can optimize such communication by using one MPI call
-   * within each node and one between the nodes.
-   * For MVAPICH2 and Intel MPI this reduces the time for
-   * the global_stat communication by 25%
-   * for 2x2-core 3 GHz Woodcrest connected by mixed DDR/SDR Infiniband.
-   * B. Hess, November 2007
-   */
-
-  nc = &cr->nc;
-
-  nc->bUse = FALSE;
-#ifndef GMX_THREADS
-  if (getenv("GMX_NO_NODECOMM") == NULL) {
-#ifdef GMX_MPI
-    MPI_Comm_size(cr->mpi_comm_mygroup,&n);
-    MPI_Comm_rank(cr->mpi_comm_mygroup,&rank);
-    MPI_Get_processor_name(mpi_hostname,&resultlen);
-    /* This procedure can only differentiate nodes with host names
-     * that end on unique numbers.
-     */
-    i = 0;
-    j = 0;
-    /* Only parse the host name up to the first dot */
-    while(i < resultlen && mpi_hostname[i] != '.') {
-      if (isdigit(mpi_hostname[i])) {
-       num[j++] = mpi_hostname[i];
-      }
-      i++;
-    }
-    num[j] = '\0';
-    if (j == 0) {
-      hostnum = 0;
-    } else {
-      /* Use only the last 9 decimals, so we don't overflow an int */
-      hostnum = strtol(num + max(0,j-9), NULL, 10); 
-    }
-
-    if (debug) {
-      fprintf(debug,
-             "In gmx_setup_nodecomm: splitting communicator of size %d\n",
-             n);
-      fprintf(debug,"In gmx_setup_nodecomm: hostname '%s', hostnum %d\n",
-             mpi_hostname,hostnum);
-    }
-
-    /* The intra-node communicator, split on node number */
-    MPI_Comm_split(cr->mpi_comm_mygroup,hostnum,rank,&nc->comm_intra);
-    MPI_Comm_rank(nc->comm_intra,&nc->rank_intra);
-    if (debug) {
-      fprintf(debug,"In gmx_setup_nodecomm: node rank %d rank_intra %d\n",
-             rank,nc->rank_intra);
-    }
-    /* The inter-node communicator, split on rank_intra.
-     * We actually only need the one for rank=0,
-     * but it is easier to create them all.
-     */
-    MPI_Comm_split(cr->mpi_comm_mygroup,nc->rank_intra,rank,&nc->comm_inter);
-    /* Check if this really created two step communication */
-    MPI_Comm_size(nc->comm_inter,&ng);
-    MPI_Comm_size(nc->comm_intra,&ni);
-    if (debug) {
-      fprintf(debug,"In gmx_setup_nodecomm: groups %d, my group size %d\n",
-             ng,ni);
-    }
-    if ((ng > 1 && ng < n) || (ni > 1 && ni < n)) {
-      nc->bUse = TRUE;
-      if (fplog)
-       fprintf(fplog,"Using two step summing over %d groups of on average %.1f processes\n\n",ng,(real)n/(real)ng);
-      if (nc->rank_intra > 0)
-       MPI_Comm_free(&nc->comm_inter);
-    } else {
-      /* One group or all processes in a separate group, use normal summing */
-      MPI_Comm_free(&nc->comm_inter);
-      MPI_Comm_free(&nc->comm_intra);
-    }
-#endif
-  }
-#endif
-}
-
-void gmx_barrier(const t_commrec *cr)
-{
-#ifndef GMX_MPI
-  gmx_call("gmx_barrier");
-#else
-  MPI_Barrier(cr->mpi_comm_mygroup);
-#endif
-}
-
-void gmx_abort(int noderank,int nnodes,int errorno)
-{
-#ifndef GMX_MPI
-  gmx_call("gmx_abort");
-#else
-#ifdef GMX_THREADS
-  fprintf(stderr,"Halting program %s\n",ShortProgram());
-  thanx(stderr);
-  exit(1);
-#else
-  if (nnodes > 1)
-  {
-      fprintf(stderr,"Halting parallel program %s on CPU %d out of %d\n",
-              ShortProgram(),noderank,nnodes);
-  }
-  else
-  {
-      fprintf(stderr,"Halting program %s\n",ShortProgram());
-  }
-
-  thanx(stderr);
-  MPI_Abort(MPI_COMM_WORLD,errorno);
-  exit(1);
-#endif
-#endif
-}
-
-void gmx_bcast(int nbytes,void *b,const t_commrec *cr)
-{
-#ifndef GMX_MPI
-  gmx_call("gmx_bast");
-#else
-  MPI_Bcast(b,nbytes,MPI_BYTE,MASTERRANK(cr),cr->mpi_comm_mygroup);
-#endif
-}
-
-void gmx_bcast_sim(int nbytes,void *b,const t_commrec *cr)
-{
-#ifndef GMX_MPI
-  gmx_call("gmx_bast");
-#else
-  MPI_Bcast(b,nbytes,MPI_BYTE,MASTERRANK(cr),cr->mpi_comm_mysim);
-#endif
-}
-
-void gmx_sumd(int nr,double r[],const t_commrec *cr)
-{
-#ifndef GMX_MPI
-    gmx_call("gmx_sumd");
-#else
-#if defined(MPI_IN_PLACE_EXISTS) || defined(GMX_THREADS)
-    if (cr->nc.bUse) {
-        if (cr->nc.rank_intra == 0)
-        {
-            /* Use two step summing. */
-            MPI_Reduce(MPI_IN_PLACE,r,nr,MPI_DOUBLE,MPI_SUM,0,
-                       cr->nc.comm_intra);
-            /* Sum the roots of the internal (intra) buffers. */
-            MPI_Allreduce(MPI_IN_PLACE,r,nr,MPI_DOUBLE,MPI_SUM,
-                          cr->nc.comm_inter);
-        }
-        else
-        {
-            /* This is here because of the silly MPI specification
-                that MPI_IN_PLACE should be put in sendbuf instead of recvbuf */
-            MPI_Reduce(r,NULL,nr,MPI_DOUBLE,MPI_SUM,0,cr->nc.comm_intra);
-        }
-        MPI_Bcast(r,nr,MPI_DOUBLE,0,cr->nc.comm_intra);
-    } 
-    else 
-    {
-        MPI_Allreduce(MPI_IN_PLACE,r,nr,MPI_DOUBLE,MPI_SUM, 
-                      cr->mpi_comm_mygroup);
-    }
-#else
-    int i;
-
-    if (nr > cr->mpb->dbuf_alloc) {
-        cr->mpb->dbuf_alloc = nr;
-        srenew(cr->mpb->dbuf,cr->mpb->dbuf_alloc);
-    }
-    if (cr->nc.bUse) {
-        /* Use two step summing */
-        MPI_Allreduce(r,cr->mpb->dbuf,nr,MPI_DOUBLE,MPI_SUM,cr->nc.comm_intra);
-        if (cr->nc.rank_intra == 0) {
-            /* Sum with the buffers reversed */
-            MPI_Allreduce(cr->mpb->dbuf,r,nr,MPI_DOUBLE,MPI_SUM, 
-                          cr->nc.comm_inter);
-        }
-        MPI_Bcast(r,nr,MPI_DOUBLE,0,cr->nc.comm_intra);
-    } else {
-        MPI_Allreduce(r,cr->mpb->dbuf,nr,MPI_DOUBLE,MPI_SUM,
-                      cr->mpi_comm_mygroup);
-        for(i=0; i<nr; i++)
-            r[i] = cr->mpb->dbuf[i];
-    }
-#endif
-#endif
-}
-
-void gmx_sumf(int nr,float r[],const t_commrec *cr)
-{
-#ifndef GMX_MPI
-    gmx_call("gmx_sumf");
-#else
-#if defined(MPI_IN_PLACE_EXISTS) || defined(GMX_THREADS)
-    if (cr->nc.bUse) {
-        /* Use two step summing.  */
-        if (cr->nc.rank_intra == 0)
-        {
-            MPI_Reduce(MPI_IN_PLACE,r,nr,MPI_FLOAT,MPI_SUM,0,
-                       cr->nc.comm_intra);
-            /* Sum the roots of the internal (intra) buffers */
-            MPI_Allreduce(MPI_IN_PLACE,r,nr,MPI_FLOAT,MPI_SUM,
-                          cr->nc.comm_inter);
-        }
-        else
-        {
-            /* This is here because of the silly MPI specification
-                that MPI_IN_PLACE should be put in sendbuf instead of recvbuf */
-            MPI_Reduce(r,NULL,nr,MPI_FLOAT,MPI_SUM,0,cr->nc.comm_intra);
-        }
-        MPI_Bcast(r,nr,MPI_FLOAT,0,cr->nc.comm_intra);
-    } 
-    else 
-    {
-        MPI_Allreduce(MPI_IN_PLACE,r,nr,MPI_FLOAT,MPI_SUM,cr->mpi_comm_mygroup);
-    }
-#else
-    int i;
-
-    if (nr > cr->mpb->fbuf_alloc) {
-        cr->mpb->fbuf_alloc = nr;
-        srenew(cr->mpb->fbuf,cr->mpb->fbuf_alloc);
-    }
-    if (cr->nc.bUse) {
-        /* Use two step summing */
-        MPI_Allreduce(r,cr->mpb->fbuf,nr,MPI_FLOAT,MPI_SUM,cr->nc.comm_intra);
-        if (cr->nc.rank_intra == 0) {
-            /* Sum with the buffers reversed */
-            MPI_Allreduce(cr->mpb->fbuf,r,nr,MPI_FLOAT,MPI_SUM, 
-                          cr->nc.comm_inter);
-        }
-        MPI_Bcast(r,nr,MPI_FLOAT,0,cr->nc.comm_intra);
-    } else {
-        MPI_Allreduce(r,cr->mpb->fbuf,nr,MPI_FLOAT,MPI_SUM,
-                      cr->mpi_comm_mygroup);
-        for(i=0; i<nr; i++)
-            r[i] = cr->mpb->fbuf[i];
-    }
-#endif
-#endif
-}
-
-void gmx_sumi(int nr,int r[],const t_commrec *cr)
-{
-#ifndef GMX_MPI
-    gmx_call("gmx_sumi");
-#else
-#if defined(MPI_IN_PLACE_EXISTS) || defined(GMX_THREADS)
-    if (cr->nc.bUse) {
-        /* Use two step summing */
-        if (cr->nc.rank_intra == 0) 
-        {
-            MPI_Reduce(MPI_IN_PLACE,r,nr,MPI_INT,MPI_SUM,0,cr->nc.comm_intra);
-            /* Sum with the buffers reversed */
-            MPI_Allreduce(MPI_IN_PLACE,r,nr,MPI_INT,MPI_SUM,cr->nc.comm_inter);
-        }
-        else
-        {
-            /* This is here because of the silly MPI specification
-                that MPI_IN_PLACE should be put in sendbuf instead of recvbuf */
-            MPI_Reduce(r,NULL,nr,MPI_INT,MPI_SUM,0,cr->nc.comm_intra);
-        }
-        MPI_Bcast(r,nr,MPI_INT,0,cr->nc.comm_intra);
-    } 
-    else 
-    {
-        MPI_Allreduce(MPI_IN_PLACE,r,nr,MPI_INT,MPI_SUM,cr->mpi_comm_mygroup);
-    }
-#else
-    int i;
-
-    if (nr > cr->mpb->ibuf_alloc) {
-        cr->mpb->ibuf_alloc = nr;
-        srenew(cr->mpb->ibuf,cr->mpb->ibuf_alloc);
-    }
-    if (cr->nc.bUse) {
-        /* Use two step summing */
-        MPI_Allreduce(r,cr->mpb->ibuf,nr,MPI_INT,MPI_SUM,cr->nc.comm_intra);
-        if (cr->nc.rank_intra == 0) {
-            /* Sum with the buffers reversed */
-            MPI_Allreduce(cr->mpb->ibuf,r,nr,MPI_INT,MPI_SUM,cr->nc.comm_inter);
-        }
-        MPI_Bcast(r,nr,MPI_INT,0,cr->nc.comm_intra);
-    } else {
-        MPI_Allreduce(r,cr->mpb->ibuf,nr,MPI_INT,MPI_SUM,cr->mpi_comm_mygroup);
-        for(i=0; i<nr; i++)
-            r[i] = cr->mpb->ibuf[i];
-    }
-#endif
-#endif
-}
-
-#ifdef GMX_MPI
-void gmx_sumd_comm(int nr,double r[],MPI_Comm mpi_comm)
-{
-#if defined(MPI_IN_PLACE_EXISTS) || defined(GMX_THREADS)
-    MPI_Allreduce(MPI_IN_PLACE,r,nr,MPI_DOUBLE,MPI_SUM,mpi_comm);
-#else
-    /* this function is only used in code that is not performance critical,
-       (during setup, when comm_rec is not the appropriate communication  
-       structure), so this isn't as bad as it looks. */
-    double *buf;
-    int i;
-
-    snew(buf, nr);
-    MPI_Allreduce(r,buf,nr,MPI_DOUBLE,MPI_SUM,mpi_comm);
-    for(i=0; i<nr; i++)
-        r[i] = buf[i];
-    sfree(buf);
-#endif
-}
-#endif
-
-#ifdef GMX_MPI
-void gmx_sumf_comm(int nr,float r[],MPI_Comm mpi_comm)
-{
-#if defined(MPI_IN_PLACE_EXISTS) || defined(GMX_THREADS)
-    MPI_Allreduce(MPI_IN_PLACE,r,nr,MPI_FLOAT,MPI_SUM,mpi_comm);
-#else
-    /* this function is only used in code that is not performance critical,
-       (during setup, when comm_rec is not the appropriate communication  
-       structure), so this isn't as bad as it looks. */
-    float *buf;
-    int i;
-
-    snew(buf, nr);
-    MPI_Allreduce(r,buf,nr,MPI_FLOAT,MPI_SUM,mpi_comm);
-    for(i=0; i<nr; i++)
-        r[i] = buf[i];
-    sfree(buf);
-#endif
-}
-#endif
-
-void gmx_sumd_sim(int nr,double r[],const gmx_multisim_t *ms)
-{
-#ifndef GMX_MPI
-  gmx_call("gmx_sumd");
-#else
-  gmx_sumd_comm(nr,r,ms->mpi_comm_masters);
-#endif
-}
-
-void gmx_sumf_sim(int nr,float r[],const gmx_multisim_t *ms)
-{
-#ifndef GMX_MPI
-  gmx_call("gmx_sumf");
-#else
-  gmx_sumf_comm(nr,r,ms->mpi_comm_masters);
-#endif
-}
-
-void gmx_sumi_sim(int nr,int r[], const gmx_multisim_t *ms)
-{
-#ifndef GMX_MPI
-    gmx_call("gmx_sumd");
-#else
-#if defined(MPI_IN_PLACE_EXISTS) || defined(GMX_THREADS)
-    MPI_Allreduce(MPI_IN_PLACE,r,nr,MPI_INT,MPI_SUM,ms->mpi_comm_masters);
-#else
-    /* this is thread-unsafe, but it will do for now: */
-    int i;
-
-    if (nr > ms->mpb->ibuf_alloc) {
-        ms->mpb->ibuf_alloc = nr;
-        srenew(ms->mpb->ibuf,ms->mpb->ibuf_alloc);
-    }
-    MPI_Allreduce(r,ms->mpb->ibuf,nr,MPI_INT,MPI_SUM,ms->mpi_comm_masters);
-    for(i=0; i<nr; i++)
-        r[i] = ms->mpb->ibuf[i];
-#endif
-#endif
-}
-
-void gmx_finalize(void)
-{
-#ifndef GMX_MPI
-  gmx_call("gmx_finalize");
-#else
-  int ret;
-
-  /* just as a check; we don't want to finalize twice */
-  int finalized;
-  MPI_Finalized(&finalized);
-  if (finalized)
-      return;
-
-  /* We sync the processes here to try to avoid problems
-   * with buggy MPI implementations that could cause
-   * unfinished processes to terminate.
-   */
-  MPI_Barrier(MPI_COMM_WORLD);
-
-  /*
-  if (DOMAINDECOMP(cr)) {
-    if (cr->npmenodes > 0 || cr->dd->bCartesian) 
-      MPI_Comm_free(&cr->mpi_comm_mygroup);
-    if (cr->dd->bCartesian)
-      MPI_Comm_free(&cr->mpi_comm_mysim);
-  }
-  */
-
-  /* Apparently certain mpich implementations cause problems
-   * with MPI_Finalize. In that case comment out MPI_Finalize.
-   */
-  if (debug)
-    fprintf(debug,"Will call MPI_Finalize now\n");
-
-  ret = MPI_Finalize();
-  if (debug)
-    fprintf(debug,"Return code from MPI_Finalize = %d\n",ret);
-#endif
-}
-
diff --git a/src/gmxlib/nonbonded/Makefile.am b/src/gmxlib/nonbonded/Makefile.am
deleted file mode 100644 (file)
index 4717820..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-
-AM_CPPFLAGS= -I$(top_srcdir)/include -DGMXLIBDIR=\"$(datadir)/top\"
-
-if GMX_IA32_SSE
-  IA32_SSE        = nb_kernel_ia32_sse
-  IA32_SSE_OBJ    = nb_kernel_ia32_sse/libnb_kernel_ia32_sse.la
-endif
-
-if GMX_IA32_SSE2
-  IA32_SSE2       = nb_kernel_ia32_sse2
-  IA32_SSE2_OBJ   = nb_kernel_ia32_sse2/libnb_kernel_ia32_sse2.la
-endif
-
-if GMX_X86_64_SSE
-  X86_64_SSE       = nb_kernel_x86_64_sse
-  X86_64_SSE_OBJ   = nb_kernel_x86_64_sse/libnb_kernel_x86_64_sse.la
-endif
-
-if GMX_X86_64_SSE2
-  X86_64_SSE2      = nb_kernel_x86_64_sse2
-  X86_64_SSE2_OBJ  = nb_kernel_x86_64_sse2/libnb_kernel_x86_64_sse2.la
-endif
-
-if GMX_PPC_ALTIVEC
-  PPC_ALTIVEC     = nb_kernel_ppc_altivec
-  PPC_ALTIVEC_OBJ = nb_kernel_ppc_altivec/libnb_kernel_ppc_altivec.la
-endif
-
-if GMX_IA64_ASM
-if GMX_DOUBLE
-  IA64_DOUBLE     = nb_kernel_ia64_double
-  IA64_DOUBLE_OBJ = nb_kernel_ia64_double/libnb_kernel_ia64_double.la
-else
-  IA64_SINGLE     = nb_kernel_ia64_single
-  IA64_SINGLE_OBJ = nb_kernel_ia64_single/libnb_kernel_ia64_single.la
-endif
-endif
-
-if GMX_BLUEGENE
-  BLUEGENE        = nb_kernel_bluegene
-  BLUEGENE_OBJ    = nb_kernel_bluegene/libnb_kernel_bluegene.la
-endif
-
-if GMX_POWER6
-  POWER6          = nb_kernel_power6
-  POWER6_OBJ      = nb_kernel_power6/libnb_kernel_power6.la
-endif
-
-
-if GMX_FORTRAN
-if GMX_DOUBLE
-  F77_DOUBLE      = nb_kernel_f77_double 
-  F77_DOUBLE_OBJ  = nb_kernel_f77_double/libnb_kernel_f77_double.la
-else
-  F77_SINGLE      = nb_kernel_f77_single
-  F77_SINGLE_OBJ  = nb_kernel_f77_single/libnb_kernel_f77_single.la
-endif
-endif
-
-
-
-SUBDIRS =       $(IA32_SSE)     $(IA32_SSE2)    $(IA32_3DNOW)           \
-                $(X86_64_SSE)   $(X86_64_SSE2)  $(PPC_ALTIVEC)          \
-                $(IA64_SINGLE)  $(IA64_DOUBLE)  $(BLUEGENE)             \
-               $(POWER6)       $(F77_DOUBLE)   $(F77_SINGLE)           \
-                nb_kernel_c
-
-
-# Convenience library for nonbonded interactions - not installed.
-
-noinst_LTLIBRARIES = libnonbonded.la
-
-# Subdirectories will contain libtool convenience libraries.
-# These are not installed, but added to the main library.
-# We also add conditional objects directly to the main library.
-libnonbonded_la_LIBADD = \
-       nb_kernel_c/libnb_kernel_c.la                             \
-        $(IA32_SSE_OBJ)         $(IA32_SSE2_OBJ)        $(IA32_3DNOW_OBJ)  \
-        $(X86_64_SSE_OBJ)       $(X86_64_SSE2_OBJ)      $(PPC_ALTIVEC_OBJ) \
-        $(IA64_SINGLE_OBJ)      $(IA64_DOUBLE_OBJ)      $(BLUEGENE_OBJ)    \
-       $(POWER6_OBJ)           $(F77_DOUBLE_OBJ)       $(F77_SINGLE_OBJ)  
-
-
-libnonbonded_la_SOURCES = \
-       nb_kerneltype.h                 nonbonded.c     \
-       nb_free_energy.c                nb_free_energy.h \
-       nb_generic.c                    nb_generic.h    \
-       nb_generic_cg.c                 nb_generic_cg.h
-
-
-
diff --git a/src/gmxlib/nonbonded/nb_kernel_x86_64_sse/.gitignore b/src/gmxlib/nonbonded/nb_kernel_x86_64_sse/.gitignore
deleted file mode 100644 (file)
index c8b0843..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-.deps
-.libs
diff --git a/src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/.gitignore b/src/gmxlib/nonbonded/nb_kernel_x86_64_sse2/.gitignore
deleted file mode 100644 (file)
index c8b0843..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-.deps
-.libs
diff --git a/src/gmxlib/selection/.cvsignore b/src/gmxlib/selection/.cvsignore
deleted file mode 100644 (file)
index 02b0523..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-Makefile
-Makefile.in
-.deps
-.libs
diff --git a/src/gmxlib/selection/.gitignore b/src/gmxlib/selection/.gitignore
deleted file mode 100644 (file)
index c8b0843..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-.deps
-.libs
diff --git a/src/gmxlib/selection/Makefile.am b/src/gmxlib/selection/Makefile.am
deleted file mode 100644 (file)
index c0bdb2e..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-# Convenience library for selection routines - not installed
-
-AM_YFLAGS=-d
-AM_CPPFLAGS= -I$(top_srcdir)/include 
-
-noinst_LTLIBRARIES = libselection.la
-
-libselection_la_SOURCES =      \
-       compiler.c      evaluate.c      evaluate.h      keywords.h      \
-       mempool.c       mempool.h       \
-       params.c        parser.c        parser.h        parsetree.c     \
-       parsetree.h     \
-       scanner.c       scanner.h       scanner_flex.h  scanner_internal.c \
-       scanner_internal.h              selcollection.h selhelp.c       \
-       selhelp.h       selection.c     \
-       selelem.c       selelem.h       selmethod.c     selvalue.c      \
-       sm_compare.c    sm_distance.c   sm_insolidangle.c       \
-       sm_keywords.c   sm_merge.c      sm_permute.c    sm_position.c   \
-       sm_same.c       sm_simple.c     \
-       symrec.c        symrec.h
-
-LDADD = ../libgmx@LIBSUFFIX@.la ../../mdlib/libmd@LIBSUFFIX@.la
-
-EXTRA_PROGRAMS = test_selection
-
-CLEANFILES     = *.la *~ \\\#* 
diff --git a/src/gmxlib/selection/compiler.c b/src/gmxlib/selection/compiler.c
deleted file mode 100644 (file)
index 45ca192..0000000
+++ /dev/null
@@ -1,2825 +0,0 @@
-/*
- *
- *                This source code is part of
- *
- *                 G   R   O   M   A   C   S
- *
- *          GROningen MAchine for Chemical Simulations
- *
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
- * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
- * Copyright (c) 2001-2009, The GROMACS development team,
- * check out http://www.gromacs.org for more information.
-
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * If you want to redistribute modifications, please consider that
- * scientific software is very special. Version control is crucial -
- * bugs must be traceable. We will be happy to consider code for
- * inclusion in the official distribution, but derived work must not
- * be called official GROMACS. Details are found in the README & COPYING
- * files - if they are missing, get the official version at www.gromacs.org.
- *
- * To help us fund GROMACS development, we humbly ask that you cite
- * the papers on the package - you can find them in the top README file.
- *
- * For more info, check our website at http://www.gromacs.org
- */
-/*! \internal \file
- * \brief Selection compilation and optimization.
- *
- * \todo
- * Better error handling and memory management in error situations.
- * At least, the main compilation function leaves the selection collection in
- * a bad state if an error occurs.
- *
- * \todo
- * The memory usage could still be optimized.
- * Use of memory pooling could still be extended, and a lot of redundant
- * gmin/gmax data could be eliminated for complex arithmetic expressions.
- */
-/*! \internal
- * \page selcompiler Selection compilation
- *
- * The compiler takes the selection element tree from the selection parser
- * (see \ref selparser) as input. The selection parser is quite independent of
- * selection evaluation details, and the compiler processes the tree to
- * conform to what the evaluation functions expect.
- * For better control and optimization possibilities, the compilation is
- * done on all selections simultaneously.
- * Hence, all the selections should be parsed before the compiler can be
- * called.
- *
- * The compiler initializes all fields in \c t_selelem not initialized by
- * the parser: \c t_selelem::v (some fields have already been initialized by
- * the parser), \c t_selelem::evaluate, and \c t_selelem::u (again, some
- * elements have been initialized in the parser).
- * The \c t_selelem::cdata field is used during the compilation to store
- * internal data, but the data is freed when the compiler returns.
- *
- * In addition to initializing the elements, the compiler reorganizes the tree
- * to simplify and optimize evaluation. The compiler also evaluates the static
- * parts of the selection: in the end of the compilation, static parts have
- * been replaced by the result of the evaluation.
- *
- * The compiler is called by calling gmx_ana_selcollection_compile().
- * This functions then does the compilation in several passes over the
- * \c t_selelem tree.
- *  -# Subexpressions are extracted: a separate root is created for each
- *     subexpression, and placed before the expression is first used.
- *     Currently, only variables and expressions used to evaluate parameter
- *     values are extracted, but common subexpression could also be detected
- *     here.
- *  -# A second pass with simple reordering and initialization is done:
- *    -# Boolean expressions are combined such that one element can evaluate,
- *       e.g., "A and B and C". The subexpressions in gmx_boolean expression are
- *       reordered such that static expressions come first without otherwise
- *       altering the relative order of the expressions.
- *    -# The \c t_selelem::evaluate field is set to the correct evaluation
- *       function from evaluate.h.
- *    -# The compiler data structure is allocated for each element, and
- *       the fields are initialized, with the exception of the contents of
- *       \c gmax and \c gmin fields.  In reality, several passes are made
- *       to completely initialize the structure, because some flags are set
- *       recursively based on which elements refer to an element, and these
- *       flags need to be set to initialize other fields.
- *    .
- *  -# The evaluation function of all elements is replaced with the
- *     analyze_static() function to be able to initialize the element before
- *     the actual evaluation function is called.
- *     The evaluation machinery is then called to initialize the whole tree,
- *     while simultaneously evaluating the static expressions.
- *     During the evaluation, track is kept of the smallest and largest
- *     possible selections, and these are stored in the internal compiler
- *     data structure for each element.
- *     To be able to do this for all possible values of dynamical expressions,
- *     special care needs to be taken with gmx_boolean expressions because they
- *     are short-circuiting. This is done through the
- *     \c SEL_CDATA_EVALMAX flag, which makes dynamic child expressions
- *     of \c BOOL_OR expressions evaluate to empty groups, while subexpressions
- *     of \c BOOL_AND are evaluated to largest possible groups.
- *     Memory is also allocated to store the results of the evaluation.
- *     For each element, analyze_static() calls the actual evaluation function
- *     after the element has been properly initialized.
- *  -# Another evaluation pass is done over subexpressions with more than
- *     one reference to them. These cannot be completely processed during the
- *     first pass, because it is not known whether later references require
- *     additional evaluation of static expressions.
- *  -# Unused subexpressions are removed. For efficiency reasons (and to avoid
- *     some checks), this is actually done several times already earlier in
- *     the compilation process.
- *  -# Most of the processing is now done, and the next pass simply sets the
- *     evaluation group of root elements to the largest selection as determined
- *     in pass 3.  For root elements of subexpressions that should not be
- *     evaluated before they are referred to, the evaluation group/function is
- *     cleared.  At the same time, position calculation data is initialized for
- *     for selection method elements that require it.  Compiler data is also
- *     freed as it is no longer needed.
- *  -# A final pass initializes the total masses and charges in the
- *     \c gmx_ana_selection_t data structures.
- *
- * The actual evaluation of the selection is described in the documentation
- * of the functions in evaluate.h.
- *
- * \todo
- * Some combinations of method parameter flags are not yet properly treated by
- * the compiler or the evaluation functions in evaluate.c. All the ones used by
- * currently implemented methods should work, but new combinations might not.
- *
- *
- * \section selcompiler_tree Element tree after compilation
- *
- * After the compilation, the selection element tree is suitable for
- * gmx_ana_selcollection_evaluate().
- * Enough memory has been allocated for \ref t_selelem::v
- * (and \ref t_selelem::cgrp for \ref SEL_SUBEXPR elements) to allow the
- * selection to be evaluated without allocating any memory.
- *
- *
- * \subsection selcompiler_tree_root Root elements
- *
- * The top level of the tree consists of a chain of \ref SEL_ROOT elements.
- * These are used for two purposes:
- *  -# A selection that should be evaluated.
- *     These elements appear in the same order as the selections in the input.
- *     For these elements, \ref t_selelem::v has been set to the maximum
- *     possible group that the selection can evaluate to (only for dynamic
- *     selections), and \ref t_selelem::cgrp has been set to use a NULL group
- *     for evaluation.
- *  -# A subexpression that appears in one or more selections.
- *     Each selection that gives a value for a method parameter is a
- *     potential subexpression, as is any variable value.
- *     Only subexpressions that require evaluation for each frame are left
- *     after the selection is compiled.
- *     Each subexpression appears in the chain before any references to it.
- *     For these elements, \c t_selelem::cgrp has been set to the group
- *     that should be used to evaluate the subexpression.
- *     If \c t_selelem::cgrp is empty, the total evaluation group is not known
- *     in advance or it is more efficient to evaluate the subexpression only
- *     when it is referenced.  If this is the case, \c t_selelem::evaluate is
- *     also NULL.
- *
- * The children of the \ref SEL_ROOT elements can be used to distinguish
- * the two types of root elements from each other; the rules are the same
- * as for the parsed tree (see \ref selparser_tree_root).
- * Subexpressions are treated as if they had been provided through variables.
- *
- * Selection names are stored as after parsing (see \ref selparser_tree_root).
- *
- *
- * \subsection selcompiler_tree_const Constant elements
- *
- * All (sub)selections that do not require particle positions have been
- * replaced with \ref SEL_CONST elements.
- * Constant elements from the parser are also retained if present in
- * dynamic parts of the selections.
- * Several constant elements with a NULL \c t_selelem::evaluate are left for
- * debugging purposes; of these, only the ones for \ref BOOL_OR expressions are
- * used during evaluation.
- *
- * The value is stored in \c t_selelem::v, and for group values with an
- * evaluation function set, also in \c t_selelem::cgrp.
- * For \ref GROUP_VALUE elements, unnecessary atoms (i.e., atoms that
- * could never be selected) have been removed from the value.
- *
- * \ref SEL_CONST elements have no children.
- *
- *
- * \subsection selcompiler_tree_method Method evaluation elements
- *
- * All selection methods that need to be evaluated dynamically are described
- * by a \ref SEL_EXPRESSION element. The \c t_selelem::method and
- * \c t_selelem::mdata fields have already been initialized by the parser,
- * and the compiler only calls the initialization functions in the method
- * data structure to do some additional initialization of these fields at
- * appropriate points. If the \c t_selelem::pc data field has been created by
- * the parser, the compiler initializes the data structure properly once the
- * required positions are known. If the \c t_selelem::pc field is NULL after
- * the parser, but the method provides only sel_updatefunc_pos(), an
- * appropriate position calculation data structure is created.
- * If \c t_selelem::pc is not NULL, \c t_selelem::pos is also initialized
- * to hold the positions calculated.
- *
- * Children of these elements are of type \ref SEL_SUBEXPRREF, and describe
- * parameter values that need to be evaluated for each frame. See the next
- * section for more details.
- * \ref SEL_CONST children can also appear, and stand for parameters that get
- * their value from a static expression. These elements are present only for
- * debugging purposes: they always have a NULL evaluation function.
- *
- *
- * \subsection selcompiler_tree_subexpr Subexpression elements
- *
- * As described in \ref selcompiler_tree_root, subexpressions are created
- * for each variable and each expression that gives a value to a selection
- * method parameter. As the only child of the \ref SEL_ROOT element,
- * these elements have a \ref SEL_SUBEXPR element. The \ref SEL_SUBEXPR
- * element has a single child, which evaluates the actual expression.
- * After compilation, only subexpressions that require particle positions
- * for evaluation are left.
- * For non-variable subexpression, automatic names have been generated to
- * help in debugging.
- *
- * For \ref SEL_SUBEXPR elements, memory has been allocated for
- * \c t_selelem::cgrp to store the group for which the expression has been
- * evaluated during the current frame.  This is only done if full subexpression
- * evaluation by _gmx_sel_evaluate_subexpr() is needed; the other evaluation
- * functions do not require this memory.
- *
- * \ref SEL_SUBEXPRREF elements are used to describe references to
- * subexpressions. They have always a single child, which is the
- * \ref SEL_SUBEXPR element being referenced.
- *
- * If a subexpression is used only once, the evaluation has been optimized by
- * setting the child of the \ref SEL_SUBEXPR element to evaluate the value of
- * \ref SEL_SUBEXPRREF directly (in the case of memory pooling, this is managed
- * by the evaluation functions).  In such cases, the evaluation routines for the
- * \ref SEL_SUBEXPRREF and \ref SEL_SUBEXPR elements only propagate some status
- * information, but do not unnecessarily copy the values.
- *
- *
- * \subsection selcompiler_tree_gmx_bool Boolean elements
- *
- * \ref SEL_BOOLEAN elements have been merged such that one element
- * may carry out evaluation of more than one operation of the same type.
- * The static parts of the expressions have been evaluated, and are placed
- * in the first child. These are followed by the dynamic expressions, in the
- * order provided by the user.
- *
- *
- * \subsection selcompiler_tree_arith Arithmetic elements
- *
- * Constant and static expressions in \ref SEL_ARITHMETIC elements have been
- * calculated.
- * Currently, no other processing is done.
- */
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <math.h>
-#include <stdarg.h>
-
-#include <smalloc.h>
-#include <string2.h>
-#include <vec.h>
-
-#include <indexutil.h>
-#include <poscalc.h>
-#include <selection.h>
-#include <selmethod.h>
-
-#include "evaluate.h"
-#include "keywords.h"
-#include "mempool.h"
-#include "selcollection.h"
-#include "selelem.h"
-
-/*! \internal \brief
- * Compiler flags.
- */
-enum
-{
-    /*! \brief
-     * Whether a subexpression needs to evaluated for all atoms.
-     *
-     * This flag is set for \ref SEL_SUBEXPR elements that are used to
-     * evaluate non-atom-valued selection method parameters, as well as
-     * those that are used directly as values of selections.
-     */
-    SEL_CDATA_FULLEVAL    =  1,
-    /*! \brief
-     * Whether the whole subexpression should be treated as static.
-     *
-     * This flag is always FALSE if \ref SEL_DYNAMIC is set for the element,
-     * but it is also FALSE for static elements within common subexpressions.
-     */
-    SEL_CDATA_STATIC      =  2,
-    /** Whether the subexpression will always be evaluated in the same group. */
-    SEL_CDATA_STATICEVAL  =  4,
-    /** Whether the compiler evaluation routine should return the maximal selection. */
-    SEL_CDATA_EVALMAX     =  8,
-    /** Whether memory has been allocated for \p gmin and \p gmax. */
-    SEL_CDATA_MINMAXALLOC = 16,
-    /** Whether subexpressions use simple pass evaluation functions. */
-    SEL_CDATA_SIMPLESUBEXPR = 32,
-    /** Whether this expressions is a part of a common subexpression. */
-    SEL_CDATA_COMMONSUBEXPR = 64 
-};
-
-/*! \internal \brief
- * Internal data structure used by the compiler.
- */
-typedef struct t_compiler_data
-{
-    /** The real evaluation method. */
-    sel_evalfunc     evaluate;
-    /** Flags for specifying how to treat this element during compilation. */
-    int              flags;
-    /** Smallest selection that can be selected by the subexpression. */
-    gmx_ana_index_t *gmin;
-    /** Largest selection that can be selected by the subexpression. */
-    gmx_ana_index_t *gmax;
-} t_compiler_data;
-
-
-/********************************************************************
- * COMPILER UTILITY FUNCTIONS
- ********************************************************************/
-
-static void
-print_group_info(FILE *fp, const char *name, t_selelem *sel, gmx_ana_index_t *g)
-{
-    fprintf(fp, " %s=", name);
-    if (!g)
-    {
-        fprintf(fp, "(null)");
-    }
-    else if (sel->cdata->flags & SEL_CDATA_MINMAXALLOC)
-    {
-        fprintf(fp, "(%d atoms, %p)", g->isize, (void*)g);
-    }
-    else if (sel->v.type == GROUP_VALUE && g == sel->v.u.g)
-    {
-        fprintf(fp, "(static, %p)", (void*)g);
-    }
-    else
-    {
-        fprintf(fp, "%p", (void*)g);
-    }
-}
-
-/*!
- * \param[in] fp      File handle to receive the output.
- * \param[in] sel     Selection element to print.
- * \param[in] level   Indentation level, starting from zero.
- */
-void
-_gmx_selelem_print_compiler_info(FILE *fp, t_selelem *sel, int level)
-{
-    if (!sel->cdata)
-    {
-        return;
-    }
-    fprintf(fp, "%*c cdata: flg=", level*2+1, ' ');
-    if (sel->cdata->flags & SEL_CDATA_FULLEVAL)
-    {
-        fprintf(fp, "F");
-    }
-    if (!(sel->cdata->flags & SEL_CDATA_STATIC))
-    {
-        fprintf(fp, "D");
-    }
-    if (sel->cdata->flags & SEL_CDATA_STATICEVAL)
-    {
-        fprintf(fp, "S");
-    }
-    if (sel->cdata->flags & SEL_CDATA_EVALMAX)
-    {
-        fprintf(fp, "M");
-    }
-    if (sel->cdata->flags & SEL_CDATA_MINMAXALLOC)
-    {
-        fprintf(fp, "A");
-    }
-    if (sel->cdata->flags & SEL_CDATA_SIMPLESUBEXPR)
-    {
-        fprintf(fp, "Ss");
-    }
-    if (sel->cdata->flags & SEL_CDATA_COMMONSUBEXPR)
-    {
-        fprintf(fp, "Sc");
-    }
-    if (!sel->cdata->flags)
-    {
-        fprintf(fp, "0");
-    }
-    fprintf(fp, " eval=");
-    _gmx_sel_print_evalfunc_name(fp, sel->cdata->evaluate);
-    print_group_info(fp, "gmin", sel, sel->cdata->gmin);
-    print_group_info(fp, "gmax", sel, sel->cdata->gmax);
-    fprintf(fp, "\n");
-}
-
-/*!
- * \param  sel Selection to free.
- *
- * This function only frees the data for the given selection, not its children.
- * It is safe to call the function when compiler data has not been allocated
- * or has already been freed; in such a case, nothing is done.
- */
-void
-_gmx_selelem_free_compiler_data(t_selelem *sel)
-{
-    if (sel->cdata)
-    {
-        sel->evaluate = sel->cdata->evaluate;
-        if (sel->cdata->flags & SEL_CDATA_MINMAXALLOC)
-        {
-            sel->cdata->gmin->name = NULL;
-            sel->cdata->gmax->name = NULL;
-            gmx_ana_index_deinit(sel->cdata->gmin);
-            gmx_ana_index_deinit(sel->cdata->gmax);
-            sfree(sel->cdata->gmin);
-            sfree(sel->cdata->gmax);
-        }
-        sfree(sel->cdata);
-    }
-    sel->cdata = NULL;
-}
-
-/*! \brief
- * Allocates memory for storing the evaluated value of a selection element.
- *
- * \param     sel   Selection element to initialize
- * \param[in] isize Maximum evaluation group size.
- * \param[in] bChildEval TRUE if children have already been processed.
- * \returns   TRUE if the memory was allocated, FALSE if children need to
- *   be processed first.
- *
- * If called more than once, memory is (re)allocated to ensure that the
- * maximum of the \p isize values can be stored.
- */
-static gmx_bool
-alloc_selection_data(t_selelem *sel, int isize, gmx_bool bChildEval)
-{
-    int        nalloc;
-
-    if (sel->mempool)
-    {
-        return TRUE;
-    }
-    /* Find out the number of elements to allocate */
-    if (sel->flags & SEL_SINGLEVAL)
-    {
-        nalloc = 1;
-    }
-    else if (sel->flags & SEL_ATOMVAL)
-    {
-        nalloc = isize;
-    }
-    else /* sel->flags should contain SEL_VARNUMVAL */
-    {
-        t_selelem *child;
-
-        if (!bChildEval)
-        {
-            return FALSE;
-        }
-        child = (sel->type == SEL_SUBEXPRREF ? sel->child : sel);
-        if (child->type == SEL_SUBEXPR)
-        {
-            child = child->child;
-        }
-        nalloc = (sel->v.type == POS_VALUE) ? child->v.u.p->nr : child->v.nr;
-    }
-    /* For positions, we actually want to allocate just a single structure
-     * for nalloc positions. */
-    if (sel->v.type == POS_VALUE)
-    {
-        isize  = nalloc;
-        nalloc = 1;
-    }
-    /* Allocate memory for sel->v.u if needed */
-    if (sel->flags & SEL_ALLOCVAL)
-    {
-        _gmx_selvalue_reserve(&sel->v, nalloc);
-    }
-    /* Reserve memory inside group and position structures if
-     * SEL_ALLOCDATA is set. */
-    if (sel->flags & SEL_ALLOCDATA)
-    {
-        if (sel->v.type == GROUP_VALUE)
-        {
-            gmx_ana_index_reserve(sel->v.u.g, isize);
-        }
-        else if (sel->v.type == POS_VALUE)
-        {
-            gmx_ana_pos_reserve(sel->v.u.p, isize, 0);
-        }
-    }
-    return TRUE;
-}
-
-/*! \brief
- * Replace the evaluation function of each element in the subtree.
- *
- * \param     sel  Root of the selection subtree to process.
- * \param[in] eval The new evaluation function.
- */
-static void
-set_evaluation_function(t_selelem *sel, sel_evalfunc eval)
-{
-    sel->evaluate = eval;
-    if (sel->type != SEL_SUBEXPRREF)
-    {
-        t_selelem *child = sel->child;
-        while (child)
-        {
-            set_evaluation_function(child, eval);
-            child = child->next;
-        }
-    }
-}
-
-
-/********************************************************************
- * SUBEXPRESSION PROCESSING
- ********************************************************************/
-
-/*! \brief
- * Reverses the chain of selection elements starting at \p root.
- *
- * \param   root First selection in the whole selection chain.
- * \returns The new first element for the chain.
- */
-static t_selelem *
-reverse_selelem_chain(t_selelem *root)
-{
-    t_selelem *item;
-    t_selelem *prev;
-    t_selelem *next;
-
-    prev = NULL;
-    item = root;
-    while (item)
-    {
-        next = item->next;
-        item->next = prev;
-        prev = item;
-        item = next;
-    }
-    return prev;
-}
-
-/*! \brief
- * Removes subexpressions that don't have any references.
- *
- * \param     root First selection in the whole selection chain.
- * \returns   The new first element for the chain.
- *
- * The elements are processed in reverse order to correctly detect
- * subexpressions only referred to by other subexpressions.
- */
-static t_selelem *
-remove_unused_subexpressions(t_selelem *root)
-{
-    t_selelem *item;
-    t_selelem *prev;
-    t_selelem *next;
-
-    root = reverse_selelem_chain(root);
-    while (root->child->type == SEL_SUBEXPR && root->child->refcount == 1)
-    {
-        next = root->next;
-        _gmx_selelem_free(root);
-        root = next;
-    }
-    prev = root;
-    item = root->next;
-    while (item)
-    {
-        next = item->next;
-        if (item->child->type == SEL_SUBEXPR && item->child->refcount == 1)
-        {
-            prev->next = next;
-            _gmx_selelem_free(item);
-        }
-        else
-        {
-            prev = item;
-        }
-        item = next;
-    }
-    return reverse_selelem_chain(root);
-}
-
-/*! \brief
- * Creates a name with a running number for a subexpression.
- *
- * \param[in,out] sel The subexpression to be named.
- * \param[in]     i   Running number for the subexpression.
- *
- * The name of the selection becomes "SubExpr N", where N is \p i;
- * Memory is allocated for the name and the name is stored both in
- * \c t_selelem::name and \c t_selelem::u::cgrp::name; the latter
- * is freed by _gmx_selelem_free().
- */
-static void
-create_subexpression_name(t_selelem *sel, int i)
-{
-    int   len, ret;
-    char *name;
-
-    len = 8 + (int)log10(abs(i)) + 3;
-    snew(name, len+1);
-    /* FIXME: snprintf used to be used here for extra safety, but this
-     * requires extra checking on Windows since it only provides a
-     * non-C99-conforming implementation as _snprintf()... */
-    ret = sprintf(name, "SubExpr %d", i);
-    if (ret < 0 || ret > len)
-    {
-        sfree(name);
-        name = NULL;
-    }
-    sel->name        = name;
-    sel->u.cgrp.name = name;
-}
-
-/*! \brief
- * Processes and extracts subexpressions from a given selection subtree.
- *
- * \param   sel      Root of the subtree to process.
- * \param   subexprn Pointer to a subexpression counter.
- * \returns Pointer to a chain of subselections, or NULL if none were found.
- *
- * This function finds recursively all \ref SEL_SUBEXPRREF elements below
- * the given root element and ensures that their children are within
- * \ref SEL_SUBEXPR elements. It also creates a chain of \ref SEL_ROOT elements
- * that contain the subexpression as their children and returns the first
- * of these root elements.
- */
-static t_selelem *
-extract_item_subselections(t_selelem *sel, int *subexprn)
-{
-    t_selelem *root;
-    t_selelem *subexpr;
-    t_selelem *child;
-
-    root = subexpr = NULL;
-    child = sel->child;
-    while (child)
-    {
-        if (!root)
-        {
-            root = subexpr = extract_item_subselections(child, subexprn);
-        }
-        else
-        {
-            subexpr->next = extract_item_subselections(child, subexprn);
-        }
-        while (subexpr && subexpr->next)
-        {
-            subexpr = subexpr->next;
-        }
-        /* The latter check excludes variable references.
-         * It also excludes subexpression elements that have already been
-         * processed, because they are given a name when they are first
-         * encountered.
-         * TODO: There should be a more robust mechanism (probably a dedicated
-         * flag) for detecting parser-generated subexpressions than relying on
-         * a NULL name field. */
-        if (child->type == SEL_SUBEXPRREF && (child->child->type != SEL_SUBEXPR
-                                              || child->child->name == NULL))
-        {
-            /* Create the root element for the subexpression */
-            if (!root)
-            {
-                root = subexpr = _gmx_selelem_create(SEL_ROOT);
-            }
-            else
-            {
-                subexpr->next = _gmx_selelem_create(SEL_ROOT);
-                subexpr       = subexpr->next;
-            }
-            /* Create the subexpression element and/or
-             * move the actual subexpression under the created element. */
-            if (child->child->type != SEL_SUBEXPR)
-            {
-                subexpr->child = _gmx_selelem_create(SEL_SUBEXPR);
-                _gmx_selelem_set_vtype(subexpr->child, child->v.type);
-                subexpr->child->child = child->child;
-                child->child          = subexpr->child;
-            }
-            else
-            {
-                subexpr->child = child->child;
-            }
-            create_subexpression_name(subexpr->child, ++*subexprn);
-            subexpr->child->refcount++;
-            /* Set the flags for the created elements */
-            subexpr->flags          |= (child->flags & SEL_VALFLAGMASK);
-            subexpr->child->flags   |= (child->flags & SEL_VALFLAGMASK);
-        }
-        child = child->next;
-    }
-
-    return root;
-}
-
-/*! \brief
- * Extracts subexpressions of the selection chain.
- * 
- * \param   sel First selection in the whole selection chain.
- * \returns The new first element for the chain.
- *
- * Finds all the subexpressions (and their subexpressions) in the
- * selection chain starting from \p sel and creates \ref SEL_SUBEXPR
- * elements for them.
- * \ref SEL_ROOT elements are also created for each subexpression
- * and inserted into the selection chain before the expressions that
- * refer to them.
- */
-static t_selelem *
-extract_subexpressions(t_selelem *sel)
-{
-    t_selelem   *root, *item, *next;
-    int          subexprn;
-
-    subexprn = 0;
-    root = NULL;
-    next = sel;
-    while (next)
-    {
-        item = extract_item_subselections(next, &subexprn);
-        if (item)
-        {
-            if (!root)
-            {
-                root = item;
-            }
-            else
-            {
-                sel->next = item;
-            }
-            while (item->next)
-            {
-                item = item->next;
-            }
-            item->next = next;
-        }
-        else if (!root)
-        {
-            root = next;
-        }
-        sel = next;
-        next = next->next;
-    }
-    return root;
-}
-
-
-/********************************************************************
- * BOOLEAN OPERATION REORDERING
- ********************************************************************/
-
-/*! \brief
- * Removes redundant gmx_boolean selection elements.
- *
- * \param  sel Root of the selection subtree to optimize.
- *
- * This function merges similar gmx_boolean operations (e.g., (A or B) or C becomes
- * a single OR operation with three operands).
- */
-static void
-optimize_gmx_boolean_expressions(t_selelem *sel)
-{
-    t_selelem *child, *prev;
-
-    /* Do recursively for children */
-    if (sel->type != SEL_SUBEXPRREF)
-    {
-        prev  = NULL;
-        child = sel->child;
-        while (child)
-        {
-            optimize_gmx_boolean_expressions(child);
-            /* Remove double negations */
-            if (child->type == SEL_BOOLEAN && child->u.boolt == BOOL_NOT
-                && child->child->type == SEL_BOOLEAN && child->child->u.boolt == BOOL_NOT)
-            {
-                /* Move the doubly negated expression up two levels */
-                if (!prev)
-                {
-                    sel->child = child->child->child;
-                    prev       = sel->child;
-                }
-                else
-                {
-                    prev->next = child->child->child;
-                    prev       = prev->next;
-                }
-                child->child->child->next = child->next;
-                /* Remove the two negations */
-                child->child->child = NULL;
-                child->next         = NULL;
-                _gmx_selelem_free(child);
-                child = prev;
-            }
-            prev  = child;
-            child = child->next;
-        }
-    }
-    if (sel->type != SEL_BOOLEAN || sel->u.boolt == BOOL_NOT)
-    {
-        return;
-    }
-    /* Merge subsequent binary operations */
-    prev  = NULL;
-    child = sel->child;
-    while (child)
-    {
-        if (child->type == SEL_BOOLEAN && child->u.boolt == sel->u.boolt)
-        {
-            if (!prev)
-            {
-                sel->child = child->child;
-                prev       = sel->child;
-            }
-            else
-            {
-                prev->next = child->child;
-            }
-            while (prev->next)
-            {
-                prev = prev->next;
-            }
-            prev->next = child->next;
-            sfree(child->v.u.g);
-            sfree(child);
-            child = prev->next;
-        }
-        else
-        {
-            prev = child;
-            child = child->next;
-        }
-    }
-}
-
-/*! \brief
- * Reorders children of gmx_boolean expressions such that static selections
- * come first.
- *
- * \param  sel Root of the selection subtree to reorder.
- *
- * The relative order of static expressions does not change.
- * The same is true for the dynamic expressions.
- */
-static void
-reorder_gmx_boolean_static_children(t_selelem *sel)
-{
-    t_selelem *child, *prev, *next;
-
-    /* Do recursively for children */
-    if (sel->type != SEL_SUBEXPRREF)
-    {
-        child = sel->child;
-        while (child)
-        {
-            reorder_gmx_boolean_static_children(child);
-            child = child->next;
-        }
-    }
-
-    /* Reorder gmx_boolean expressions such that static selections come first */
-    if (sel->type == SEL_BOOLEAN && (sel->flags & SEL_DYNAMIC))
-    {
-        t_selelem  start;
-
-        start.next = sel->child;
-        prev  = &start;
-        child = &start;
-        while (child->next)
-        {
-            /* child is the last handled static expression */
-            /* prev is the last handled non-static expression */
-            next = prev->next;
-            while (next && (next->flags & SEL_DYNAMIC))
-            {
-                prev = next;
-                next = next->next;
-            }
-            /* next is now the first static expression after child */
-            if (!next)
-            {
-                break;
-            }
-            /* Reorder such that next comes after child */
-            if (prev != child)
-            {
-                prev->next  = next->next;
-                next->next  = child->next;
-                child->next = next;
-            }
-            else
-            {
-                prev = prev->next;
-            }
-            /* Advance child by one */
-            child = next;
-        }
-
-        sel->child = start.next;
-    }
-}
-
-
-/********************************************************************
- * ARITHMETIC EXPRESSION PROCESSING
- ********************************************************************/
-
-/*! \brief
- * Processes arithmetic expressions to simplify and speed up evaluation.
- *
- * \param  sel Root of the selection subtree to process.
- *
- * Currently, this function only converts integer constants to reals
- * within arithmetic expressions.
- */
-static gmx_bool
-optimize_arithmetic_expressions(t_selelem *sel)
-{
-    t_selelem  *child;
-    gmx_bool        bOk;
-
-    /* Do recursively for children. */
-    if (sel->type != SEL_SUBEXPRREF)
-    {
-        child = sel->child;
-        while (child)
-        {
-            bOk = optimize_arithmetic_expressions(child);
-            if (!bOk)
-            {
-                return bOk;
-            }
-            child = child->next;
-        }
-    }
-
-    if (sel->type != SEL_ARITHMETIC)
-    {
-        return TRUE;
-    }
-
-    /* Convert integer constants to reals. */
-    child = sel->child;
-    while (child)
-    {
-        if (child->v.type == INT_VALUE)
-        {
-            real  *r;
-
-            if (child->type != SEL_CONST)
-            {
-                gmx_impl("Non-constant integer expressions not implemented in arithmetic evaluation");
-                return FALSE;
-            }
-            snew(r, 1);
-            r[0] = child->v.u.i[0];
-            sfree(child->v.u.i);
-            child->v.u.r = r;
-            child->v.type = REAL_VALUE;
-        }
-        else if (child->v.type != REAL_VALUE)
-        {
-            gmx_bug("Internal error");
-            return FALSE;
-        }
-        child = child->next;
-    }
-    return TRUE;
-}
-
-
-/********************************************************************
- * EVALUATION PREPARATION COMPILER
- ********************************************************************/
-
-/*! \brief
- * Sets the evaluation functions for the selection (sub)tree.
- *
- * \param[in,out] sel Root of the selection subtree to process.
- * \returns       TRUE on success, FALSE if any subexpression fails.
- *
- * This function sets the evaluation function (\c t_selelem::evaluate)
- * for the selection elements.
- */
-static gmx_bool
-init_item_evalfunc(t_selelem *sel)
-{
-    /* Process children. */
-    if (sel->type != SEL_SUBEXPRREF)
-    {
-        t_selelem *child;
-
-        child = sel->child;
-        while (child)
-        {
-            if (!init_item_evalfunc(child))
-            {
-                return FALSE;
-            }
-            child = child->next;
-        }
-    }
-
-    /* Set the evaluation function */
-    switch (sel->type)
-    {
-        case SEL_CONST:
-            if (sel->v.type == GROUP_VALUE)
-            {
-                sel->evaluate = &_gmx_sel_evaluate_static;
-            }
-            break;
-
-        case SEL_EXPRESSION:
-            if (!(sel->flags & SEL_DYNAMIC) && sel->u.expr.method
-                && sel->u.expr.method->init_frame)
-            {
-                sel->flags |= SEL_INITFRAME;
-            }
-            sel->evaluate = &_gmx_sel_evaluate_method;
-            break;
-
-        case SEL_ARITHMETIC:
-            sel->evaluate = &_gmx_sel_evaluate_arithmetic;
-            break;
-
-        case SEL_MODIFIER:
-            if (sel->v.type != NO_VALUE)
-            {
-                sel->evaluate = &_gmx_sel_evaluate_modifier;
-            }
-            break;
-
-        case SEL_BOOLEAN:
-            switch (sel->u.boolt)
-            {
-                case BOOL_NOT: sel->evaluate = &_gmx_sel_evaluate_not; break;
-                case BOOL_AND: sel->evaluate = &_gmx_sel_evaluate_and; break;
-                case BOOL_OR:  sel->evaluate = &_gmx_sel_evaluate_or;  break;
-                case BOOL_XOR:
-                    gmx_impl("xor expressions not implemented");
-                    return FALSE;
-            }
-            break;
-
-        case SEL_ROOT:
-            sel->evaluate = &_gmx_sel_evaluate_root;
-            break;
-
-        case SEL_SUBEXPR:
-            sel->evaluate = (sel->refcount == 2
-                             ? &_gmx_sel_evaluate_subexpr_simple
-                             : &_gmx_sel_evaluate_subexpr);
-            break;
-
-        case SEL_SUBEXPRREF:
-            sel->name     = sel->child->name;
-            sel->evaluate = (sel->child->refcount == 2
-                             ? &_gmx_sel_evaluate_subexprref_simple
-                             : &_gmx_sel_evaluate_subexprref);
-            break;
-    }
-
-    return TRUE;
-}
-
-/*! \brief
- * Sets the memory pool for selection elements that can use it.
- *
- * \param     sel      Root of the selection subtree to process.
- * \param[in] mempool  Memory pool to use.
- */
-static void
-setup_memory_pooling(t_selelem *sel, gmx_sel_mempool_t *mempool)
-{
-    if (sel->type != SEL_SUBEXPRREF)
-    {
-        t_selelem         *child;
-
-        child = sel->child;
-        while (child)
-        {
-            if ((sel->type == SEL_BOOLEAN && (child->flags & SEL_DYNAMIC))
-                || (sel->type == SEL_ARITHMETIC && child->type != SEL_CONST
-                    && !(child->flags & SEL_SINGLEVAL))
-                || (sel->type == SEL_SUBEXPR && sel->refcount > 2))
-            {
-                child->mempool = mempool;
-                if (child->type == SEL_SUBEXPRREF
-                    && child->child->refcount == 2)
-                {
-                    child->child->child->mempool = mempool;
-                }
-            }
-            setup_memory_pooling(child, mempool);
-            child = child->next;
-        }
-    }
-}
-
-/*! \brief
- * Prepares the selection (sub)tree for evaluation.
- *
- * \param[in,out] sel Root of the selection subtree to prepare.
- *
- * It also allocates memory for the \p sel->v.u.g or \p sel->v.u.p
- * structure if required.
- */
-static void
-init_item_evaloutput(t_selelem *sel)
-{
-    /* Process children. */
-    if (sel->type != SEL_SUBEXPRREF)
-    {
-        t_selelem *child;
-
-        child = sel->child;
-        while (child)
-        {
-            init_item_evaloutput(child);
-            child = child->next;
-        }
-    }
-
-    if (sel->type == SEL_SUBEXPR && sel->refcount == 2)
-    {
-        sel->flags &= ~(SEL_ALLOCVAL | SEL_ALLOCDATA);
-        if (sel->v.type == GROUP_VALUE || sel->v.type == POS_VALUE)
-        {
-            _gmx_selvalue_setstore(&sel->v, sel->child->v.u.ptr);
-        }
-    }
-    else if (sel->type == SEL_SUBEXPR
-             && (sel->cdata->flags & SEL_CDATA_FULLEVAL))
-    {
-        sel->evaluate = &_gmx_sel_evaluate_subexpr_staticeval;
-        sel->cdata->evaluate = sel->evaluate;
-        sel->child->mempool = NULL;
-        sel->flags &= ~(SEL_ALLOCVAL | SEL_ALLOCDATA);
-        if (sel->v.type == GROUP_VALUE || sel->v.type == POS_VALUE)
-        {
-            _gmx_selvalue_setstore(&sel->v, sel->child->v.u.ptr);
-        }
-    }
-    else if (sel->type == SEL_SUBEXPRREF && sel->child->refcount == 2)
-    {
-        if (sel->v.u.ptr)
-        {
-            _gmx_selvalue_setstore(&sel->child->v, sel->v.u.ptr);
-            _gmx_selelem_free_values(sel->child->child);
-            sel->child->child->flags &= ~(SEL_ALLOCVAL | SEL_ALLOCDATA);
-            sel->child->child->flags |= (sel->flags & SEL_ALLOCDATA);
-            _gmx_selvalue_setstore(&sel->child->child->v, sel->v.u.ptr);
-        }
-        else if (sel->v.type == GROUP_VALUE || sel->v.type == POS_VALUE)
-        {
-            _gmx_selvalue_setstore(&sel->v, sel->child->child->v.u.ptr);
-        }
-        sel->flags &= ~(SEL_ALLOCVAL | SEL_ALLOCDATA);
-    }
-
-    /* Make sure that the group/position structure is allocated. */
-    if (!sel->v.u.ptr && (sel->flags & SEL_ALLOCVAL))
-    {
-        if (sel->v.type == GROUP_VALUE || sel->v.type == POS_VALUE)
-        {
-            _gmx_selvalue_reserve(&sel->v, 1);
-            sel->v.nr = 1;
-        }
-    }
-}
-
-
-/********************************************************************
- * COMPILER DATA INITIALIZATION
- ********************************************************************/
-
-/*! \brief
- * Allocates memory for the compiler data and initializes the structure.
- *
- * \param sel Root of the selection subtree to process.
- */
-static void
-init_item_compilerdata(t_selelem *sel)
-{
-    t_selelem   *child;
-
-    /* Allocate the compiler data structure */
-    snew(sel->cdata, 1);
-
-    /* Store the real evaluation method because the compiler will replace it */
-    sel->cdata->evaluate = sel->evaluate;
-
-    /* Initialize the flags */
-    sel->cdata->flags = SEL_CDATA_STATICEVAL;
-    if (!(sel->flags & SEL_DYNAMIC))
-    {
-        sel->cdata->flags |= SEL_CDATA_STATIC;
-    }
-    if (sel->type == SEL_SUBEXPR)
-    {
-        sel->cdata->flags |= SEL_CDATA_EVALMAX;
-    }
-    /* Set the full evaluation flag for subexpressions that require it;
-     * the subexpression has already been initialized, so we can simply
-     * access its compilation flags.*/
-    if (sel->type == SEL_EXPRESSION || sel->type == SEL_MODIFIER)
-    {
-        child = sel->child;
-        while (child)
-        {
-            if (!(child->flags & SEL_ATOMVAL) && child->child)
-            {
-                child->child->cdata->flags |= SEL_CDATA_FULLEVAL;
-            }
-            child = child->next;
-        }
-    }
-    else if (sel->type == SEL_ROOT && sel->child->type == SEL_SUBEXPRREF)
-    {
-        sel->child->child->cdata->flags |= SEL_CDATA_FULLEVAL;
-    }
-
-    /* Initialize children */
-    if (sel->type != SEL_SUBEXPRREF)
-    {
-        child = sel->child;
-        while (child)
-        {
-            init_item_compilerdata(child);
-            child = child->next;
-        }
-    }
-
-    /* Determine whether we should evaluate the minimum or the maximum
-     * for the children of this element. */
-    if (sel->type == SEL_BOOLEAN)
-    {
-        gmx_bool  bEvalMax;
-
-        bEvalMax = (sel->u.boolt == BOOL_AND);
-        child = sel->child;
-        while (child)
-        {
-            if (bEvalMax)
-            {
-                child->cdata->flags |= SEL_CDATA_EVALMAX;
-            }
-            else if (child->type == SEL_BOOLEAN && child->u.boolt == BOOL_NOT)
-            {
-                child->child->cdata->flags |= SEL_CDATA_EVALMAX;
-            }
-            child = child->next;
-        }
-    }
-    else if (sel->type == SEL_EXPRESSION || sel->type == SEL_MODIFIER
-             || sel->type == SEL_SUBEXPR)
-    {
-        child = sel->child;
-        while (child)
-        {
-            child->cdata->flags |= SEL_CDATA_EVALMAX;
-            child = child->next;
-        }
-    }
-}
-
-/*! \brief
- * Initializes the static evaluation flag for a selection subtree.
- *
- * \param[in,out] sel  Root of the selection subtree to process.
- *
- * Sets the \c bStaticEval in the compiler data structure:
- * for any element for which the evaluation group may depend on the trajectory
- * frame, the flag is cleared.
- *
- * reorder_gmx_boolean_static_children() should have been called.
- */
-static void
-init_item_staticeval(t_selelem *sel)
-{
-    t_selelem   *child;
-
-    /* Subexpressions with full evaluation should always have bStaticEval,
-     * so don't do anything if a reference to them is encountered. */
-    if (sel->type == SEL_SUBEXPRREF
-        && (sel->child->cdata->flags & SEL_CDATA_FULLEVAL))
-    {
-        return;
-    }
-
-    /* Propagate the bStaticEval flag to children if it is not set */
-    if (!(sel->cdata->flags & SEL_CDATA_STATICEVAL))
-    {
-        child = sel->child;
-        while (child)
-        {
-            if ((sel->type != SEL_EXPRESSION && sel->type != SEL_MODIFIER)
-                || (child->flags & SEL_ATOMVAL))
-            {
-                if (child->cdata->flags & SEL_CDATA_STATICEVAL)
-                {
-                    child->cdata->flags &= ~SEL_CDATA_STATICEVAL;
-                    init_item_staticeval(child);
-                }
-            }
-            child = child->next;
-        }
-    }
-    else /* bStaticEval is set */
-    {
-        /* For gmx_boolean expressions, any expression after the first dynamic
-         * expression should not have bStaticEval. */
-        if (sel->type == SEL_BOOLEAN)
-        {
-            child = sel->child;
-            while (child && !(child->flags & SEL_DYNAMIC))
-            {
-                child = child->next;
-            }
-            if (child)
-            {
-                child = child->next;
-            }
-            while (child)
-            {
-                child->cdata->flags &= ~SEL_CDATA_STATICEVAL;
-                child = child->next;
-            }
-        }
-
-        /* Process the children */
-        child = sel->child;
-        while (child)
-        {
-            init_item_staticeval(child);
-            child = child->next;
-        }
-    }
-}
-
-/*! \brief
- * Initializes compiler flags for subexpressions.
- *
- * \param sel Root of the selection subtree to process.
- */
-static void
-init_item_subexpr_flags(t_selelem *sel)
-{
-    if (sel->type == SEL_SUBEXPR)
-    {
-        if (sel->refcount == 2)
-        {
-            sel->cdata->flags |= SEL_CDATA_SIMPLESUBEXPR;
-        }
-        else if (!(sel->cdata->flags & SEL_CDATA_FULLEVAL))
-        {
-            sel->cdata->flags |= SEL_CDATA_COMMONSUBEXPR;
-        }
-    }
-    else if (sel->type == SEL_SUBEXPRREF && sel->child->refcount == 2)
-    {
-        sel->cdata->flags |= SEL_CDATA_SIMPLESUBEXPR;
-    }
-
-    /* Process children, but only follow subexpression references if the
-     * common subexpression flag needs to be propagated. */
-    if (sel->type != SEL_SUBEXPRREF
-        || ((sel->cdata->flags & SEL_CDATA_COMMONSUBEXPR)
-            && sel->child->refcount > 2))
-    {
-        t_selelem *child = sel->child;
-
-        while (child)
-        {
-            if (!(child->cdata->flags & SEL_CDATA_COMMONSUBEXPR))
-            {
-                if (sel->type != SEL_EXPRESSION || (child->flags & SEL_ATOMVAL))
-                {
-                    child->cdata->flags |=
-                        (sel->cdata->flags & SEL_CDATA_COMMONSUBEXPR);
-                }
-                init_item_subexpr_flags(child);
-            }
-            child = child->next;
-        }
-    }
-}
-
-/*! \brief
- * Initializes the gmin and gmax fields of the compiler data structure.
- *
- * \param sel Root of the selection subtree to process.
- */
-static void
-init_item_minmax_groups(t_selelem *sel)
-{
-    /* Process children. */
-    if (sel->type != SEL_SUBEXPRREF)
-    {
-        t_selelem *child;
-
-        child = sel->child;
-        while (child)
-        {
-            init_item_minmax_groups(child);
-            child = child->next;
-        }
-    }
-
-    /* Initialize the minimum and maximum evaluation groups. */
-    if (sel->type != SEL_ROOT && sel->v.type != NO_VALUE)
-    {
-        if (sel->v.type == GROUP_VALUE
-            && (sel->cdata->flags & SEL_CDATA_STATIC))
-        {
-            sel->cdata->gmin = sel->v.u.g;
-            sel->cdata->gmax = sel->v.u.g;
-        }
-        else if (sel->type == SEL_SUBEXPR
-                 && ((sel->cdata->flags & SEL_CDATA_SIMPLESUBEXPR)
-                     || (sel->cdata->flags & SEL_CDATA_FULLEVAL)))
-        {
-            sel->cdata->gmin = sel->child->cdata->gmin;
-            sel->cdata->gmax = sel->child->cdata->gmax;
-        }
-        else
-        {
-            sel->cdata->flags |= SEL_CDATA_MINMAXALLOC;
-            snew(sel->cdata->gmin, 1);
-            snew(sel->cdata->gmax, 1);
-        }
-    }
-}
-
-
-/********************************************************************
- * EVALUATION GROUP INITIALIZATION
- ********************************************************************/
-
-/*! \brief
- * Initializes evaluation groups for root items.
- *
- * \param[in,out] sc   Selection collection data.
- *
- * The evaluation group of each \ref SEL_ROOT element corresponding to a
- * selection in \p sc is set to \p gall.  The same is done for \ref SEL_ROOT
- * elements corresponding to subexpressions that need full evaluation.
- */
-static void
-initialize_evalgrps(gmx_ana_selcollection_t *sc)
-{
-    t_selelem   *root;
-
-    root = sc->root;
-    while (root)
-    {
-        if (root->child->type != SEL_SUBEXPR
-            || (root->child->cdata->flags & SEL_CDATA_FULLEVAL))
-        {
-            gmx_ana_index_set(&root->u.cgrp, sc->gall.isize, sc->gall.index,
-                              root->u.cgrp.name, 0);
-        }
-        root = root->next;
-    }
-}
-
-
-/********************************************************************
- * STATIC ANALYSIS
- ********************************************************************/
-
-/*! \brief
- * Marks a subtree completely dynamic or undoes such a change.
- *
- * \param     sel      Selection subtree to mark.
- * \param[in] bDynamic If TRUE, the \p bStatic flag of the whole
- *   selection subtree is cleared. If FALSE, the flag is restored to
- *   using \ref SEL_DYNAMIC.
- *
- * Does not descend into parameters of methods unless the parameters
- * are evaluated for each atom.
- */
-static void
-mark_subexpr_dynamic(t_selelem *sel, gmx_bool bDynamic)
-{
-    t_selelem *child;
-
-    if (!bDynamic && !(sel->flags & SEL_DYNAMIC))
-    {
-        sel->cdata->flags |= SEL_CDATA_STATIC;
-    }
-    else
-    {
-        sel->cdata->flags &= ~SEL_CDATA_STATIC;
-    }
-    child = sel->child;
-    while (child)
-    {
-        if (sel->type != SEL_EXPRESSION || child->type != SEL_SUBEXPRREF
-            || (child->u.param->flags & SPAR_ATOMVAL))
-        {
-            mark_subexpr_dynamic(child, bDynamic);
-        }
-        child = child->next;
-    }
-}
-
-/*! \brief
- * Frees memory for subexpressions that are no longer needed.
- *
- * \param     sel      Selection subtree to check.
- *
- * Checks whether the subtree rooted at \p sel refers to any \ref SEL_SUBEXPR
- * elements that are not referred to by anything else except their own root
- * element. If such elements are found, all memory allocated for them is freed
- * except the actual element. The element is left because otherwise a dangling
- * pointer would be left at the root element, which is not traversed by this
- * function. Later compilation passes remove the stub elements.
- */
-static void
-release_subexpr_memory(t_selelem *sel)
-{
-    if (sel->type == SEL_SUBEXPR)
-    {
-        if (sel->refcount == 2)
-        {
-            release_subexpr_memory(sel->child);
-            sel->name = NULL;
-            _gmx_selelem_free_chain(sel->child);
-            _gmx_selelem_free_values(sel);
-            _gmx_selelem_free_exprdata(sel);
-            _gmx_selelem_free_compiler_data(sel);
-            sel->child = NULL;
-        }
-    }
-    else
-    {
-        t_selelem *child;
-
-        child = sel->child;
-        while (child)
-        {
-            release_subexpr_memory(child);
-            child = child->next;
-        }
-    }
-}
-
-/*! \brief
- * Makes an evaluated selection element static.
- *
- * \param     sel   Selection element to make static.
- *
- * The evaluated value becomes the value of the static element.
- * The element type is changed to SEL_CONST and the children are
- * deleted.
- */
-static void
-make_static(t_selelem *sel)
-{
-    /* If this is a subexpression reference and the data is stored in the
-     * child, we transfer data ownership before doing anything else. */
-    if (sel->type == SEL_SUBEXPRREF
-        && (sel->cdata->flags & SEL_CDATA_SIMPLESUBEXPR))
-    {
-        if (sel->child->child->flags & SEL_ALLOCDATA)
-        {
-            sel->flags |= SEL_ALLOCDATA;
-            sel->child->child->flags &= ~SEL_ALLOCDATA;
-        }
-        if (sel->child->child->flags & SEL_ALLOCVAL)
-        {
-            sel->flags |= SEL_ALLOCVAL;
-            sel->v.nalloc = sel->child->child->v.nalloc;
-            sel->child->child->flags &= ~SEL_ALLOCVAL;
-            sel->child->child->v.nalloc = -1;
-        }
-    }
-    /* When we reach here for parameter elements, the value is already
-     * stored in the parent element, so make sure that it is not freed
-     * through this element. */
-    if (sel->type == SEL_SUBEXPRREF && sel->u.param)
-    {
-        sel->u.param->val.nalloc = sel->v.nalloc;
-        sel->flags &= ~(SEL_ALLOCVAL | SEL_ALLOCDATA);
-        sel->v.nalloc = -1;
-    }
-    /* Free the children. */
-    release_subexpr_memory(sel);
-    _gmx_selelem_free_chain(sel->child);
-    sel->child           = NULL;
-    /* Free the expression data as it is no longer needed */
-    _gmx_selelem_free_exprdata(sel);
-    /* Make the item static */
-    sel->name            = NULL;
-    sel->type            = SEL_CONST;
-    sel->evaluate        = NULL;
-    sel->cdata->evaluate = NULL;
-    /* Set the group value.
-     * free_exprdata above frees the cgrp group, so we can just override it. */
-    if (sel->v.type == GROUP_VALUE)
-    {
-        gmx_ana_index_set(&sel->u.cgrp, sel->v.u.g->isize, sel->v.u.g->index, NULL, 0);
-    }
-}
-
-/*! \brief
- * Evaluates a constant expression during analyze_static().
- *
- * \param[in]     data Evaluation data.
- * \param[in,out] sel Selection to process.
- * \param[in]     g   The evaluation group.
- * \returns       0 on success, a non-zero error code on error.
- */
-static int
-process_const(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g)
-{
-    int  rc;
-
-    rc = 0;
-    if (sel->v.type == GROUP_VALUE)
-    {
-        if (sel->cdata->evaluate)
-        {
-            rc = sel->cdata->evaluate(data, sel, g);
-        }
-    }
-    /* Other constant expressions do not need evaluation */
-    return rc;
-}
-
-/*! \brief
- * Sets the parameter value pointer for \ref SEL_SUBEXPRREF params.
- *
- * \param[in,out] sel Selection to process.
- *
- * Copies the value pointer of \p sel to \c sel->u.param if one is present
- * and should receive the value from the compiler
- * (most parameter values are handled during parsing).
- * If \p sel is not of type \ref SEL_SUBEXPRREF, or if \c sel->u.param is NULL,
- * the function does nothing.
- * Also, if the \c sel->u.param does not have \ref SPAR_VARNUM or
- * \ref SPAR_ATOMVAL, the function returns immediately.
- */
-static void
-store_param_val(t_selelem *sel)
-{
-    /* Return immediately if there is no parameter. */
-    if (sel->type != SEL_SUBEXPRREF || !sel->u.param)
-    {
-        return;
-    }
-
-    /* Or if the value does not need storing. */
-    if (!(sel->u.param->flags & (SPAR_VARNUM | SPAR_ATOMVAL)))
-    {
-        return;
-    }
-
-    if (sel->v.type == INT_VALUE || sel->v.type == REAL_VALUE
-        || sel->v.type == STR_VALUE)
-    {
-        _gmx_selvalue_setstore(&sel->u.param->val, sel->v.u.ptr);
-    }
-}
-
-/*! \brief
- * Handles the initialization of a selection method during analyze_static() pass.
- *
- * \param[in,out] sel Selection element to process.
- * \param[in]     top Topology structure.
- * \param[in]     isize Size of the evaluation group for the element.
- * \returns       0 on success, a non-zero error code on return.
- *
- * Calls sel_initfunc() (and possibly sel_outinitfunc()) to initialize the
- * method.
- * If no \ref SPAR_ATOMVAL parameters are present, multiple initialization
- * is prevented by using \ref SEL_METHODINIT and \ref SEL_OUTINIT flags.
- */
-static int
-init_method(t_selelem *sel, t_topology *top, int isize)
-{
-    t_selelem *child;
-    gmx_bool       bAtomVal;
-    int        rc;
-
-    /* Find out whether there are any atom-valued parameters */
-    bAtomVal = FALSE;
-    child = sel->child;
-    while (child)
-    {
-        if (child->flags & SEL_ATOMVAL)
-        {
-            bAtomVal = TRUE;
-        }
-        child = child->next;
-    }
-
-    /* Initialize the method */
-    if (sel->u.expr.method->init
-        && (bAtomVal || !(sel->flags & SEL_METHODINIT)))
-    {
-        sel->flags |= SEL_METHODINIT;
-        rc = sel->u.expr.method->init(top, sel->u.expr.method->nparams,
-                sel->u.expr.method->param, sel->u.expr.mdata);
-        if (rc != 0)
-        {
-            return rc;
-        }
-    }
-    if (bAtomVal || !(sel->flags & SEL_OUTINIT))
-    {
-        sel->flags |= SEL_OUTINIT;
-        if (sel->u.expr.method->outinit)
-        {
-            rc = sel->u.expr.method->outinit(top, &sel->v, sel->u.expr.mdata);
-            if (rc != 0)
-            {
-                return rc;
-            }
-            if (sel->v.type != POS_VALUE && sel->v.type != GROUP_VALUE)
-            {
-                alloc_selection_data(sel, isize, TRUE);
-            }
-        }
-        else
-        {
-            alloc_selection_data(sel, isize, TRUE);
-            if ((sel->flags & SEL_DYNAMIC)
-                && sel->v.type != GROUP_VALUE && sel->v.type != POS_VALUE)
-            {
-                sel->v.nr = isize;
-            }
-            /* If the method is char-valued, pre-allocate the strings. */
-            if (sel->u.expr.method->flags & SMETH_CHARVAL)
-            {
-                int  i;
-
-                /* A sanity check */
-                if (sel->v.type != STR_VALUE)
-                {
-                    gmx_bug("internal error");
-                    return -1;
-                }
-                sel->flags |= SEL_ALLOCDATA;
-                for (i = 0; i < isize; ++i)
-                {
-                    if (sel->v.u.s[i] == NULL)
-                    {
-                        snew(sel->v.u.s[i], 2);
-                    }
-                }
-            }
-        }
-        /* Clear the values for dynamic output to avoid valgrind warnings. */
-        if ((sel->flags & SEL_DYNAMIC) && sel->v.type == REAL_VALUE)
-        {
-            int i;
-
-            for (i = 0; i < sel->v.nr; ++i)
-            {
-                sel->v.u.r[i] = 0.0;
-            }
-        }
-    }
-
-    return 0;
-}
-
-/*! \brief
- * Evaluates the static part of a gmx_boolean expression.
- *
- * \param[in]     data Evaluation data.
- * \param[in,out] sel Boolean selection element whose children should be
- *   processed.
- * \param[in]     g   The evaluation group.
- * \returns       0 on success, a non-zero error code on error.
- *
- * reorder_item_static_children() should have been called.
- */
-static int
-evaluate_gmx_boolean_static_part(gmx_sel_evaluate_t *data, t_selelem *sel,
-                             gmx_ana_index_t *g)
-{
-    t_selelem *child, *next;
-    int        rc;
-
-    /* Find the last static subexpression */
-    child = sel->child;
-    while (child->next && (child->next->cdata->flags & SEL_CDATA_STATIC))
-    {
-        child = child->next;
-    }
-    if (!(child->cdata->flags & SEL_CDATA_STATIC))
-    {
-        return 0;
-    }
-
-    /* Evalute the static part if there is more than one expression */
-    if (child != sel->child)
-    {
-        next  = child->next;
-        child->next = NULL;
-        rc = sel->cdata->evaluate(data, sel, g);
-        if (rc != 0)
-        {
-            return rc;
-        }
-        /* Replace the subexpressions with the result */
-        _gmx_selelem_free_chain(sel->child);
-        snew(child, 1);
-        child->type       = SEL_CONST;
-        child->flags      = SEL_FLAGSSET | SEL_SINGLEVAL | SEL_ALLOCVAL | SEL_ALLOCDATA;
-        _gmx_selelem_set_vtype(child, GROUP_VALUE);
-        child->evaluate   = NULL;
-        _gmx_selvalue_reserve(&child->v, 1);
-        gmx_ana_index_copy(child->v.u.g, sel->v.u.g, TRUE);
-        init_item_compilerdata(child);
-        init_item_minmax_groups(child);
-        child->cdata->flags &= ~SEL_CDATA_STATICEVAL;
-        child->cdata->flags |= sel->cdata->flags & SEL_CDATA_STATICEVAL;
-        child->next = next;
-        sel->child = child;
-    }
-    else if (child->evaluate)
-    {
-        rc = child->evaluate(data, child, g);
-        if (rc != 0)
-        {
-            return rc;
-        }
-    }
-    /* Set the evaluation function for the constant element.
-     * We never need to evaluate the element again during compilation,
-     * but we may need to evaluate the static part again if the
-     * expression is not an OR with a static evaluation group.
-     * If we reach here with a NOT expression, the NOT expression
-     * is also static, and will be made a constant later, so don't waste
-     * time copying the group. */
-    child->evaluate = NULL;
-    if (sel->u.boolt == BOOL_NOT
-        || ((sel->cdata->flags & SEL_CDATA_STATICEVAL)
-            && sel->u.boolt == BOOL_OR))
-    {
-        child->cdata->evaluate = NULL;
-    }
-    else
-    {
-        child->cdata->evaluate = &_gmx_sel_evaluate_static;
-        /* The cgrp has only been allocated if it originated from an
-         * external index group. In that case, we need special handling
-         * to preserve the name of the group and to not leak memory.
-         * If cgrp has been set in make_static(), it is not allocated,
-         * and hence we can overwrite it safely. */
-        if (child->u.cgrp.nalloc_index > 0)
-        {
-            char *name = child->u.cgrp.name;
-            gmx_ana_index_copy(&child->u.cgrp, child->v.u.g, FALSE);
-            gmx_ana_index_squeeze(&child->u.cgrp);
-            child->u.cgrp.name = name;
-        }
-        else
-        {
-            gmx_ana_index_copy(&child->u.cgrp, child->v.u.g, TRUE);
-        }
-    }
-    return 0;
-}
-
-/*! \brief
- * Evaluates the minimum and maximum groups for a gmx_boolean expression.
- *
- * \param[in]  sel  \ref SEL_BOOLEAN element currently being evaluated.
- * \param[in]  g    Group for which \p sel has been evaluated.
- * \param[out] gmin Largest subset of the possible values of \p sel.
- * \param[out] gmax Smallest superset of the possible values of \p sel.
- *
- * This is a helper function for analyze_static() that is called for
- * dynamic \ref SEL_BOOLEAN elements after they have been evaluated.
- * It uses the minimum and maximum groups of the children to calculate
- * the minimum and maximum groups for \p sel, and also updates the static
- * part of \p sel (which is in the first child) if the children give
- * cause for this.
- *
- * This function may allocate some extra memory for \p gmin and \p gmax,
- * but as these groups are freed at the end of analyze_static() (which is
- * reached shortly after this function returns), this should not be a major
- * problem.
- */
-static void
-evaluate_gmx_boolean_minmax_grps(t_selelem *sel, gmx_ana_index_t *g,
-                             gmx_ana_index_t *gmin, gmx_ana_index_t *gmax)
-{
-    t_selelem *child;
-
-    switch (sel->u.boolt)
-    {
-        case BOOL_NOT:
-            gmx_ana_index_reserve(gmin, g->isize);
-            gmx_ana_index_reserve(gmax, g->isize);
-            gmx_ana_index_difference(gmax, g, sel->child->cdata->gmin);
-            gmx_ana_index_difference(gmin, g, sel->child->cdata->gmax);
-            break;
-
-        case BOOL_AND:
-            gmx_ana_index_copy(gmin, sel->child->cdata->gmin, TRUE);
-            gmx_ana_index_copy(gmax, sel->child->cdata->gmax, TRUE);
-            child = sel->child->next;
-            while (child && gmax->isize > 0)
-            {
-                gmx_ana_index_intersection(gmin, gmin, child->cdata->gmin);
-                gmx_ana_index_intersection(gmax, gmax, child->cdata->gmax);
-                child = child->next;
-            }
-            /* Update the static part if other expressions limit it */
-            if ((sel->child->cdata->flags & SEL_CDATA_STATIC)
-                && sel->child->v.u.g->isize > gmax->isize)
-            {
-                gmx_ana_index_copy(sel->child->v.u.g, gmax, FALSE);
-                gmx_ana_index_squeeze(sel->child->v.u.g);
-                if (sel->child->u.cgrp.isize > 0)
-                {
-                    gmx_ana_index_copy(&sel->child->u.cgrp, gmax, FALSE);
-                    gmx_ana_index_squeeze(&sel->child->u.cgrp);
-                }
-            }
-            break;
-
-        case BOOL_OR:
-            /* We can assume here that the gmin of children do not overlap
-             * because of the way _gmx_sel_evaluate_or() works. */
-            gmx_ana_index_reserve(gmin, g->isize);
-            gmx_ana_index_reserve(gmax, g->isize);
-            gmx_ana_index_copy(gmin, sel->child->cdata->gmin, FALSE);
-            gmx_ana_index_copy(gmax, sel->child->cdata->gmax, FALSE);
-            child = sel->child->next;
-            while (child && gmin->isize < g->isize)
-            {
-                gmx_ana_index_merge(gmin, gmin, child->cdata->gmin);
-                gmx_ana_index_union(gmax, gmax, child->cdata->gmax);
-                child = child->next;
-            }
-            /* Update the static part if other expressions have static parts
-             * that are not included. */
-            if ((sel->child->cdata->flags & SEL_CDATA_STATIC)
-                && sel->child->v.u.g->isize < gmin->isize)
-            {
-                gmx_ana_index_reserve(sel->child->v.u.g, gmin->isize);
-                gmx_ana_index_copy(sel->child->v.u.g, gmin, FALSE);
-                if (sel->child->u.cgrp.isize > 0)
-                {
-                    gmx_ana_index_reserve(&sel->child->u.cgrp, gmin->isize);
-                    gmx_ana_index_copy(&sel->child->u.cgrp, gmin, FALSE);
-                }
-            }
-            break;
-
-        case BOOL_XOR: /* Should not be reached */
-            gmx_impl("xor expressions not implemented");
-            break;
-    }
-}
-
-/*! \brief
- * Evaluates the static parts of \p sel and analyzes the structure.
- * 
- * \param[in]     data Evaluation data.
- * \param[in,out] sel  Selection currently being evaluated.
- * \param[in]     g    Group for which \p sel should be evaluated.
- * \returns       0 on success, a non-zero error code on error.
- *
- * This function is used as the replacement for the \c t_selelem::evaluate
- * function pointer.
- * It does the single most complex task in the compiler: after all elements
- * have been processed, the \p gmin and \p gmax fields of \p t_compiler_data
- * have been properly initialized, enough memory has been allocated for
- * storing the value of each expression, and the static parts of the 
- * expressions have been evaluated.
- * The above is exactly true only for elements other than subexpressions:
- * another pass is required for subexpressions that are referred to more than
- * once and whose evaluation group is not known in advance.
- */
-static int
-analyze_static(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g)
-{
-    t_selelem       *child, *next;
-    gmx_bool             bDoMinMax;
-    int              rc;
-
-    if (sel->type != SEL_ROOT && g)
-    {
-        alloc_selection_data(sel, g->isize, FALSE);
-    }
-
-    bDoMinMax = (sel->cdata->flags & SEL_CDATA_MINMAXALLOC);
-    if (sel->type != SEL_SUBEXPR && bDoMinMax)
-    {
-        gmx_ana_index_deinit(sel->cdata->gmin);
-        gmx_ana_index_deinit(sel->cdata->gmax);
-    }
-
-    /* TODO: This switch is awfully long... */
-    rc = 0;
-    switch (sel->type)
-    {
-        case SEL_CONST:
-            rc = process_const(data, sel, g);
-            break;
-
-        case SEL_EXPRESSION:
-        case SEL_MODIFIER:
-            rc = _gmx_sel_evaluate_method_params(data, sel, g);
-            if (rc != 0)
-            {
-                return rc;
-            }
-            rc = init_method(sel, data->top, g->isize);
-            if (rc != 0)
-            {
-                return rc;
-            }
-            if (!(sel->flags & SEL_DYNAMIC))
-            {
-                rc = sel->cdata->evaluate(data, sel, g);
-                if (rc == 0 && (sel->cdata->flags & SEL_CDATA_STATIC))
-                {
-                    make_static(sel);
-                }
-            }
-            else
-            {
-                /* Modifiers need to be evaluated even though they process
-                 * positions to get the modified output groups from the
-                 * maximum possible selections. */
-                if (sel->type == SEL_MODIFIER)
-                {
-                    rc = sel->cdata->evaluate(data, sel, g);
-                }
-                if (bDoMinMax)
-                {
-                    gmx_ana_index_copy(sel->cdata->gmax, g, TRUE);
-                }
-            }
-            break;
-
-        case SEL_BOOLEAN:
-            if (!(sel->flags & SEL_DYNAMIC))
-            {
-                rc = sel->cdata->evaluate(data, sel, g);
-                if (rc == 0 && (sel->cdata->flags & SEL_CDATA_STATIC))
-                {
-                    make_static(sel);
-                }
-            }
-            else
-            {
-                /* Evalute the static part if there is more than one expression */
-                rc = evaluate_gmx_boolean_static_part(data, sel, g);
-                if (rc != 0)
-                {
-                    return rc;
-                }
-
-                /* Evaluate the selection.
-                 * If the type is gmx_boolean, we must explicitly handle the
-                 * static part evaluated in evaluate_gmx_boolean_static_part()
-                 * here because g may be larger. */
-                if (sel->u.boolt == BOOL_AND && sel->child->type == SEL_CONST)
-                {
-                    rc = sel->cdata->evaluate(data, sel, sel->child->v.u.g);
-                }
-                else
-                {
-                    rc = sel->cdata->evaluate(data, sel, g);
-                }
-                if (rc != 0)
-                {
-                    return rc;
-                }
-
-                /* Evaluate minimal and maximal selections */
-                evaluate_gmx_boolean_minmax_grps(sel, g, sel->cdata->gmin,
-                                             sel->cdata->gmax);
-            }
-            break;
-
-        case SEL_ARITHMETIC:
-            rc = sel->cdata->evaluate(data, sel, g);
-            if (rc != 0)
-            {
-                return rc;
-            }
-            if (!(sel->flags & SEL_DYNAMIC))
-            {
-                if (sel->cdata->flags & SEL_CDATA_STATIC)
-                {
-                    make_static(sel);
-                }
-            }
-            else if (bDoMinMax)
-            {
-                gmx_ana_index_copy(sel->cdata->gmax, g, TRUE);
-            }
-            break;
-
-        case SEL_ROOT:
-            rc = sel->cdata->evaluate(data, sel, g);
-            break;
-
-        case SEL_SUBEXPR:
-            if (sel->cdata->flags & (SEL_CDATA_SIMPLESUBEXPR | SEL_CDATA_FULLEVAL))
-            {
-                rc = sel->cdata->evaluate(data, sel, g);
-                _gmx_selvalue_setstore(&sel->v, sel->child->v.u.ptr);
-            }
-            else if (sel->u.cgrp.isize == 0)
-            {
-                gmx_ana_index_reserve(&sel->u.cgrp, g->isize);
-                rc = sel->cdata->evaluate(data, sel, g);
-                if (bDoMinMax)
-                {
-                    gmx_ana_index_copy(sel->cdata->gmin, sel->child->cdata->gmin, TRUE);
-                    gmx_ana_index_copy(sel->cdata->gmax, sel->child->cdata->gmax, TRUE);
-                }
-            }
-            else
-            {
-                int isize = gmx_ana_index_difference_size(g, &sel->u.cgrp);
-                if (isize > 0)
-                {
-                    isize += sel->u.cgrp.isize;
-                    gmx_ana_index_reserve(&sel->u.cgrp, isize);
-                    alloc_selection_data(sel, isize, FALSE);
-                }
-                rc = sel->cdata->evaluate(data, sel, g);
-                if (isize > 0 && bDoMinMax)
-                {
-                    gmx_ana_index_reserve(sel->cdata->gmin,
-                                          sel->cdata->gmin->isize
-                                          + sel->child->cdata->gmin->isize);
-                    gmx_ana_index_reserve(sel->cdata->gmax,
-                                          sel->cdata->gmax->isize
-                                          + sel->child->cdata->gmax->isize);
-                    gmx_ana_index_merge(sel->cdata->gmin, sel->cdata->gmin,
-                                        sel->child->cdata->gmin);
-                    gmx_ana_index_merge(sel->cdata->gmax, sel->cdata->gmax,
-                                        sel->child->cdata->gmax);
-                }
-            }
-            break;
-
-        case SEL_SUBEXPRREF:
-            if (!g && !(sel->cdata->flags & SEL_CDATA_SIMPLESUBEXPR))
-            {
-                /* The subexpression should have been evaluated if g is NULL
-                 * (i.e., this is a method parameter or a direct value of a
-                 * selection). */
-                alloc_selection_data(sel, sel->child->cdata->gmax->isize, TRUE);
-            }
-            rc = sel->cdata->evaluate(data, sel, g);
-            if (rc != 0)
-            {
-                return rc;
-            }
-            if ((sel->cdata->flags & SEL_CDATA_SIMPLESUBEXPR)
-                && (sel->child->child->flags & SEL_ALLOCVAL))
-            {
-                _gmx_selvalue_setstore(&sel->v, sel->child->child->v.u.ptr);
-            }
-            /* Store the parameter value if required */
-            store_param_val(sel);
-            if (!(sel->flags & SEL_DYNAMIC))
-            {
-                if (sel->cdata->flags & SEL_CDATA_STATIC)
-                {
-                    make_static(sel);
-                }
-            }
-            else if (bDoMinMax)
-            {
-                if ((sel->cdata->flags & SEL_CDATA_SIMPLESUBEXPR) || !g)
-                {
-                    gmx_ana_index_copy(sel->cdata->gmin, sel->child->cdata->gmin, TRUE);
-                    gmx_ana_index_copy(sel->cdata->gmax, sel->child->cdata->gmax, TRUE);
-                }
-                else
-                {
-                    gmx_ana_index_reserve(sel->cdata->gmin,
-                                          min(g->isize, sel->child->cdata->gmin->isize));
-                    gmx_ana_index_reserve(sel->cdata->gmax,
-                                          min(g->isize, sel->child->cdata->gmax->isize));
-                    gmx_ana_index_intersection(sel->cdata->gmin,
-                                               sel->child->cdata->gmin, g);
-                    gmx_ana_index_intersection(sel->cdata->gmax,
-                                               sel->child->cdata->gmax, g);
-                }
-            }
-            break;
-    }
-    /* Exit if there was some problem */
-    if (rc != 0)
-    {
-        return rc;
-    }
-
-    /* Update the minimal and maximal evaluation groups */
-    if (bDoMinMax)
-    {
-        gmx_ana_index_squeeze(sel->cdata->gmin);
-        gmx_ana_index_squeeze(sel->cdata->gmax);
-        sfree(sel->cdata->gmin->name);
-        sfree(sel->cdata->gmax->name);
-        sel->cdata->gmin->name = NULL;
-        sel->cdata->gmax->name = NULL;
-    }
-
-    /* Replace the result of the evaluation */
-    /* This is not necessary for subexpressions or for gmx_boolean negations
-     * because the evaluation function already has done it properly. */
-    if (sel->v.type == GROUP_VALUE && (sel->flags & SEL_DYNAMIC)
-        && sel->type != SEL_SUBEXPR
-        && !(sel->type == SEL_BOOLEAN && sel->u.boolt == BOOL_NOT))
-    {
-        if (sel->cdata->flags & SEL_CDATA_EVALMAX)
-        {
-            gmx_ana_index_copy(sel->v.u.g, sel->cdata->gmax, FALSE);
-        }
-        else
-        {
-            gmx_ana_index_copy(sel->v.u.g, sel->cdata->gmin, FALSE);
-        }
-    }
-
-    return 0;
-}
-
-
-/********************************************************************
- * EVALUATION GROUP INITIALIZATION
- ********************************************************************/
-
-/*! \brief
- * Initializes the evaluation group for a \ref SEL_ROOT element.
- *
- * \param     root Root element to initialize.
- * \param[in] gall Group of all atoms.
- *
- * Checks whether it is necessary to evaluate anything through the root
- * element, and either clears the evaluation function or initializes the
- * evaluation group.
- */
-static void
-init_root_item(t_selelem *root, gmx_ana_index_t *gall)
-{
-    t_selelem   *expr;
-    char        *name;
-
-    expr = root->child;
-    /* Subexpressions with non-static evaluation group should not be
-     * evaluated by the root, and neither should be single-reference
-     * subexpressions that don't evaluate for all atoms. */
-    if (expr->type == SEL_SUBEXPR
-        && (!(root->child->cdata->flags & SEL_CDATA_STATICEVAL)
-            || ((root->child->cdata->flags & SEL_CDATA_SIMPLESUBEXPR)
-                && !(root->child->cdata->flags & SEL_CDATA_FULLEVAL))))
-    {
-        root->evaluate = NULL;
-        if (root->cdata)
-        {
-            root->cdata->evaluate = NULL;
-        }
-    }
-
-    /* Set the evaluation group */
-    name = root->u.cgrp.name;
-    if (root->evaluate)
-    {
-        /* Non-atom-valued non-group expressions don't care about the group, so
-         * don't allocate any memory for it. */
-        if ((expr->flags & SEL_VARNUMVAL)
-            || ((expr->flags & SEL_SINGLEVAL) && expr->v.type != GROUP_VALUE))
-        {
-            gmx_ana_index_set(&root->u.cgrp, -1, NULL, NULL, 0);
-        }
-        else if (expr->cdata->gmax->isize == gall->isize)
-        {
-            /* Save some memory by only referring to the global group. */
-            gmx_ana_index_set(&root->u.cgrp, gall->isize, gall->index, NULL, 0);
-        }
-        else
-        {
-            gmx_ana_index_copy(&root->u.cgrp, expr->cdata->gmax, TRUE);
-        }
-        /* For selections, store the maximum group for
-         * gmx_ana_selcollection_evaluate_fin() as the value of the root
-         * element (unused otherwise). */
-        if (expr->type != SEL_SUBEXPR && expr->v.u.p->g)
-        {
-            t_selelem *child = expr;
-
-            /* TODO: This code is copied from parsetree.c; it would be better
-             * to have this hardcoded only in one place. */
-            while (child->type == SEL_MODIFIER)
-            {
-                child = child->child;
-                if (child->type == SEL_SUBEXPRREF)
-                {
-                    child = child->child->child;
-                }
-            }
-            if (child->type == SEL_SUBEXPRREF)
-            {
-                child = child->child->child;
-            }
-            if (child->child->flags & SEL_DYNAMIC)
-            {
-                _gmx_selelem_set_vtype(root, GROUP_VALUE);
-                root->flags  |= (SEL_ALLOCVAL | SEL_ALLOCDATA);
-                _gmx_selvalue_reserve(&root->v, 1);
-                gmx_ana_index_copy(root->v.u.g, expr->v.u.p->g, TRUE);
-            }
-        }
-    }
-    else
-    {
-        gmx_ana_index_clear(&root->u.cgrp);
-    }
-    root->u.cgrp.name = name;
-}
-
-
-/********************************************************************
- * FINAL SUBEXPRESSION OPTIMIZATION
- ********************************************************************/
-
-/*! \brief
- * Optimizes subexpression evaluation.
- *
- * \param     sel Root of the selection subtree to process.
- *
- * Optimizes away some unnecessary evaluation of subexpressions that are only
- * referenced once.
- */
-static void
-postprocess_item_subexpressions(t_selelem *sel)
-{
-    /* Process children. */
-    if (sel->type != SEL_SUBEXPRREF)
-    {
-        t_selelem *child;
-
-        child = sel->child;
-        while (child)
-        {
-            postprocess_item_subexpressions(child);
-            child = child->next;
-        }
-    }
-
-    /* Replace the evaluation function of statically evaluated subexpressions
-     * for which the static group was not known in advance. */
-    if (sel->type == SEL_SUBEXPR && sel->refcount > 2
-        && (sel->cdata->flags & SEL_CDATA_STATICEVAL)
-        && !(sel->cdata->flags & SEL_CDATA_FULLEVAL))
-    {
-        char *name;
-
-        /* We need to free memory allocated for the group, because it is no
-         * longer needed (and would be lost on next call to the evaluation
-         * function). But we need to preserve the name. */
-        name = sel->u.cgrp.name;
-        gmx_ana_index_deinit(&sel->u.cgrp);
-        sel->u.cgrp.name = name;
-
-        sel->evaluate = &_gmx_sel_evaluate_subexpr_staticeval;
-        if (sel->cdata)
-        {
-            sel->cdata->evaluate = sel->evaluate;
-        }
-        _gmx_selelem_free_values(sel->child);
-        sel->child->mempool = NULL;
-        _gmx_selvalue_setstore(&sel->child->v, sel->v.u.ptr);
-        sel->child->flags &= ~(SEL_ALLOCVAL | SEL_ALLOCDATA);
-    }
-
-    /* Adjust memory allocation flags for subexpressions that are used only
-     * once.  This is not strictly necessary, but we do it to have the memory
-     * managed consistently for all types of subexpressions. */
-    if (sel->type == SEL_SUBEXPRREF
-        && (sel->cdata->flags & SEL_CDATA_SIMPLESUBEXPR))
-    {
-        if (sel->child->child->flags & SEL_ALLOCVAL)
-        {
-            sel->flags |= SEL_ALLOCVAL;
-            sel->flags |= (sel->child->child->flags & SEL_ALLOCDATA);
-            sel->v.nalloc = sel->child->child->v.nalloc;
-            sel->child->child->flags &= ~(SEL_ALLOCVAL | SEL_ALLOCDATA);
-            sel->child->child->v.nalloc = -1;
-        }
-    }
-
-    /* Do the same for subexpressions that are evaluated at once for all atoms. */
-    if (sel->type == SEL_SUBEXPR
-        && !(sel->cdata->flags & SEL_CDATA_SIMPLESUBEXPR)
-        && (sel->cdata->flags & SEL_CDATA_FULLEVAL))
-    {
-        sel->flags |= SEL_ALLOCVAL;
-        sel->flags |= (sel->child->flags & SEL_ALLOCDATA);
-        sel->v.nalloc = sel->child->v.nalloc;
-        sel->child->flags &= ~(SEL_ALLOCVAL | SEL_ALLOCDATA);
-        sel->child->v.nalloc = -1;
-    }
-}
-
-
-/********************************************************************
- * COM CALCULATION INITIALIZATION
- ********************************************************************/
-
-/*! \brief
- * Initializes COM/COG calculation for method expressions that require it.
- *
- * \param     sel    Selection subtree to process.
- * \param[in,out] pcc   Position calculation collection to use.
- * \param[in] type   Default position calculation type.
- * \param[in] flags  Flags for default position calculation.
- * \returns   0 on success, a non-zero error code on error.
- *
- * Searches recursively through the selection tree for dynamic
- * \ref SEL_EXPRESSION elements that define the \c gmx_ana_selmethod_t::pupdate
- * function.
- * For each such element found, position calculation is initialized
- * for the maximal evaluation group.
- * The type of the calculation is determined by \p type and \p flags.
- * No calculation is initialized if \p type equals \ref POS_ATOM and
- * the method also defines the \c gmx_ana_selmethod_t::update method.
- */
-static int
-init_item_comg(t_selelem *sel, gmx_ana_poscalc_coll_t *pcc,
-               e_poscalc_t type, int flags)
-{
-    t_selelem *child;
-    int        rc;
-
-    /* Initialize COM calculation for dynamic selections now that we know the maximal evaluation group */
-    if (sel->type == SEL_EXPRESSION && sel->u.expr.method
-        && sel->u.expr.method->pupdate)
-    {
-        if (!sel->u.expr.method->update || type != POS_ATOM)
-        {
-            /* Create a default calculation if one does not yet exist */
-            int cflags;
-            cflags = 0;
-            if (!(sel->cdata->flags & SEL_CDATA_STATICEVAL))
-            {
-                cflags |= POS_DYNAMIC;
-            }
-            if (!sel->u.expr.pc)
-            {
-                cflags |= flags;
-                rc = gmx_ana_poscalc_create(&sel->u.expr.pc, pcc, type, cflags);
-                if (rc != 0)
-                {
-                    return rc;
-                }
-            }
-            else
-            {
-                gmx_ana_poscalc_set_flags(sel->u.expr.pc, cflags);
-            }
-            gmx_ana_poscalc_set_maxindex(sel->u.expr.pc, sel->cdata->gmax);
-            snew(sel->u.expr.pos, 1);
-            gmx_ana_poscalc_init_pos(sel->u.expr.pc, sel->u.expr.pos);
-        }
-    }
-
-    /* Call recursively for all children unless the children have already been processed */
-    if (sel->type != SEL_SUBEXPRREF)
-    {
-        child = sel->child;
-        while (child)
-        {
-            rc = init_item_comg(child, pcc, type, flags);
-            if (rc != 0)
-            {
-                return rc;
-            }
-            child = child->next;
-        }
-    }
-    return 0;
-}
-
-
-/********************************************************************
- * COMPILER DATA FREEING
- ********************************************************************/
-
-/*! \brief
- * Frees the allocated compiler data recursively.
- *
- * \param     sel Root of the selection subtree to process.
- *
- * Frees the data allocated for the compilation process.
- */
-static void
-free_item_compilerdata(t_selelem *sel)
-{
-    t_selelem *child;
-
-    /* Free compilation data */
-    _gmx_selelem_free_compiler_data(sel);
-
-    /* Call recursively for all children unless the children have already been processed */
-    if (sel->type != SEL_SUBEXPRREF)
-    {
-        child = sel->child;
-        while (child)
-        {
-            free_item_compilerdata(child);
-            child = child->next;
-        }
-    }
-}
-
-
-/********************************************************************
- * MASS AND CHARGE CALCULATION
- ********************************************************************/
-
-/*! \brief
- * Initializes total masses and charges for selections.
- *
- * \param[in]     top   Topology information.
- * \param[in]     ngrps Number of elements in the \p sel array.
- * \param[in,out] sel   Array of selections to update.
- * \param[in]     bMaskOnly TRUE if the positions will always be calculated
- *   for all atoms, i.e., the masses/charges do not change.
- */
-static void
-calculate_mass_charge(t_topology *top, int ngrps, gmx_ana_selection_t *sel[],
-                      gmx_bool bMaskOnly)
-{
-    int   g, b, i;
-
-    for (g = 0; g < ngrps; ++g)
-    {
-        sel[g]->g = sel[g]->p.g;
-        snew(sel[g]->orgm, sel[g]->p.nr);
-        snew(sel[g]->orgq, sel[g]->p.nr);
-        for (b = 0; b < sel[g]->p.nr; ++b)
-        {
-            sel[g]->orgq[b] = 0;
-            if (top)
-            {
-                sel[g]->orgm[b] = 0;
-                for (i = sel[g]->p.m.mapb.index[b]; i < sel[g]->p.m.mapb.index[b+1]; ++i)
-                {
-                    sel[g]->orgm[b] += top->atoms.atom[sel[g]->g->index[i]].m;
-                    sel[g]->orgq[b] += top->atoms.atom[sel[g]->g->index[i]].q;
-                }
-            }
-            else
-            {
-                sel[g]->orgm[b] = 1;
-            }
-        }
-        if (sel[g]->bDynamic && !bMaskOnly)
-        {
-            snew(sel[g]->m, sel[g]->p.nr);
-            snew(sel[g]->q, sel[g]->p.nr);
-            for (b = 0; b < sel[g]->p.nr; ++b)
-            {
-                sel[g]->m[b] = sel[g]->orgm[b];
-                sel[g]->q[b] = sel[g]->orgq[b];
-            }
-        }
-        else
-        {
-            sel[g]->m = sel[g]->orgm;
-            sel[g]->q = sel[g]->orgq;
-        }
-    }
-}
-
-
-/********************************************************************
- * MAIN COMPILATION FUNCTION
- ********************************************************************/
-
-/*!
- * \param[in,out] sc     Selection collection to debug.
- * \param[in]     bDebug If TRUE, later call to gmx_ana_selcollection_compile()
- *     will print out intermediate selection trees.
- */
-void
-gmx_ana_selcollection_set_compile_debug(gmx_ana_selcollection_t *sc, gmx_bool bDebug)
-{
-    sc->bDebugCompile = bDebug;
-}
-
-/*!
- * \param[in,out] sc Selection collection to be compiled.
- * \returns       0 on successful compilation, a non-zero error code on error.
- *
- * Before compilation, the selection collection should have been initialized
- * with gmx_ana_selcollection_parse_*().
- * The compiled selection collection can be passed to
- * gmx_ana_selcollection_evaluate() to evaluate the selection for a frame.
- * If an error occurs, \p sc is cleared.
- *
- * The covered fraction information in \p sc is initialized to
- * \ref CFRAC_NONE.
- */
-int
-gmx_ana_selcollection_compile(gmx_ana_selcollection_t *sc)
-{
-    gmx_sel_evaluate_t  evaldata;
-    t_selelem   *item;
-    e_poscalc_t  post;
-    int          flags;
-    int          rc;
-
-    rc = _gmx_sel_mempool_create(&sc->mempool);
-    if (rc != 0)
-    {
-        return rc;
-    }
-    _gmx_sel_evaluate_init(&evaldata, sc->mempool, &sc->gall,
-                           sc->top, NULL, NULL);
-
-    /* Clear the symbol table because it is not possible to parse anything
-     * after compilation, and variable references in the symbol table can
-     * also mess up the compilation and/or become invalid.
-     */
-    _gmx_selcollection_clear_symtab(sc);
-
-    /* Remove any unused variables. */
-    sc->root = remove_unused_subexpressions(sc->root);
-    /* Extract subexpressions into separate roots */
-    sc->root = extract_subexpressions(sc->root);
-
-    /* Initialize the evaluation callbacks and process the tree structure
-     * to conform to the expectations of the callback functions. */
-    /* Also, initialize and allocate the compiler data structure */
-    item = sc->root;
-    while (item)
-    {
-        /* Process gmx_boolean and arithmetic expressions. */
-        optimize_gmx_boolean_expressions(item);
-        reorder_gmx_boolean_static_children(item);
-        if (!optimize_arithmetic_expressions(item))
-        {
-            /* FIXME: Clean up the collection */
-            return -1;
-        }
-        /* Initialize evaluation function. */
-        if (!init_item_evalfunc(item))
-        {
-            /* FIXME: Clean up the collection */
-            return -1;
-        }
-        setup_memory_pooling(item, sc->mempool);
-        /* Initialize the compiler data */
-        init_item_compilerdata(item);
-        init_item_staticeval(item);
-        item = item->next;
-    }
-    /* Initialize subexpression flags and evaluation output.
-     * Requires compiler flags for the full tree. */
-    item = sc->root;
-    while (item)
-    {
-        init_item_subexpr_flags(item);
-        init_item_evaloutput(item);
-        item = item->next;
-    }
-    /* Initialize minimum/maximum index groups.
-     * Requires evaluation output for the full tree. */
-    item = sc->root;
-    while (item)
-    {
-        init_item_minmax_groups(item);
-        item = item->next;
-    }
-    /* Initialize the evaluation index groups */
-    initialize_evalgrps(sc);
-
-    if (sc->bDebugCompile)
-    {
-        fprintf(stderr, "\nTree after initial compiler processing:\n");
-        gmx_ana_selcollection_print_tree(stderr, sc, FALSE);
-    }
-
-    /* Evaluate all static parts of the selection and analyze the tree
-     * to allocate enough memory to store the value of each dynamic subtree. */
-    item = sc->root;
-    while (item)
-    {
-        if (item->child->cdata->flags & SEL_CDATA_COMMONSUBEXPR)
-        {
-            mark_subexpr_dynamic(item->child, TRUE);
-        }
-        set_evaluation_function(item, &analyze_static);
-        rc = item->evaluate(&evaldata, item, NULL);
-        if (rc != 0)
-        {
-            /* FIXME: Clean up the collection */
-            return rc;
-        }
-        item = item->next;
-    }
-
-    /* At this point, static subexpressions no longer have references to them,
-     * so they can be removed. */
-    sc->root = remove_unused_subexpressions(sc->root);
-
-    if (sc->bDebugCompile)
-    {
-        fprintf(stderr, "\nTree after first analysis pass:\n");
-        gmx_ana_selcollection_print_tree(stderr, sc, FALSE);
-    }
-
-    /* Do a second pass to evaluate static parts of common subexpressions */
-    item = sc->root;
-    while (item)
-    {
-        if (item->child->cdata->flags & SEL_CDATA_COMMONSUBEXPR)
-        {
-            gmx_bool bMinMax = item->child->cdata->flags & SEL_CDATA_MINMAXALLOC;
-
-            mark_subexpr_dynamic(item->child, FALSE);
-            item->child->u.cgrp.isize = 0;
-            /* We won't clear item->child->v.u.g here, because it may
-             * be static, and hence actually point to item->child->cdata->gmax,
-             * which is used below. We could also check whether this is the
-             * case and only clear the group otherwise, but because the value
-             * is actually overwritten immediately in the evaluate call, we
-             * won't, because similar problems may arise if gmax handling ever
-             * changes and the check were not updated.
-             * For the same reason, we clear the min/max flag so that the
-             * evaluation group doesn't get messed up. */
-            set_evaluation_function(item, &analyze_static);
-            item->child->cdata->flags &= ~SEL_CDATA_MINMAXALLOC;
-            rc = item->evaluate(&evaldata, item->child, item->child->cdata->gmax);
-            if (bMinMax)
-            {
-                item->child->cdata->flags |= SEL_CDATA_MINMAXALLOC;
-            }
-            if (rc != 0)
-            {
-                /* FIXME: Clean up the collection */
-                return rc;
-            }
-        }
-        item = item->next;
-    }
-
-    /* We need a yet another pass of subexpression removal to remove static
-     * subexpressions referred to by common dynamic subexpressions. */
-    sc->root = remove_unused_subexpressions(sc->root);
-
-    if (sc->bDebugCompile)
-    {
-        fprintf(stderr, "\nTree after second analysis pass:\n");
-        gmx_ana_selcollection_print_tree(stderr, sc, FALSE);
-    }
-
-    /* Initialize evaluation groups, position calculations for methods, perform
-     * some final optimization, and free the memory allocated for the
-     * compilation. */
-    /* By default, use whole residues/molecules. */
-    flags = POS_COMPLWHOLE;
-    rc = gmx_ana_poscalc_type_from_enum(sc->rpost, &post, &flags);
-    if (rc != 0)
-    {
-        gmx_bug("invalid default reference position type");
-        /* FIXME: Clean up the collection */
-        return rc;
-    }
-    item = sc->root;
-    while (item)
-    {
-        init_root_item(item, &sc->gall);
-        postprocess_item_subexpressions(item);
-        rc = init_item_comg(item, sc->pcc, post, flags);
-        if (rc != 0)
-        {
-            /* FIXME: Clean up the collection */
-            return rc;
-        }
-        free_item_compilerdata(item);
-        item = item->next;
-    }
-
-    /* Allocate memory for the evaluation memory pool. */
-    rc = _gmx_sel_mempool_reserve(sc->mempool, 0);
-    if (rc != 0)
-    {
-        return rc;
-    }
-
-    /* Finish up by calculating total masses and charges. */
-    calculate_mass_charge(sc->top, sc->nr, sc->sel, sc->bMaskOnly);
-
-    return 0;
-}
diff --git a/src/gmxlib/selection/evaluate.c b/src/gmxlib/selection/evaluate.c
deleted file mode 100644 (file)
index 9fbe3c0..0000000
+++ /dev/null
@@ -1,1139 +0,0 @@
-/*
- *
- *                This source code is part of
- *
- *                 G   R   O   M   A   C   S
- *
- *          GROningen MAchine for Chemical Simulations
- *
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
- * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
- * Copyright (c) 2001-2009, The GROMACS development team,
- * check out http://www.gromacs.org for more information.
-
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * If you want to redistribute modifications, please consider that
- * scientific software is very special. Version control is crucial -
- * bugs must be traceable. We will be happy to consider code for
- * inclusion in the official distribution, but derived work must not
- * be called official GROMACS. Details are found in the README & COPYING
- * files - if they are missing, get the official version at www.gromacs.org.
- *
- * To help us fund GROMACS development, we humbly ask that you cite
- * the papers on the package - you can find them in the top README file.
- *
- * For more info, check our website at http://www.gromacs.org
- */
-/*! \internal \file
- * \brief Implementation of functions in evaluate.h.
- *
- * \todo
- * One of the major bottlenecks for selection performance is that all the
- * evaluation is carried out for atoms.
- * There are several cases when the evaluation could be done for residues
- * or molecules instead, including keywords that select by residue and
- * cases where residue centers are used as reference positions.
- * Implementing this would require a mechanism for recognizing whether
- * something can be evaluated by residue/molecule instead by atom, and
- * converting selections by residue/molecule into selections by atom
- * when necessary.
- */
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <string.h>
-
-#include <maths.h>
-#include <smalloc.h>
-#include <vec.h>
-
-#include <indexutil.h>
-#include <poscalc.h>
-#include <selection.h>
-#include <selmethod.h>
-
-#include "evaluate.h"
-#include "mempool.h"
-#include "selcollection.h"
-#include "selelem.h"
-
-/*!
- * \param[in] fp       File handle to receive the output.
- * \param[in] evalfunc Function pointer to print.
- */
-void
-_gmx_sel_print_evalfunc_name(FILE *fp, sel_evalfunc evalfunc)
-{
-    if (!evalfunc)
-        fprintf(fp, "none");
-    else if (evalfunc == &_gmx_sel_evaluate_root)
-        fprintf(fp, "root");
-    else if (evalfunc == &_gmx_sel_evaluate_static)
-        fprintf(fp, "static");
-    else if (evalfunc == &_gmx_sel_evaluate_subexpr_simple)
-        fprintf(fp, "subexpr_simple");
-    else if (evalfunc == &_gmx_sel_evaluate_subexpr_staticeval)
-        fprintf(fp, "subexpr_staticeval");
-    else if (evalfunc == &_gmx_sel_evaluate_subexpr)
-        fprintf(fp, "subexpr");
-    else if (evalfunc == &_gmx_sel_evaluate_subexprref_simple)
-        fprintf(fp, "ref_simple");
-    else if (evalfunc == &_gmx_sel_evaluate_subexprref)
-        fprintf(fp, "ref");
-    else if (evalfunc == &_gmx_sel_evaluate_method)
-        fprintf(fp, "method");
-    else if (evalfunc == &_gmx_sel_evaluate_modifier)
-        fprintf(fp, "mod");
-    else if (evalfunc == &_gmx_sel_evaluate_not)
-        fprintf(fp, "not");
-    else if (evalfunc == &_gmx_sel_evaluate_and)
-        fprintf(fp, "and");
-    else if (evalfunc == &_gmx_sel_evaluate_or)
-        fprintf(fp, "or");
-    else if (evalfunc == &_gmx_sel_evaluate_arithmetic)
-        fprintf(fp, "arithmetic");
-    else
-        fprintf(fp, "%p", (void*)(evalfunc));
-}
-
-/*!
- * \param[out] data Evaluation data structure to initialize.
- * \param[in]  mp   Memory pool for intermediate evaluation values.
- * \param[in]  gall Index group with all the atoms.
- * \param[in]  top  Topology structure for evaluation.
- * \param[in]  fr   New frame for evaluation.
- * \param[in]  pbc  New PBC information for evaluation.
- */
-void
-_gmx_sel_evaluate_init(gmx_sel_evaluate_t *data,
-                       gmx_sel_mempool_t *mp, gmx_ana_index_t *gall,
-                       t_topology *top, t_trxframe *fr, t_pbc *pbc)
-{
-    data->mp   = mp;
-    data->gall = gall;
-    data->top  = top;
-    data->fr   = fr;
-    data->pbc  = pbc;
-}
-
-/*! \brief
- * Recursively initializes the flags for evaluation.
- *
- * \param[in,out] sel Selection element to clear.
- *
- * The \ref SEL_INITFRAME flag is set for \ref SEL_EXPRESSION elements whose
- * method defines the \p init_frame callback (see sel_framefunc()), and
- * cleared for other elements.
- *
- * The \ref SEL_EVALFRAME flag is cleared for all elements.
- */
-static void
-init_frame_eval(t_selelem *sel)
-{
-    while (sel)
-    {
-        sel->flags &= ~(SEL_INITFRAME | SEL_EVALFRAME);
-        if (sel->type == SEL_EXPRESSION)
-        {
-            if (sel->u.expr.method && sel->u.expr.method->init_frame)
-            {
-                sel->flags |= SEL_INITFRAME;
-            }
-        }
-        if (sel->child && sel->type != SEL_SUBEXPRREF)
-        {
-            init_frame_eval(sel->child);
-        }
-        sel = sel->next;
-    }
-}
-
-/*!
- * \param[in,out] sc  The selection collection to evaluate.
- * \param[in] fr  Frame for which the evaluation should be carried out.
- * \param[in] pbc PBC data, or NULL if no PBC should be used.
- * \returns   0 on successful evaluation, a non-zero error code on error.
- *
- * This functions sets the global variables for topology, frame and PBC,
- * clears some information in the selection to initialize the evaluation
- * for a new frame, and evaluates \p sel and all the selections pointed by
- * the \p next pointers of \p sel.
- *
- * This is the only function that user code should call if they want to
- * evaluate a selection for a new frame.
- */
-int
-gmx_ana_selcollection_evaluate(gmx_ana_selcollection_t *sc,
-                               t_trxframe *fr, t_pbc *pbc)
-{
-    gmx_sel_evaluate_t  data;
-    t_selelem          *sel;
-    int                 g, i;
-    int                 rc;
-
-    _gmx_sel_evaluate_init(&data, sc->mempool, &sc->gall, sc->top, fr, pbc);
-    init_frame_eval(sc->root);
-    sel = sc->root;
-    while (sel)
-    {
-        /* Clear the evaluation group of subexpressions */
-        if (sel->child && sel->child->type == SEL_SUBEXPR)
-        {
-            sel->child->u.cgrp.isize = 0;
-            /* Not strictly necessary, because the value will be overwritten
-             * during first evaluation of the subexpression anyways, but we
-             * clear the group for clarity. Note that this is _not_ done during
-             * compilation because of some additional complexities involved
-             * (see compiler.c), so it should not be relied upon in
-             * _gmx_sel_evaluate_subexpr(). */
-            if (sel->child->v.type == GROUP_VALUE)
-            {
-                sel->child->v.u.g->isize = 0;
-            }
-        }
-        if (sel->evaluate)
-        {
-            rc = sel->evaluate(&data, sel, NULL);
-            if (rc != 0)
-            {
-                return rc;
-            }
-        }
-        sel = sel->next;
-    }
-    /* Update selection information */
-    for (g = 0; g < sc->nr; ++g)
-    {
-        gmx_ana_selection_t *sel = sc->sel[g];
-
-        if (sel->m != sel->orgm)
-        {
-            for (i = 0; i < sel->p.nr; ++i)
-            {
-                sel->m[i] = sel->orgm[sel->p.m.refid[i]];
-                sel->q[i] = sel->orgq[sel->p.m.refid[i]];
-            }
-        }
-        if (sel->bCFracDyn)
-        {
-            sel->cfrac = _gmx_selelem_estimate_coverfrac(sel->selelem);
-            sel->avecfrac += sel->cfrac;
-        }
-    }
-    return 0;
-}
-
-/*!
- * \param[in,out] sc  The selection collection to evaluate.
- * \param[in]     nframes Total number of frames.
- * \returns       0 on successful evaluation, a non-zero error code on error.
- */
-int
-gmx_ana_selcollection_evaluate_fin(gmx_ana_selcollection_t *sc, int nframes)
-{
-    t_selelem          *sel;
-    int                 g;
-
-    for (g = 0; g < sc->nr; ++g)
-    {
-        sel = sc->sel[g]->selelem;
-        if (sc->sel[g]->bDynamic)
-        {
-            gmx_ana_index_copy(sc->sel[g]->g, sel->v.u.g, FALSE);
-            sc->sel[g]->g->name = NULL;
-            gmx_ana_indexmap_update(&sc->sel[g]->p.m, sc->sel[g]->g, sc->bMaskOnly);
-            sc->sel[g]->p.nr = sc->sel[g]->p.m.nr;
-        }
-
-        if (sc->sel[g]->bCFracDyn)
-        {
-            sc->sel[g]->avecfrac /= nframes;
-        }
-    }
-    return 0;
-}
-
-/*!
- * \param[in] data Data for the current frame.
- * \param[in] sel  Selection element being evaluated.
- * \param[in] g    Group for which \p sel should be evaluated.
- * \returns   0 on success, a non-zero error code on error.
- *
- * Evaluates each child of \p sel in \p g.
- */
-int
-_gmx_sel_evaluate_children(gmx_sel_evaluate_t *data, t_selelem *sel,
-                           gmx_ana_index_t *g)
-{
-    t_selelem  *child;
-    int         rc;
-
-    child = sel->child;
-    while (child)
-    {
-        if (child->evaluate)
-        {
-            rc = child->evaluate(data, child, g);
-            if (rc != 0)
-            {
-                return rc;
-            }
-        }
-        child = child->next;
-    }
-    return 0;
-}
-
-/*!
- * \param[in] data Data for the current frame.
- * \param[in] sel Selection element being evaluated.
- * \param[in] g   Group for which \p sel should be evaluated
- *   (not used, can be NULL).
- * \returns   0 on success, a non-zero error code on error.
- *
- * Evaluates the first child element in the group defined by \p sel->u.cgrp.
- * If \p sel->u.cgrp is empty, nothing is done.
- * The value of \p sel is not touched (root elements do not evaluate to
- * values).
- *
- * This function can be used as \c t_selelem::evaluate for \ref SEL_ROOT
- * elements.
- */
-int
-_gmx_sel_evaluate_root(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g)
-{
-    int        rc;
-
-    if (sel->u.cgrp.isize == 0 || !sel->child->evaluate)
-    {
-        return 0;
-    }
-
-    rc = sel->child->evaluate(data, sel->child,
-                              sel->u.cgrp.isize < 0 ? NULL : &sel->u.cgrp);
-
-    return rc;
-}
-
-/*!
- * \param[in] data Data for the current frame.
- * \param[in] sel Selection element being evaluated.
- * \param[in] g   Group for which \p sel should be evaluated.
- * \returns   0 for success.
- *
- * Sets the value of \p sel to the intersection of \p g and \p sel->u.cgrp.
- *
- * This function can be used as \c t_selelem::evaluate for \ref SEL_CONST
- * elements with value type \ref GROUP_VALUE.
- */
-int
-_gmx_sel_evaluate_static(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g)
-{
-    gmx_ana_index_intersection(sel->v.u.g, &sel->u.cgrp, g);
-    return 0;
-}
-
-
-/*********************************************************************
- * SUBEXPRESSION EVALUATION
- *********************************************************************/
-
-/*!
- * \param[in] data Data for the current frame.
- * \param[in] sel  Selection element being evaluated.
- * \param[in] g    Group for which \p sel should be evaluated.
- * \returns   0 on success, a non-zero error code on error.
- *
- * Evaluates the child element (there should be exactly one) in \p g.
- * The compiler has taken care that the child actually stores the evaluated
- * value in the value pointer of this element.
- *
- * This function is used as \c t_selelem::evaluate for \ref SEL_SUBEXPR
- * elements that are used only once, and hence do not need full subexpression
- * handling.
- */
-int
-_gmx_sel_evaluate_subexpr_simple(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g)
-{
-    int        rc;
-
-    if (sel->child->evaluate)
-    {
-        rc = sel->child->evaluate(data, sel->child, g);
-        if (rc != 0)
-        {
-            return rc;
-        }
-    }
-    sel->v.nr = sel->child->v.nr;
-    return 0;
-}
-
-/*!
- * \param[in] data Data for the current frame.
- * \param[in] sel  Selection element being evaluated.
- * \param[in] g    Group for which \p sel should be evaluated.
- * \returns   0 on success, a non-zero error code on error.
- *
- * If this is the first call for this frame, evaluates the child element
- * there should be exactly one in \p g.
- * The compiler has taken care that the child actually stores the evaluated
- * value in the value pointer of this element.
- * Assumes that \p g is persistent for the duration of the whole evaluation.
- *
- * This function is used as \c t_selelem::evaluate for \ref SEL_SUBEXPR
- * elements that have a static evaluation group, and hence do not need full
- * subexpression handling.
- */
-int
-_gmx_sel_evaluate_subexpr_staticeval(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g)
-{
-    if (sel->u.cgrp.isize == 0)
-    {
-        int  rc;
-
-        rc = sel->child->evaluate(data, sel->child, g);
-        if (rc != 0)
-        {
-            return rc;
-        }
-        sel->v.nr = sel->child->v.nr;
-        gmx_ana_index_set(&sel->u.cgrp, g->isize, g->index, sel->u.cgrp.name, 0);
-    }
-    return 0;
-}
-
-/*!
- * \param[in]  data  Data for the current frame.
- * \param[in]  sel   Selection element being evaluated.
- * \param[in]  g     Group for which \p sel should be evaluated.
- * \returns    0 on success, a non-zero error code on error.
- *
- * Finds the part of \p g for which the subexpression
- * has not yet been evaluated by comparing \p g to \p sel->u.cgrp.
- * If the part is not empty, the child expression is evaluated for this
- * part, and the results merged to the old values of the child.
- * The value of \p sel itself is undefined after the call.
- *
- * \todo
- * The call to gmx_ana_index_difference() can take quite a lot of unnecessary
- * time if the subexpression is evaluated either several times for the same
- * group or for completely distinct groups.
- * However, in the majority of cases, these situations occur when
- * _gmx_sel_evaluate_subexpr_staticeval() can be used, so this should not be a
- * major problem.
- */
-int
-_gmx_sel_evaluate_subexpr(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g)
-{
-    gmx_ana_index_t  gmiss;
-    int              rc;
-
-    if (sel->u.cgrp.isize == 0)
-    {
-        char *name;
-        void *old_ptr    = sel->child->v.u.ptr;
-        int   old_nalloc = sel->child->v.nalloc;
-        _gmx_selvalue_setstore(&sel->child->v, sel->v.u.ptr);
-        rc = sel->child->evaluate(data, sel->child, g);
-        _gmx_selvalue_setstore_alloc(&sel->child->v, old_ptr, old_nalloc);
-        if (rc != 0)
-        {
-            return rc;
-        }
-        /* We need to keep the name for the cgrp across the copy to avoid
-         * problems if g has a name set. */
-        name = sel->u.cgrp.name;
-        gmx_ana_index_copy(&sel->u.cgrp, g, FALSE);
-        sel->u.cgrp.name = name;
-        gmiss.isize = 0;
-    }
-    else
-    {
-        /* We allocate some extra memory here to avoid some computation. */
-        rc = _gmx_sel_mempool_alloc_group(data->mp, &gmiss, g->isize);
-        if (rc != 0)
-        {
-            return rc;
-        }
-        gmx_ana_index_difference(&gmiss, g, &sel->u.cgrp);
-        if (gmiss.isize == 0)
-        {
-            _gmx_sel_mempool_free_group(data->mp, &gmiss);
-        }
-    }
-    if (gmiss.isize > 0)
-    {
-        rc = _gmx_selelem_mempool_reserve(sel->child, gmiss.isize);
-        if (rc != 0)
-        {
-            return rc;
-        }
-        /* Evaluate the missing values for the child */
-        rc = sel->child->evaluate(data, sel->child, &gmiss);
-        if (rc != 0)
-        {
-            return rc;
-        }
-        /* Merge the missing values to the existing ones. */
-        if (sel->v.type == GROUP_VALUE)
-        {
-            gmx_ana_index_merge(sel->v.u.g, sel->child->v.u.g, sel->v.u.g);
-        }
-        else
-        {
-            int  i, j, k;
-
-            i = sel->u.cgrp.isize - 1;
-            j = gmiss.isize - 1;
-            /* TODO: This switch is kind of ugly, but it may be difficult to
-             * do this portably without C++ templates. */
-            switch (sel->v.type)
-            {
-                case INT_VALUE:
-                    for (k = sel->u.cgrp.isize + gmiss.isize - 1; k >= 0; k--)
-                    {
-                        if (i < 0 || (j >= 0 && sel->u.cgrp.index[i] < gmiss.index[j]))
-                        {
-                            sel->v.u.i[k] = sel->v.u.i[j--];
-                        }
-                        else
-                        {
-                            sel->v.u.i[k] = sel->child->v.u.i[i--];
-                        }
-                    }
-                    break;
-
-                case REAL_VALUE:
-                    for (k = sel->u.cgrp.isize + gmiss.isize - 1; k >= 0; k--)
-                    {
-                        if (i < 0 || (j >= 0 && sel->u.cgrp.index[i] < gmiss.index[j]))
-                        {
-                            sel->v.u.r[k] = sel->v.u.r[j--];
-                        }
-                        else
-                        {
-                            sel->v.u.r[k] = sel->child->v.u.r[i--];
-                        }
-                    }
-                    break;
-
-                case STR_VALUE:
-                    for (k = sel->u.cgrp.isize + gmiss.isize - 1; k >= 0; k--)
-                    {
-                        if (i < 0 || (j >= 0 && sel->u.cgrp.index[i] < gmiss.index[j]))
-                        {
-                            sel->v.u.s[k] = sel->v.u.s[j--];
-                        }
-                        else
-                        {
-                            sel->v.u.s[k] = sel->child->v.u.s[i--];
-                        }
-                    }
-                    break;
-
-                case POS_VALUE:
-                    /* TODO: Implement this */
-                    gmx_impl("position subexpressions not implemented properly");
-                    return -1;
-
-                case NO_VALUE:
-                case GROUP_VALUE:
-                    gmx_bug("internal error");
-                    return -1;
-            }
-        }
-        gmx_ana_index_merge(&sel->u.cgrp, &sel->u.cgrp, &gmiss);
-        _gmx_selelem_mempool_release(sel->child);
-        _gmx_sel_mempool_free_group(data->mp, &gmiss);
-    }
-    return 0;
-}
-
-/*!
- * \param[in] data Data for the current frame.
- * \param[in] sel Selection element being evaluated.
- * \param[in] g   Group for which \p sel should be evaluated.
- * \returns   0 for success.
- *
- * Sets the value pointers of the child and its child to point to the same
- * memory as the value pointer of this element to avoid copying, and then
- * evaluates evaluates the child.
- *
- * This function is used as \c t_selelem:evaluate for \ref SEL_SUBEXPRREF
- * elements for which the \ref SEL_SUBEXPR does not have other references.
- */
-int
-_gmx_sel_evaluate_subexprref_simple(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g)
-{
-    if (g)
-    {
-        int rc;
-
-        _gmx_selvalue_setstore(&sel->child->v, sel->v.u.ptr);
-        _gmx_selvalue_setstore_alloc(&sel->child->child->v, sel->v.u.ptr,
-                                     sel->child->child->v.nalloc);
-        rc = sel->child->evaluate(data, sel->child, g);
-        if (rc != 0)
-        {
-            return rc;
-        }
-    }
-    sel->v.nr = sel->child->v.nr;
-    if (sel->u.param)
-    {
-        sel->u.param->val.nr = sel->v.nr;
-        if (sel->u.param->nvalptr)
-        {
-            *sel->u.param->nvalptr = sel->u.param->val.nr;
-        }
-    }
-    return 0;
-}
-
-/*!
- * \param[in] data Data for the current frame.
- * \param[in] sel Selection element being evaluated.
- * \param[in] g   Group for which \p sel should be evaluated.
- * \returns   0 on success, a non-zero error code on error.
- *
- * If the value type is \ref POS_VALUE, the value of the child is simply
- * copied to set the value of \p sel (the child subexpression should
- * already have been evaluated by its root).
- * If the value type is something else, the child is evaluated for the
- * group \p g, and the value of the child is then copied.
- * There should be only one child element.
- *
- * This function is used as \c t_selelem::evaluate for \ref SEL_SUBEXPRREF
- * elements.
- */
-int
-_gmx_sel_evaluate_subexprref(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g)
-{
-    t_selelem *expr;
-    int        i, j;
-
-    if (g)
-    {
-        int rc;
-
-        rc = sel->child->evaluate(data, sel->child, g);
-        if (rc != 0)
-        {
-            return rc;
-        }
-    }
-    expr = sel->child;
-    switch (sel->v.type)
-    {
-        case INT_VALUE:
-            if (!g)
-            {
-                sel->v.nr = expr->v.nr;
-                memcpy(sel->v.u.i, expr->v.u.i, sel->v.nr*sizeof(*sel->v.u.i));
-            }
-            else
-            {
-                sel->v.nr = g->isize;
-                /* Extract the values corresponding to g */
-                for (i = j = 0; i < g->isize; ++i, ++j)
-                {
-                    while (sel->child->u.cgrp.index[j] < g->index[i])
-                    {
-                        ++j;
-                    }
-                    sel->v.u.i[i] = expr->v.u.i[j];
-                }
-            }
-            break;
-
-        case REAL_VALUE:
-            if (!g)
-            {
-                sel->v.nr = expr->v.nr;
-                memcpy(sel->v.u.r, expr->v.u.r, sel->v.nr*sizeof(*sel->v.u.r));
-            }
-            else
-            {
-                sel->v.nr = g->isize;
-                /* Extract the values corresponding to g */
-                for (i = j = 0; i < g->isize; ++i, ++j)
-                {
-                    while (sel->child->u.cgrp.index[j] < g->index[i])
-                    {
-                        ++j;
-                    }
-                    sel->v.u.r[i] = expr->v.u.r[j];
-                }
-            }
-            break;
-
-        case STR_VALUE:
-            if (!g)
-            {
-                sel->v.nr = expr->v.nr;
-                memcpy(sel->v.u.s, expr->v.u.s, sel->v.nr*sizeof(*sel->v.u.s));
-            }
-            else
-            {
-                sel->v.nr = g->isize;
-                /* Extract the values corresponding to g */
-                for (i = j = 0; i < g->isize; ++i, ++j)
-                {
-                    while (sel->child->u.cgrp.index[j] < g->index[i])
-                    {
-                        ++j;
-                    }
-                    sel->v.u.s[i] = expr->v.u.s[j];
-                }
-            }
-            break;
-
-        case POS_VALUE:
-            /* Currently, there is no need to do anything fancy here,
-             * but some future extensions may need a more flexible
-             * implementation. */
-            gmx_ana_pos_copy(sel->v.u.p, expr->v.u.p, FALSE);
-            break;
-
-        case GROUP_VALUE:
-            if (!g)
-            {
-                gmx_ana_index_copy(sel->v.u.g, expr->v.u.g, FALSE);
-            }
-            else
-            {
-                gmx_ana_index_intersection(sel->v.u.g, expr->v.u.g, g);
-            }
-            break;
-
-        default: /* should not be reached */
-            gmx_bug("invalid subexpression reference type");
-            return -1;
-    }
-    /* Store the number of values if needed */
-    if (sel->u.param)
-    {
-        sel->u.param->val.nr = sel->v.nr;
-        if (sel->u.param->nvalptr)
-        {
-            *sel->u.param->nvalptr = sel->u.param->val.nr;
-        }
-    }
-    return 0;
-}
-
-/********************************************************************
- * METHOD EXPRESSION EVALUATION
- ********************************************************************/
-
-/*!
- * \param[in] data Data for the current frame.
- * \param[in] sel Selection element being evaluated.
- * \param[in] g   Group for which \p sel should be evaluated.
- * \returns   0 on success, a non-zero error code on error.
- *
- * Evaluates each child of a \ref SEL_EXPRESSION element.
- * The value of \p sel is not touched.
- *
- * This function is not used as \c t_selelem::evaluate,
- * but is used internally.
- */
-int
-_gmx_sel_evaluate_method_params(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g)
-{
-    t_selelem *child;
-    int        rc;
-
-    child = sel->child;
-    while (child)
-    {
-        if (child->evaluate && !(child->flags & SEL_EVALFRAME))
-        {
-            if (child->flags & SEL_ATOMVAL)
-            {
-                rc = child->evaluate(data, child, g);
-            }
-            else
-            {
-                rc = child->evaluate(data, child, NULL);
-                child->flags |= SEL_EVALFRAME;
-            }
-            if (rc != 0)
-            {
-                return rc;
-            }
-        }
-        child = child->next;
-    }
-    return 0;
-}
-
-/*!
- * \param[in] data Data for the current frame.
- * \param[in] sel Selection element being evaluated.
- * \param[in] g   Group for which \p sel should be evaluated.
- * \returns   0 on success, a non-zero error code on error.
- *
- * Evaluates all child selections (using _gmx_sel_evaluate_method_params())
- * to evaluate any parameter values.
- * If this is the first time this expression is evaluated for
- * the frame, sel_framefunc() callback is called if one is provided.
- * If a reference position calculation has been initialized for this element,
- * the positions are also updated, and sel_updatefunc_pos() is used to
- * evaluate the value. Otherwise, sel_updatefunc() is used.
- *
- * This function is used as \c t_selelem::evaluate for \ref SEL_EXPRESSION
- * elements.
- */
-int
-_gmx_sel_evaluate_method(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g)
-{
-    int rc;
-
-    rc = _gmx_sel_evaluate_method_params(data, sel, g);
-    if (rc != 0)
-    {
-        return rc;
-    }
-    if (sel->flags & SEL_INITFRAME)
-    {
-        rc = sel->u.expr.method->init_frame(data->top, data->fr, data->pbc,
-                                            sel->u.expr.mdata);
-        sel->flags &= ~SEL_INITFRAME;
-        if (rc != 0)
-        {
-            return rc;
-        }
-    }
-    if (sel->u.expr.pc)
-    {
-        gmx_ana_poscalc_update(sel->u.expr.pc, sel->u.expr.pos, g,
-                               data->fr, data->pbc);
-        rc = sel->u.expr.method->pupdate(data->top, data->fr, data->pbc,
-                                         sel->u.expr.pos, &sel->v,
-                                         sel->u.expr.mdata);
-    }
-    else
-    {
-        rc = sel->u.expr.method->update(data->top, data->fr, data->pbc, g,
-                                        &sel->v, sel->u.expr.mdata);
-    }
-    return rc;
-}
-
-/*!
- * \param[in] data Data for the current frame.
- * \param[in] sel Selection element being evaluated.
- * \param[in] g   Group for which \p sel should be evaluated.
- * \returns   0 on success, a non-zero error code on error.
- *
- * Evaluates all child selections (using _gmx_sel_evaluate_method_params())
- * to evaluate any parameter values.
- * If this is the first time this expression is evaluated for
- * the frame, sel_framefunc() callback is called if one is provided.
- * The modifier is then evaluated using sel_updatefunc_pos().
- *
- * This function is used as \c t_selelem::evaluate for \ref SEL_MODIFIER
- * elements.
- */
-int
-_gmx_sel_evaluate_modifier(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g)
-{
-    int rc;
-
-    rc = _gmx_sel_evaluate_method_params(data, sel, g);
-    if (rc != 0)
-    {
-        return rc;
-    }
-    if (sel->flags & SEL_INITFRAME)
-    {
-        rc = sel->u.expr.method->init_frame(data->top, data->fr, data->pbc,
-                                            sel->u.expr.mdata);
-        sel->flags &= ~SEL_INITFRAME;
-        if (rc != 0)
-        {
-            return rc;
-        }
-    }
-    if (sel->child->v.type != POS_VALUE)
-    {
-        gmx_bug("non-position valued modifiers not implemented");
-        return -1;
-    }
-    rc = sel->u.expr.method->pupdate(data->top, data->fr, data->pbc,
-                                    sel->child->v.u.p,
-                                    &sel->v, sel->u.expr.mdata);
-    return rc;
-}
-
-
-/********************************************************************
- * BOOLEAN EXPRESSION EVALUATION
- ********************************************************************/
-
-/*!
- * \param[in] data Data for the current frame.
- * \param[in] sel Selection element being evaluated.
- * \param[in] g   Group for which \p sel should be evaluated.
- * \returns   0 on success, a non-zero error code on error.
- *
- * Evaluates the child element (there should be only one) in the group
- * \p g, and then sets the value of \p sel to the complement of the 
- * child value.
- *
- * This function is used as \c t_selelem::evaluate for \ref SEL_BOOLEAN
- * elements with \ref BOOL_NOT.
- */
-int
-_gmx_sel_evaluate_not(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g)
-{
-    int rc;
-
-    rc = _gmx_selelem_mempool_reserve(sel->child, g->isize);
-    if (rc == 0)
-    {
-        rc = sel->child->evaluate(data, sel->child, g);
-    }
-    if (rc != 0)
-    {
-        return rc;
-    }
-    gmx_ana_index_difference(sel->v.u.g, g, sel->child->v.u.g);
-    _gmx_selelem_mempool_release(sel->child);
-    return 0;
-}
-
-/*!
- * \param[in] data Data for the current frame.
- * \param[in] sel Selection element being evaluated.
- * \param[in] g   Group for which \p sel should be evaluated.
- * \returns   0 on success, a non-zero error code on error.
- *
- * Short-circuiting evaluation of logical AND expressions.
- *
- * Starts by evaluating the first child element in the group \p g.
- * The each following child element is evaluated in the intersection
- * of all the previous values until all children have been evaluated
- * or the intersection becomes empty.
- * The value of \p sel is set to the intersection of all the (evaluated)
- * child values.
- *
- * If the first child does not have an evaluation function, it is skipped
- * and the evaluation is started at the second child.
- * This happens if the first child is a constant expression and during
- * compilation it was detected that the evaluation group is always a subset
- * of the constant group
- * (currently, the compiler never detects this).
- *
- * This function is used as \c t_selelem::evaluate for \ref SEL_BOOLEAN
- * elements with \ref BOOL_AND.
- */
-int
-_gmx_sel_evaluate_and(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g)
-{
-    t_selelem *child;
-    int        rc;
-
-    child = sel->child;
-    /* Skip the first child if it does not have an evaluation function. */
-    if (!child->evaluate)
-    {
-        child = child->next;
-    }
-    rc = _gmx_selelem_mempool_reserve(child, g->isize);
-    if (rc == 0)
-    {
-        rc = child->evaluate(data, child, g);
-    }
-    if (rc != 0)
-    {
-        return rc;
-    }
-    gmx_ana_index_copy(sel->v.u.g, child->v.u.g, FALSE);
-    _gmx_selelem_mempool_release(child);
-    child = child->next;
-    while (child && sel->v.u.g->isize > 0)
-    {
-        rc = _gmx_selelem_mempool_reserve(child, sel->v.u.g->isize);
-        if (rc == 0)
-        {
-            rc = child->evaluate(data, child, sel->v.u.g);
-        }
-        if (rc != 0)
-        {
-            return rc;
-        }
-        gmx_ana_index_intersection(sel->v.u.g, sel->v.u.g, child->v.u.g);
-        _gmx_selelem_mempool_release(child);
-        child = child->next;
-    }
-    return 0;
-}
-
-/*!
- * \param[in] data Data for the current frame.
- * \param[in] sel Selection element being evaluated.
- * \param[in] g   Group for which \p sel should be evaluated.
- * \returns   0 on success, a non-zero error code on error.
- *
- * Short-circuiting evaluation of logical OR expressions.
- *
- * Starts by evaluating the first child element in the group \p g.
- * For each subsequent child, finds the part of \p g that is not
- * included the value of any previous child, and evaluates the child
- * in that group until the last child is evaluated or all of \p g
- * is included in some child value.
- * The value of \p sel is set to the union of all the (evaluated)
- * child values.
- *
- * If the first child does not have an evaluation function, its value is
- * used without evaluation.
- * This happens if the first child is a constant expression, the selection
- * has been compiled, and the evaluation group is the same for each frame.
- * In this case, the compiler has taken care of that the child value is a
- * subset of \p g, making it unnecessary to evaluate it.
- *
- * This function is used as \c t_selelem::evaluate for \ref SEL_BOOLEAN
- * elements with \ref BOOL_OR.
- */
-int
-_gmx_sel_evaluate_or(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g)
-{
-    t_selelem     *child;
-    gmx_ana_index_t  tmp, tmp2;
-    int              rc;
-
-    child = sel->child;
-    if (child->evaluate)
-    {
-        rc = _gmx_selelem_mempool_reserve(child, g->isize);
-        if (rc == 0)
-        {
-            rc = child->evaluate(data, child, g);
-        }
-        if (rc != 0)
-        {
-            return rc;
-        }
-        gmx_ana_index_partition(sel->v.u.g, &tmp, g, child->v.u.g);
-        _gmx_selelem_mempool_release(child);
-    }
-    else
-    {
-        gmx_ana_index_partition(sel->v.u.g, &tmp, g, child->v.u.g);
-    }
-    child = child->next;
-    while (child && tmp.isize > 0)
-    {
-        tmp.name = NULL;
-        rc = _gmx_selelem_mempool_reserve(child, tmp.isize);
-        if (rc == 0)
-        {
-            rc = child->evaluate(data, child, &tmp);
-        }
-        if (rc != 0)
-        {
-            return rc;
-        }
-        gmx_ana_index_partition(&tmp, &tmp2, &tmp, child->v.u.g);
-        _gmx_selelem_mempool_release(child);
-        sel->v.u.g->isize += tmp.isize;
-        tmp.isize = tmp2.isize;
-        tmp.index = tmp2.index;
-        child = child->next;
-    }
-    gmx_ana_index_sort(sel->v.u.g);
-    return 0;
-}
-
-
-/********************************************************************
- * ARITHMETIC EVALUATION
- ********************************************************************/
-
-/*!
- * \param[in] data Data for the current frame.
- * \param[in] sel  Selection element being evaluated.
- * \param[in] g    Group for which \p sel should be evaluated.
- * \returns   0 on success, a non-zero error code on error.
- */
-int
-_gmx_sel_evaluate_arithmetic(gmx_sel_evaluate_t *data, t_selelem *sel,
-                             gmx_ana_index_t *g)
-{
-    t_selelem  *left, *right;
-    int         n, i, i1, i2;
-    real        lval, rval=0., val=0.;
-    int         rc;
-
-    left  = sel->child;
-    right = left->next;
-
-    if (left->mempool)
-    {
-        _gmx_selvalue_setstore(&left->v, sel->v.u.ptr);
-        if (right)
-        {
-            rc = _gmx_selelem_mempool_reserve(right, g->isize);
-            if (rc != 0)
-            {
-                return rc;
-            }
-        }
-    }
-    else if (right && right->mempool)
-    {
-        _gmx_selvalue_setstore(&right->v, sel->v.u.ptr);
-    }
-    rc = _gmx_sel_evaluate_children(data, sel, g);
-
-    n = (sel->flags & SEL_SINGLEVAL) ? 1 : g->isize;
-    sel->v.nr = n;
-    for (i = i1 = i2 = 0; i < n; ++i)
-    {
-        lval = left->v.u.r[i1];
-        if (sel->u.arith.type != ARITH_NEG)
-        {
-            rval = right->v.u.r[i2];
-        }
-        switch (sel->u.arith.type)
-        {
-            case ARITH_PLUS:    val = lval + rval;     break;
-            case ARITH_MINUS:   val = lval - rval;     break;
-            case ARITH_NEG:     val = -lval;           break;
-            case ARITH_MULT:    val = lval * rval;     break;
-            case ARITH_DIV:     val = lval / rval;     break;
-            case ARITH_EXP:     val = pow(lval, rval); break;
-        }
-        sel->v.u.r[i] = val;
-        if (!(left->flags & SEL_SINGLEVAL))
-        {
-            ++i1;
-        }
-        if (sel->u.arith.type != ARITH_NEG && !(right->flags & SEL_SINGLEVAL))
-        {
-            ++i2;
-        }
-    }
-
-    if (left->mempool)
-    {
-        _gmx_selvalue_setstore(&left->v, NULL);
-        if (right)
-        {
-            _gmx_selelem_mempool_release(right);
-        }
-    }
-    else if (right && right->mempool)
-    {
-        _gmx_selvalue_setstore(&right->v, NULL);
-    }
-    return 0;
-}
diff --git a/src/gmxlib/selection/evaluate.h b/src/gmxlib/selection/evaluate.h
deleted file mode 100644 (file)
index 99c15c7..0000000
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- *
- *                This source code is part of
- *
- *                 G   R   O   M   A   C   S
- *
- *          GROningen MAchine for Chemical Simulations
- *
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
- * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
- * Copyright (c) 2001-2009, The GROMACS development team,
- * check out http://www.gromacs.org for more information.
-
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * If you want to redistribute modifications, please consider that
- * scientific software is very special. Version control is crucial -
- * bugs must be traceable. We will be happy to consider code for
- * inclusion in the official distribution, but derived work must not
- * be called official GROMACS. Details are found in the README & COPYING
- * files - if they are missing, get the official version at www.gromacs.org.
- *
- * To help us fund GROMACS development, we humbly ask that you cite
- * the papers on the package - you can find them in the top README file.
- *
- * For more info, check our website at http://www.gromacs.org
- */
-/*! \internal \file
- * \brief Evaluation functions for sel_evalfunc().
- *
- * This is an implementation header: there should be no need to use it outside
- * this directory.
- * Users should only use gmx_ana_selcollection_evaluate() declared in
- * \ref selection.h to evaluate selections.
- *
- * The functions defined in this header file are all the possible values
- * for the \c t_selelem::evaluate field (in addition to NULL).
- */
-#ifndef SELECTION_EVALUATE_H
-#define SELECTION_EVALUATE_H
-
-#include <typedefs.h>
-
-#include <indexutil.h>
-
-#include "selelem.h"
-
-struct gmx_sel_mempool_t;
-
-/*! \internal \brief
- * Data structure for passing information required during evaluation.
- */
-typedef struct gmx_sel_evaluate_t
-{
-    /** Memory pool for intermediate values. */
-    struct gmx_sel_mempool_t *mp;
-    /** Index group that contains all the atoms. */
-    gmx_ana_index_t         *gall;
-    /** Topology information. */
-    t_topology              *top;
-    /** Current frame. */
-    t_trxframe              *fr;
-    /** PBC data. */
-    t_pbc                   *pbc;
-} gmx_sel_evaluate_t;
-
-/*! \name Utility functions
- */
-/*@{*/
-/** Initializes an evaluation data structure. */
-void
-_gmx_sel_evaluate_init(gmx_sel_evaluate_t *data,
-                       struct gmx_sel_mempool_t *mp, gmx_ana_index_t *gall,
-                       t_topology *top, t_trxframe *fr, t_pbc *pbc);
-/** Evaluates the children of a general selection element. */
-int
-_gmx_sel_evaluate_children(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g);
-/** Evaluates the children of a \ref SEL_EXPRESSION element. */
-int
-_gmx_sel_evaluate_method_params(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g);
-/*@}*/
-
-/*! \name Misc. evaluation functions
- */
-/*@{*/
-/** Evaluates a root selection element. */
-int
-_gmx_sel_evaluate_root(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g);
-/** Evaluates a static group selection element. */
-int
-_gmx_sel_evaluate_static(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g);
-/** Evaluates an arithmetic expression element. */
-int
-_gmx_sel_evaluate_arithmetic(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g);
-/*@}*/
-
-/*! \name Subexpression evaluation functions
- */
-/*@{*/
-/** Evaluates a subexpression when there is only one reference. */
-int
-_gmx_sel_evaluate_subexpr_simple(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g);
-/** Evaluates a subexpression when the evaluation group is static. */
-int
-_gmx_sel_evaluate_subexpr_staticeval(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g);
-/** Evaluates a subexpression. */
-int
-_gmx_sel_evaluate_subexpr(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g);
-/** Evaluates a subexpression reference when there are no other references. */
-int
-_gmx_sel_evaluate_subexprref_simple(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g);
-/** Evaluates a subexpression reference. */
-int
-_gmx_sel_evaluate_subexprref(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g);
-/*@}*/
-
-/*! \name Method evaluation functions
- */
-/*@{*/
-
-/** Evaluates a method expression. */
-int
-_gmx_sel_evaluate_method(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g);
-/** Evaluates a modifier expression. */
-int
-_gmx_sel_evaluate_modifier(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g);
-/*@}*/
-
-/*! \name Boolean evaluation functions
- */
-/*@{*/
-/** Evaluates a boolean NOT element. */
-int
-_gmx_sel_evaluate_not(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g);
-/** Evaluates a boolean AND element with short-circuiting. */
-int
-_gmx_sel_evaluate_and(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g);
-/** Evaluates a boolean OR element with short-circuiting. */
-int
-_gmx_sel_evaluate_or(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g);
-/*@}*/
-
-#endif
diff --git a/src/gmxlib/selection/keywords.h b/src/gmxlib/selection/keywords.h
deleted file mode 100644 (file)
index f28f2aa..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- *
- *                This source code is part of
- *
- *                 G   R   O   M   A   C   S
- *
- *          GROningen MAchine for Chemical Simulations
- *
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
- * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
- * Copyright (c) 2001-2009, The GROMACS development team,
- * check out http://www.gromacs.org for more information.
-
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * If you want to redistribute modifications, please consider that
- * scientific software is very special. Version control is crucial -
- * bugs must be traceable. We will be happy to consider code for
- * inclusion in the official distribution, but derived work must not
- * be called official GROMACS. Details are found in the README & COPYING
- * files - if they are missing, get the official version at www.gromacs.org.
- *
- * To help us fund GROMACS development, we humbly ask that you cite
- * the papers on the package - you can find them in the top README file.
- *
- * For more info, check our website at http://www.gromacs.org
- */
-/*! \internal \file
- * \brief Definitions of generic keyword evaluation structures.
- * 
- * This is an implementation header: there should be no need to use it outside
- * this directory.
- */
-#ifndef SELECTION_KEYWORDS_H
-#define SELECTION_KEYWORDS_H
-
-struct gmx_ana_selmethod_t;
-struct t_selelem;
-struct t_selexpr_param;
-
-/** Selection method data for comparison expression evaluation. */
-extern struct gmx_ana_selmethod_t sm_compare;
-
-/** Selection method data for integer keyword evaluation. */
-extern struct gmx_ana_selmethod_t sm_keyword_int;
-/** Selection method data for real keyword evaluation. */
-extern struct gmx_ana_selmethod_t sm_keyword_real;
-/** Selection method data for string keyword evaluation. */
-extern struct gmx_ana_selmethod_t sm_keyword_str;
-/** Selection method data for position keyword evaluation. */
-extern struct gmx_ana_selmethod_t sm_keyword_pos;
-
-/** Prints information about a comparison expression. */
-void
-_gmx_selelem_print_compare_info(FILE *fp, void *data);
-
-/** Sets the position type for position keyword evaluation. */
-void
-_gmx_selelem_set_kwpos_type(struct t_selelem *sel, const char *type);
-/** Sets the flags for position keyword evaluation. */
-void
-_gmx_selelem_set_kwpos_flags(struct t_selelem *sel, int flags);
-
-/** Does custom processing for parameters of the \c same selection method. */
-int
-_gmx_selelem_custom_init_same(struct gmx_ana_selmethod_t **method,
-                              struct t_selexpr_param *params, void *scanner);
-
-/** Initializes a selection element for evaluating a keyword in a given group. */
-int
-_gmx_sel_init_keyword_evaluator(struct t_selelem **sel,
-                                struct gmx_ana_selmethod_t *method,
-                                struct t_selexpr_param *param, void *scanner);
-
-#endif
diff --git a/src/gmxlib/selection/mempool.c b/src/gmxlib/selection/mempool.c
deleted file mode 100644 (file)
index 32d8aa0..0000000
+++ /dev/null
@@ -1,210 +0,0 @@
-/*
- *
- *                This source code is part of
- *
- *                 G   R   O   M   A   C   S
- *
- *          GROningen MAchine for Chemical Simulations
- *
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
- * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
- * Copyright (c) 2001-2009, The GROMACS development team,
- * check out http://www.gromacs.org for more information.
-
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * If you want to redistribute modifications, please consider that
- * scientific software is very special. Version control is crucial -
- * bugs must be traceable. We will be happy to consider code for
- * inclusion in the official distribution, but derived work must not
- * be called official GROMACS. Details are found in the README & COPYING
- * files - if they are missing, get the official version at www.gromacs.org.
- *
- * To help us fund GROMACS development, we humbly ask that you cite
- * the papers on the package - you can find them in the top README file.
- *
- * For more info, check our website at http://www.gromacs.org
- */
-/*! \internal \file
- * \brief Memory pooling for selection evaluation.
- *
- * \todo
- * Document these functions.
- */
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <assert.h>
-#include <stdlib.h>
-
-#include <gmx_fatal.h>
-#include <smalloc.h>
-
-#include <indexutil.h>
-
-#include "mempool.h"
-
-#define ALIGN_STEP 8
-
-typedef struct gmx_sel_mempool_block_t
-{
-    void                       *ptr;
-    size_t                      size;
-} gmx_sel_mempool_block_t;
-
-struct gmx_sel_mempool_t
-{
-    size_t                      currsize;
-    size_t                      freesize;
-    char                       *buffer;
-    char                       *freeptr;
-    int                         nblocks;
-    gmx_sel_mempool_block_t    *blockstack;
-    int                         blockstack_nalloc;
-    size_t                      maxsize;
-};
-
-int
-_gmx_sel_mempool_create(gmx_sel_mempool_t **mpp)
-{
-    gmx_sel_mempool_t *mp;
-
-    snew(mp, 1);
-    mp->currsize          = 0;
-    mp->freesize          = 0;
-    mp->buffer            = NULL;
-    mp->freeptr           = NULL;
-    mp->nblocks           = 0;
-    mp->blockstack        = NULL;
-    mp->blockstack_nalloc = 0;
-    mp->maxsize           = 0;
-    *mpp = mp;
-    return 0;
-}
-
-void
-_gmx_sel_mempool_destroy(gmx_sel_mempool_t *mp)
-{
-    if (!mp->buffer)
-    {
-        int  i;
-
-        for (i = 0; i < mp->nblocks; ++i)
-        {
-            sfree(mp->blockstack[i].ptr);
-        }
-    }
-    sfree(mp->buffer);
-    sfree(mp->blockstack);
-    sfree(mp);
-}
-
-int
-_gmx_sel_mempool_alloc(gmx_sel_mempool_t *mp, void **ptrp, size_t size)
-{
-    void   *ptr = NULL;
-    size_t  size_walign;
-
-    *ptrp = NULL;
-    size_walign = ((size + ALIGN_STEP - 1) / ALIGN_STEP) * ALIGN_STEP;
-    if (mp->buffer)
-    {
-        if (mp->freesize < size)
-        {
-            gmx_bug("out of memory pool memory");
-            return ENOMEM;
-        }
-        ptr = mp->freeptr;
-        mp->freeptr  += size_walign;
-        mp->freesize -= size_walign;
-        mp->currsize += size_walign;
-    }
-    else
-    {
-        ptr = malloc(size);
-        if (!ptr)
-        {
-            gmx_mem("out of memory");
-            return ENOMEM;
-        }
-        mp->currsize += size_walign;
-        if (mp->currsize > mp->maxsize)
-        {
-            mp->maxsize = mp->currsize;
-        }
-    }
-
-    if (mp->nblocks >= mp->blockstack_nalloc)
-    {
-        mp->blockstack_nalloc = mp->nblocks + 10;
-        srenew(mp->blockstack, mp->blockstack_nalloc);
-    }
-    mp->blockstack[mp->nblocks].ptr  = ptr;
-    mp->blockstack[mp->nblocks].size = size_walign;
-    mp->nblocks++;
-
-    *ptrp = ptr;
-    return 0;
-}
-
-void
-_gmx_sel_mempool_free(gmx_sel_mempool_t *mp, void *ptr)
-{
-    int size;
-
-    if (ptr == NULL)
-    {
-        return;
-    }
-    assert(mp->nblocks > 0 && mp->blockstack[mp->nblocks - 1].ptr == ptr);
-    mp->nblocks--;
-    size = mp->blockstack[mp->nblocks].size;
-    mp->currsize -= size;
-    if (mp->buffer)
-    {
-        mp->freeptr = (char *)ptr;
-        mp->freesize += size;
-    }
-    else
-    {
-        sfree(ptr);
-    }
-}
-
-int
-_gmx_sel_mempool_reserve(gmx_sel_mempool_t *mp, size_t size)
-{
-    assert(mp->nblocks == 0 && !mp->buffer);
-    if (size == 0)
-    {
-        size = mp->maxsize;
-    }
-    mp->buffer = (char *)malloc(size);
-    if (!mp->buffer)
-    {
-        gmx_mem("out of memory");
-        return ENOMEM;
-    }
-    mp->freesize = size;
-    mp->freeptr  = mp->buffer;
-    return 0;
-}
-
-int
-_gmx_sel_mempool_alloc_group(gmx_sel_mempool_t *mp, gmx_ana_index_t *g,
-                             int isize)
-{
-    return _gmx_sel_mempool_alloc(mp, (void **)&g->index,
-                                  sizeof(*g->index)*isize);
-}
-
-void
-_gmx_sel_mempool_free_group(gmx_sel_mempool_t *mp, gmx_ana_index_t *g)
-{
-    _gmx_sel_mempool_free(mp, g->index);
-    g->index = NULL;
-}
diff --git a/src/gmxlib/selection/mempool.h b/src/gmxlib/selection/mempool.h
deleted file mode 100644 (file)
index ca6abba..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- *
- *                This source code is part of
- *
- *                 G   R   O   M   A   C   S
- *
- *          GROningen MAchine for Chemical Simulations
- *
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
- * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
- * Copyright (c) 2001-2009, The GROMACS development team,
- * check out http://www.gromacs.org for more information.
-
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * If you want to redistribute modifications, please consider that
- * scientific software is very special. Version control is crucial -
- * bugs must be traceable. We will be happy to consider code for
- * inclusion in the official distribution, but derived work must not
- * be called official GROMACS. Details are found in the README & COPYING
- * files - if they are missing, get the official version at www.gromacs.org.
- *
- * To help us fund GROMACS development, we humbly ask that you cite
- * the papers on the package - you can find them in the top README file.
- *
- * For more info, check our website at http://www.gromacs.org
- */
-/*! \internal \file
- * \brief Declarations for memory pooling functions.
- *
- * This is an implementation header: there should be no need to use it outside
- * this directory.
- */
-#ifndef GMX_SELECTION_MEMPOOL_H
-#define GMX_SELECTION_MEMPOOL_H
-
-struct gmx_ana_index_t;
-
-typedef struct gmx_sel_mempool_t gmx_sel_mempool_t;
-
-/** Create an empty memory pool. */
-int
-_gmx_sel_mempool_create(gmx_sel_mempool_t **mpp);
-/** Destroy a memory pool. */
-void
-_gmx_sel_mempool_destroy(gmx_sel_mempool_t *mp);
-
-/** Allocate memory from a memory pool. */
-int
-_gmx_sel_mempool_alloc(gmx_sel_mempool_t *mp, void **ptrp, size_t size);
-/** Release memory allocated from a memory pool. */
-void
-_gmx_sel_mempool_free(gmx_sel_mempool_t *mp, void *ptr);
-/** Set the size of a memory pool. */
-int
-_gmx_sel_mempool_reserve(gmx_sel_mempool_t *mp, size_t size);
-
-/** Convenience function for allocating an index group from a memory pool. */
-int
-_gmx_sel_mempool_alloc_group(gmx_sel_mempool_t *mp, struct gmx_ana_index_t *g,
-                             int isize);
-/** Convenience function for freeing an index group from a memory pool. */
-void
-_gmx_sel_mempool_free_group(gmx_sel_mempool_t *mp, struct gmx_ana_index_t *g);
-
-#endif
diff --git a/src/gmxlib/selection/params.c b/src/gmxlib/selection/params.c
deleted file mode 100644 (file)
index 21ae7e8..0000000
+++ /dev/null
@@ -1,1246 +0,0 @@
-/*
- *
- *                This source code is part of
- *
- *                 G   R   O   M   A   C   S
- *
- *          GROningen MAchine for Chemical Simulations
- *
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
- * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
- * Copyright (c) 2001-2009, The GROMACS development team,
- * check out http://www.gromacs.org for more information.
-
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * If you want to redistribute modifications, please consider that
- * scientific software is very special. Version control is crucial -
- * bugs must be traceable. We will be happy to consider code for
- * inclusion in the official distribution, but derived work must not
- * be called official GROMACS. Details are found in the README & COPYING
- * files - if they are missing, get the official version at www.gromacs.org.
- *
- * To help us fund GROMACS development, we humbly ask that you cite
- * the papers on the package - you can find them in the top README file.
- *
- * For more info, check our website at http://www.gromacs.org
- */
-/*! \internal \file
- * \brief
- * Implementation of functions in selparam.h.
- */
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <smalloc.h>
-#include <string2.h>
-#include <vec.h>
-
-#include <position.h>
-#include <selmethod.h>
-#include <selparam.h>
-
-#include "parsetree.h"
-#include "position.h"
-#include "selelem.h"
-
-/*!
- * \param[in] name   Name of the parameter to search.
- * \param[in] nparam Number of parameters in the \p param array.
- * \param[in] param  Parameter array to search.
- * \returns   Pointer to the parameter in the \p param
- *   or NULL if no parameter with name \p name was found.
- *
- * The comparison is case-sensitive.
- */
-gmx_ana_selparam_t *
-gmx_ana_selparam_find(const char *name, int nparam, gmx_ana_selparam_t *param)
-{
-    int                i;
-
-    if (nparam == 0)
-    {
-        return NULL;
-    }
-    /* Find the first non-null parameter */
-    i = 0;
-    while (i < nparam && param[i].name == NULL)
-    {
-        ++i;
-    }
-    /* Process the special case of a NULL parameter */
-    if (name == NULL)
-    {
-        return (i == 0) ? NULL : &param[i-1];
-    }
-    for ( ; i < nparam; ++i)
-    {
-        if (!strcmp(param[i].name, name))
-        {
-            return &param[i];
-        }
-        /* Check for 'no' prefix on gmx_boolean parameters */
-        if (param[i].val.type == NO_VALUE
-            && strlen(name) > 2 && name[0] == 'n' && name[1] == 'o'
-            && !strcmp(param[i].name, name+2))
-        {
-            return &param[i];
-        }
-    }
-    return NULL;
-}
-
-/*! \brief
- * Does a type conversion on a \c t_selexpr_value.
- *
- * \param[in,out] value    Value to convert.
- * \param[in]     type     Type to convert to.
- * \param[in]     scanner  Scanner data structure.
- * \returns       0 on success, a non-zero value on error.
- */
-static int
-convert_value(t_selexpr_value *value, e_selvalue_t type, void *scanner)
-{
-    if (value->type == type || type == NO_VALUE)
-    {
-        return 0;
-    }
-    if (value->bExpr)
-    {
-        /* Conversion from atom selection to position using default
-         * reference positions. */
-        if (value->type == GROUP_VALUE && type == POS_VALUE)
-        {
-            value->u.expr =
-                _gmx_sel_init_position(value->u.expr, NULL, scanner);
-            if (value->u.expr == NULL)
-            {
-                return -1;
-            }
-            value->type = type;
-            return 0;
-        }
-        return -1;
-    }
-    else
-    {
-        /* Integers to floating point are easy */
-        if (value->type == INT_VALUE && type == REAL_VALUE)
-        {
-            value->u.r.r1 = (real)value->u.i.i1;
-            value->u.r.r2 = (real)value->u.i.i2;
-            value->type = type;
-            return 0;
-        }
-        /* Reals that are integer-valued can also be converted */
-        if (value->type == REAL_VALUE && type == INT_VALUE
-            && gmx_within_tol(value->u.r.r1, (int)value->u.r.r1, GMX_REAL_EPS)
-            && gmx_within_tol(value->u.r.r2, (int)value->u.r.r2, GMX_REAL_EPS))
-        {
-            value->u.i.i1 = (int)value->u.r.r1;
-            value->u.i.i2 = (int)value->u.r.r2;
-            value->type = type;
-            return 0;
-        }
-    }
-    return -1;
-}
-
-/*! \brief
- * Does a type conversion on a list of values.
- *
- * \param[in,out] values   Values to convert.
- * \param[in]     type     Type to convert to.
- * \param[in]     scanner  Scanner data structure.
- * \returns       0 on success, a non-zero value on error.
- */
-static int
-convert_values(t_selexpr_value *values, e_selvalue_t type, void *scanner)
-{
-    t_selexpr_value *value;
-    int              rc, rc1;
-
-    rc = 0;
-    value = values;
-    while (value)
-    {
-        rc1 = convert_value(value, type, scanner);
-        if (rc1 != 0 && rc == 0)
-        {
-            rc = rc1;
-        }
-        value = value->next;
-    }
-    /* FIXME: More informative error messages */
-    return rc;
-}
-
-/*! \brief
- * Adds a child element for a parameter, keeping the parameter order.
- *
- * \param[in,out] root  Root element to which the child is added.
- * \param[in]     child Child to add.
- * \param[in]     param Parameter for which this child is a value.
- *
- * Puts \p child in the child list of \p root such that the list remains
- * in the same order as the corresponding parameters.
- */
-static void
-place_child(t_selelem *root, t_selelem *child, gmx_ana_selparam_t *param)
-{
-    gmx_ana_selparam_t *ps;
-    int                 n;
-
-    ps = root->u.expr.method->param;
-    n  = param - ps;
-    /* Put the child element in the correct place */
-    if (!root->child || n < root->child->u.param - ps)
-    {
-        child->next = root->child;
-        root->child = child;
-    }
-    else
-    {
-        t_selelem *prev;
-
-        prev = root->child;
-        while (prev->next && prev->next->u.param - ps >= n)
-        {
-            prev = prev->next;
-        }
-        child->next = prev->next;
-        prev->next  = child;
-    }
-}
-
-/*! \brief
- * Comparison function for sorting integer ranges.
- * 
- * \param[in] a Pointer to the first range.
- * \param[in] b Pointer to the second range.
- * \returns   -1, 0, or 1 depending on the relative order of \p a and \p b.
- *
- * The ranges are primarily sorted based on their starting point, and
- * secondarily based on length (longer ranges come first).
- */
-static int
-cmp_int_range(const void *a, const void *b)
-{
-    if (((int *)a)[0] < ((int *)b)[0])
-    {
-        return -1;
-    }
-    if (((int *)a)[0] > ((int *)b)[0])
-    {
-        return 1;
-    }
-    if (((int *)a)[1] > ((int *)b)[1])
-    {
-        return -1;
-    }
-    return 0;
-}
-
-/*! \brief
- * Comparison function for sorting real ranges.
- *
- * \param[in] a Pointer to the first range.
- * \param[in] b Pointer to the second range.
- * \returns   -1, 0, or 1 depending on the relative order of \p a and \p b.
- *
- * The ranges are primarily sorted based on their starting point, and
- * secondarily based on length (longer ranges come first).
- */
-static int
-cmp_real_range(const void *a, const void *b)
-{
-    if (((real *)a)[0] < ((real *)b)[0])
-    {
-        return -1;
-    }
-    if (((real *)a)[0] > ((real *)b)[0])
-    {
-        return 1;
-    }
-    if (((real *)a)[1] > ((real *)b)[1])
-    {
-        return -1;
-    }
-    return 0;
-}
-
-/*! \brief
- * Parses the values for a parameter that takes integer or real ranges.
- * 
- * \param[in] nval   Number of values in \p values.
- * \param[in] values Pointer to the list of values.
- * \param     param  Parameter to parse.
- * \returns   TRUE if the values were parsed successfully, FALSE otherwise.
- */
-static gmx_bool
-parse_values_range(int nval, t_selexpr_value *values, gmx_ana_selparam_t *param)
-{
-    t_selexpr_value    *value;
-    int                *idata;
-    real               *rdata;
-    int                 i, j, n;
-
-    param->flags &= ~SPAR_DYNAMIC;
-    if (param->val.type != INT_VALUE && param->val.type != REAL_VALUE)
-    {
-        gmx_bug("internal error");
-        return FALSE;
-    }
-    idata = NULL;
-    rdata = NULL;
-    if (param->val.type == INT_VALUE)
-    {
-        snew(idata, nval*2);
-    }
-    else
-    {
-        snew(rdata, nval*2);
-    }
-    value = values;
-    i = 0;
-    while (value)
-    {
-        if (value->bExpr)
-        {
-            _gmx_selparser_error("expressions not supported within range parameters");
-            return FALSE;
-        }
-        if (value->type != param->val.type)
-        {
-            gmx_bug("internal error");
-            return FALSE;
-        }
-        if (param->val.type == INT_VALUE)
-        {
-            /* Make sure the input range is in increasing order */
-            if (value->u.i.i1 > value->u.i.i2)
-            {
-                int tmp       = value->u.i.i1;
-                value->u.i.i1 = value->u.i.i2;
-                value->u.i.i2 = tmp;
-            }
-            /* Check if the new range overlaps or extends the previous one */
-            if (i > 0 && value->u.i.i1 <= idata[i-1]+1 && value->u.i.i2 >= idata[i-2]-1)
-            {
-                idata[i-2] = min(idata[i-2], value->u.i.i1);
-                idata[i-1] = max(idata[i-1], value->u.i.i2);
-            }
-            else
-            {
-                idata[i++] = value->u.i.i1;
-                idata[i++] = value->u.i.i2;
-            }
-        }
-        else
-        {
-            /* Make sure the input range is in increasing order */
-            if (value->u.r.r1 > value->u.r.r2)
-            {
-                real tmp      = value->u.r.r1;
-                value->u.r.r1 = value->u.r.r2;
-                value->u.r.r2 = tmp;
-            }
-            /* Check if the new range overlaps or extends the previous one */
-            if (i > 0 && value->u.r.r1 <= rdata[i-1] && value->u.r.r2 >= rdata[i-2])
-            {
-                rdata[i-2] = min(rdata[i-2], value->u.r.r1);
-                rdata[i-1] = max(rdata[i-1], value->u.r.r2);
-            }
-            else
-            {
-                rdata[i++] = value->u.r.r1;
-                rdata[i++] = value->u.r.r2;
-            }
-        }
-        value = value->next;
-    }
-    n = i/2;
-    /* Sort the ranges and merge consequent ones */
-    if (param->val.type == INT_VALUE)
-    {
-        qsort(idata, n, 2*sizeof(int), &cmp_int_range);
-        for (i = j = 2; i < 2*n; i += 2)
-        {
-            if (idata[j-1]+1 >= idata[i])
-            {
-                if (idata[i+1] > idata[j-1])
-                {
-                    idata[j-1] = idata[i+1];
-                }
-            }
-            else
-            {
-                idata[j]   = idata[i];
-                idata[j+1] = idata[i+1];
-                j += 2;
-            }
-        }
-    }
-    else
-    {
-        qsort(rdata, n, 2*sizeof(real), &cmp_real_range);
-        for (i = j = 2; i < 2*n; i += 2)
-        {
-            if (rdata[j-1]+1 >= rdata[i])
-            {
-                if (rdata[i+1] > rdata[j-1])
-                {
-                    rdata[j-1] = rdata[i+1];
-                }
-            }
-            else
-            {
-                rdata[j]   = rdata[i];
-                rdata[j+1] = rdata[i+1];
-                j += 2;
-            }
-        }
-    }
-    n = j/2;
-    /* Store the values */
-    if (param->flags & SPAR_VARNUM)
-    {
-        param->val.nr  = n;
-        if (param->val.type == INT_VALUE)
-        {
-            srenew(idata, j);
-            _gmx_selvalue_setstore_alloc(&param->val, idata, j);
-        }
-        else
-        {
-            srenew(rdata, j);
-            _gmx_selvalue_setstore_alloc(&param->val, rdata, j);
-        }
-    }
-    else
-    {
-        if (n != param->val.nr)
-        {
-            _gmx_selparser_error("the value of parameter '%s' should consist of exactly one range",
-                                 param->name);       
-            sfree(idata);
-            sfree(rdata);
-            return FALSE;
-        }
-        if (param->val.type == INT_VALUE)
-        {
-            memcpy(param->val.u.i, idata, 2*n*sizeof(int));
-            sfree(idata);
-        }
-        else
-        {
-            memcpy(param->val.u.r, rdata, 2*n*sizeof(real));
-            sfree(rdata);
-        }
-    }
-    if (param->nvalptr)
-    {
-        *param->nvalptr = param->val.nr;
-    }
-    param->nvalptr = NULL;
-
-    return TRUE;
-}
-
-/*! \brief
- * Parses the values for a parameter that takes a variable number of values.
- * 
- * \param[in] nval   Number of values in \p values.
- * \param[in] values Pointer to the list of values.
- * \param     param  Parameter to parse.
- * \param     root   Selection element to which child expressions are added.
- * \returns   TRUE if the values were parsed successfully, FALSE otherwise.
- *
- * For integer ranges, the sequence of numbers from the first to second value
- * is stored, each as a separate value.
- */
-static gmx_bool
-parse_values_varnum(int nval, t_selexpr_value *values,
-                    gmx_ana_selparam_t *param, t_selelem *root)
-{
-    t_selexpr_value    *value;
-    int                 i, j;
-
-    param->flags &= ~SPAR_DYNAMIC;
-    /* Update nval if there are integer ranges. */
-    if (param->val.type == INT_VALUE)
-    {
-        value = values;
-        while (value)
-        {
-            if (value->type == INT_VALUE && !value->bExpr)
-            {
-                nval += abs(value->u.i.i2 - value->u.i.i1);
-            }
-            value = value->next;
-        }
-    }
-
-    /* Check that the value type is actually implemented */
-    if (param->val.type != INT_VALUE && param->val.type != REAL_VALUE
-        && param->val.type != STR_VALUE && param->val.type != POS_VALUE)
-    {
-        gmx_bug("internal error");
-        return FALSE;
-    }
-
-    /* Reserve appropriate amount of memory */
-    if (param->val.type == POS_VALUE)
-    {
-        gmx_ana_pos_reserve(param->val.u.p, nval, 0);
-        gmx_ana_pos_set_nr(param->val.u.p, nval);
-        gmx_ana_indexmap_init(&param->val.u.p->m, NULL, NULL, INDEX_UNKNOWN);
-    }
-    else
-    {
-        _gmx_selvalue_reserve(&param->val, nval);
-    }
-
-    value = values;
-    i     = 0;
-    while (value)
-    {
-        if (value->bExpr)
-        {
-            _gmx_selparser_error("expressions not supported within value lists");
-            return FALSE;
-        }
-        if (value->type != param->val.type)
-        {
-            gmx_bug("internal error");
-            return FALSE;
-        }
-        switch (param->val.type)
-        {
-            case INT_VALUE:
-                if (value->u.i.i1 <= value->u.i.i2)
-                {
-                    for (j = value->u.i.i1; j <= value->u.i.i2; ++j)
-                    {
-                        param->val.u.i[i++] = j;
-                    }
-                }
-                else
-                {
-                    for (j = value->u.i.i1; j >= value->u.i.i2; --j)
-                    {
-                        param->val.u.i[i++] = j;
-                    }
-                }
-                break;
-            case REAL_VALUE:
-                if (value->u.r.r1 != value->u.r.r2)
-                {
-                    _gmx_selparser_error("real ranges not supported for parameter '%s'", param->name);
-                    return FALSE;
-                }
-                param->val.u.r[i++] = value->u.r.r1;
-                break;
-            case STR_VALUE:  param->val.u.s[i++] = strdup(value->u.s); break;
-            case POS_VALUE:  copy_rvec(value->u.x, param->val.u.p->x[i++]); break;
-            default: /* Should not be reached */
-                gmx_bug("internal error");
-                return FALSE;
-        }
-        value = value->next;
-    }
-    param->val.nr = i;
-    if (param->nvalptr)
-    {
-        *param->nvalptr = param->val.nr;
-    }
-    param->nvalptr = NULL;
-    /* Create a dummy child element to store the string values.
-     * This element is responsible for freeing the values, but carries no
-     * other function. */
-    if (param->val.type == STR_VALUE)
-    {
-        t_selelem *child;
-
-        child = _gmx_selelem_create(SEL_CONST);
-        _gmx_selelem_set_vtype(child, STR_VALUE);
-        child->name = param->name;
-        child->flags &= ~SEL_ALLOCVAL;
-        child->flags |= SEL_FLAGSSET | SEL_VARNUMVAL | SEL_ALLOCDATA;
-        child->v.nr = param->val.nr;
-        _gmx_selvalue_setstore(&child->v, param->val.u.s);
-        /* Because the child is not group-valued, the u union is not used
-         * for anything, so we can abuse it by storing the parameter value
-         * as place_child() expects, but this is really ugly... */
-        child->u.param = param;
-        place_child(root, child, param);
-    }
-
-    return TRUE;
-}
-
-/*! \brief
- * Adds a new subexpression reference to a selection element.
- *
- * \param[in,out] root  Root element to which the subexpression is added.
- * \param[in]     param Parameter for which this expression is a value.
- * \param[in]     expr  Expression to add.
- * \returns       The created child element.
- *
- * Creates a new \ref SEL_SUBEXPRREF element and adds it into the child
- * list of \p root.
- * If \p expr is already a \ref SEL_SUBEXPRREF, it is used as it is.
- * \ref SEL_ALLOCVAL is cleared for the returned element.
- */
-static t_selelem *
-add_child(t_selelem *root, gmx_ana_selparam_t *param, t_selelem *expr)
-{
-    t_selelem          *child;
-    int                 rc;
-
-    if (root->type != SEL_EXPRESSION && root->type != SEL_MODIFIER)
-    {
-        gmx_bug("unsupported root element for selection parameter parser");
-        return NULL;
-    }
-    /* Create a subexpression reference element if necessary */
-    if (expr->type == SEL_SUBEXPRREF)
-    {
-        child = expr;
-    }
-    else
-    {
-        child = _gmx_selelem_create(SEL_SUBEXPRREF);
-        if (!child)
-        {
-            return NULL;
-        }
-        _gmx_selelem_set_vtype(child, expr->v.type);
-        child->child  = expr;
-    }
-    /* Setup the child element */
-    child->flags &= ~SEL_ALLOCVAL;
-    child->u.param = param;
-    if (child->v.type != param->val.type)
-    {
-        _gmx_selparser_error("invalid expression value for parameter '%s'",
-                             param->name);
-        goto on_error;
-    }
-    rc = _gmx_selelem_update_flags(child);
-    if (rc != 0)
-    {
-        goto on_error;
-    }
-    if ((child->flags & SEL_DYNAMIC) && !(param->flags & SPAR_DYNAMIC))
-    {
-        _gmx_selparser_error("parameter '%s' does not support dynamic values",
-                             param->name);
-        goto on_error;
-    }
-    if (!(child->flags & SEL_DYNAMIC))
-    {
-        param->flags &= ~SPAR_DYNAMIC;
-    }
-    /* Put the child element in the correct place */
-    place_child(root, child, param);
-    return child;
-
-on_error:
-    if (child != expr)
-    {
-        _gmx_selelem_free(child);
-    }
-    return NULL;
-}
-
-/*! \brief
- * Parses an expression value for a parameter that takes a variable number of values.
- * 
- * \param[in] nval   Number of values in \p values.
- * \param[in] values Pointer to the list of values.
- * \param     param  Parameter to parse.
- * \param     root   Selection element to which child expressions are added.
- * \returns   TRUE if the values were parsed successfully, FALSE otherwise.
- */
-static gmx_bool
-parse_values_varnum_expr(int nval, t_selexpr_value *values,
-                         gmx_ana_selparam_t *param, t_selelem *root)
-{
-    t_selexpr_value    *value;
-    t_selelem          *child;
-    t_selelem          *expr;
-
-    if (nval != 1 || !values->bExpr)
-    {
-        gmx_bug("internal error");
-        return FALSE;
-    }
-
-    value = values;
-    child = add_child(root, param, value->u.expr);
-    value->u.expr = NULL;
-    if (!child)
-    {
-        return FALSE;
-    }
-
-    /* Process single-valued expressions */
-    /* TODO: We should also handle SEL_SINGLEVAL expressions here */
-    if (child->v.type == POS_VALUE || child->v.type == GROUP_VALUE)
-    {
-        /* Set the value storage */
-        _gmx_selvalue_setstore(&child->v, param->val.u.ptr);
-        param->val.nr = 1;
-        if (param->nvalptr)
-        {
-            *param->nvalptr = param->val.nr;
-        }
-        param->nvalptr = NULL;
-        return TRUE;
-    }
-
-    if (!(child->flags & SEL_VARNUMVAL))
-    {
-        _gmx_selparser_error("invalid expression value for parameter '%s'",
-                             param->name);
-        return FALSE;
-    }
-
-    child->flags   |= SEL_ALLOCVAL;
-    param->val.nr   = -1;
-    *param->nvalptr = param->val.nr;
-    /* Rest of the initialization is done during compilation in
-     * init_method(). */
-
-    return TRUE;
-}
-
-/*! \brief
- * Initializes the storage of an expression value.
- *
- * \param[in,out] sel   Selection element that evaluates the value.
- * \param[in]     param Parameter to receive the value.
- * \param[in]     i     The value of \p sel evaluates the value \p i for
- *   \p param.
- *
- * Initializes the data pointer of \p sel such that the result is stored
- * as the value \p i of \p param.
- * This function is used internally by parse_values_std().
- */
-static gmx_bool
-set_expr_value_store(t_selelem *sel, gmx_ana_selparam_t *param, int i)
-{
-    if (sel->v.type != GROUP_VALUE && !(sel->flags & SEL_SINGLEVAL))
-    {
-        _gmx_selparser_error("invalid expression value for parameter '%s'",
-                             param->name);
-        return FALSE;
-    }
-    switch (sel->v.type)
-    {
-        case INT_VALUE:   sel->v.u.i = &param->val.u.i[i]; break;
-        case REAL_VALUE:  sel->v.u.r = &param->val.u.r[i]; break;
-        case STR_VALUE:   sel->v.u.s = &param->val.u.s[i]; break;
-        case POS_VALUE:   sel->v.u.p = &param->val.u.p[i]; break;
-        case GROUP_VALUE: sel->v.u.g = &param->val.u.g[i]; break;
-        default: /* Error */
-            gmx_bug("internal error");
-            return FALSE;
-    }
-    sel->v.nr = 1;
-    sel->v.nalloc = -1;
-    return TRUE;
-}
-
-/*! \brief
- * Parses the values for a parameter that takes a constant number of values.
- * 
- * \param[in] nval   Number of values in \p values.
- * \param[in] values Pointer to the list of values.
- * \param     param  Parameter to parse.
- * \param     root   Selection element to which child expressions are added.
- * \returns   TRUE if the values were parsed successfully, FALSE otherwise.
- *
- * For integer ranges, the sequence of numbers from the first to second value
- * is stored, each as a separate value.
- */
-static gmx_bool
-parse_values_std(int nval, t_selexpr_value *values, gmx_ana_selparam_t *param,
-                 t_selelem *root)
-{
-    t_selexpr_value   *value;
-    t_selelem         *child;
-    int                i, j;
-    gmx_bool               bDynamic;
-
-    /* Handle atom-valued parameters */
-    if (param->flags & SPAR_ATOMVAL)
-    {
-        if (nval > 1)
-        {
-            _gmx_selparser_error("extra values for parameter '%s'", param->name);
-            return FALSE;
-        }
-        value = values;
-        if (value->bExpr)
-        {
-            child = add_child(root, param, value->u.expr);
-            value->u.expr = NULL;
-            if (!child)
-            {
-                return FALSE;
-            }
-            child->flags |= SEL_ALLOCVAL;
-            if (child->v.type != GROUP_VALUE && (child->flags & SEL_ATOMVAL))
-            {
-                /* Rest of the initialization is done during compilation in
-                 * init_method(). */
-                /* TODO: Positions are not correctly handled */
-                param->val.nr = -1;
-                if (param->nvalptr)
-                {
-                    *param->nvalptr = -1;
-                }
-                return TRUE;
-            }
-            param->flags  &= ~SPAR_ATOMVAL;
-            param->val.nr  = 1;
-            if (param->nvalptr)
-            {
-                *param->nvalptr = 1;
-            }
-            param->nvalptr = NULL;
-            if (param->val.type == INT_VALUE || param->val.type == REAL_VALUE
-                || param->val.type == STR_VALUE)
-            {
-                _gmx_selvalue_reserve(&param->val, 1);
-            }
-            return set_expr_value_store(child, param, 0);
-        }
-        /* If we reach here, proceed with normal parameter handling */
-        param->val.nr = 1;
-        if (param->val.type == INT_VALUE || param->val.type == REAL_VALUE
-            || param->val.type == STR_VALUE)
-        {
-            _gmx_selvalue_reserve(&param->val, 1);
-        }
-        param->flags &= ~SPAR_ATOMVAL;
-        param->flags &= ~SPAR_DYNAMIC;
-    }
-
-    value = values;
-    i = 0;
-    bDynamic = FALSE;
-    while (value && i < param->val.nr)
-    {
-        if (value->type != param->val.type)
-        {
-            _gmx_selparser_error("incorrect value for parameter '%s' skipped", param->name);
-            value = value->next;
-            continue;
-        }
-        if (value->bExpr)
-        {
-            child = add_child(root, param, value->u.expr);
-            /* Clear the expression from the value once it is stored */
-            value->u.expr = NULL;
-            /* Check that the expression is valid */
-            if (!child)
-            {
-                return FALSE;
-            }
-            if (!set_expr_value_store(child, param, i))
-            {
-                return FALSE;
-            }
-            if (child->flags & SEL_DYNAMIC)
-            {
-                bDynamic = TRUE;
-            }
-        }
-        else
-        {
-            /* Value is not an expression */
-            switch (value->type)
-            {
-                case INT_VALUE:
-                    if (value->u.i.i1 <= value->u.i.i2)
-                    {
-                        for (j = value->u.i.i1; j <= value->u.i.i2 && i < param->val.nr; ++j)
-                        {
-                            param->val.u.i[i++] = j;
-                        }
-                        if (j != value->u.i.i2 + 1)
-                        {
-                            _gmx_selparser_error("extra values for parameter '%s' skipped", param->name);
-                        }
-                    }
-                    else
-                    {
-                        for (j = value->u.i.i1; j >= value->u.i.i2 && i < param->val.nr; --j)
-                        {
-                            param->val.u.i[i++] = j;
-                        }
-                        if (j != value->u.i.i2 - 1)
-                        {
-                            _gmx_selparser_error("extra values for parameter '%s' skipped", param->name);
-                        }
-                    }
-                    --i;
-                    break;
-                case REAL_VALUE:
-                    if (value->u.r.r1 != value->u.r.r2)
-                    {
-                        _gmx_selparser_error("real ranges not supported for parameter '%s'", param->name);
-                        return FALSE;
-                    }
-                    param->val.u.r[i] = value->u.r.r1;
-                    break;
-                case STR_VALUE:
-                    param->val.u.s[i] = strdup(value->u.s);
-                    break;
-                case POS_VALUE:
-                    gmx_ana_pos_init_const(&param->val.u.p[i], value->u.x);
-                    break;
-                case NO_VALUE:
-                case GROUP_VALUE:
-                    gmx_bug("internal error");
-                    return FALSE;
-            }
-        }
-        ++i;
-        value = value->next;
-    }
-    if (value)
-    {
-        _gmx_selparser_error("extra values for parameter '%s'", param->name);
-        return FALSE;
-    }
-    if (i < param->val.nr)
-    {
-        _gmx_selparser_error("not enough values for parameter '%s'", param->name);
-        return FALSE;
-    }
-    if (!bDynamic)
-    {
-        param->flags &= ~SPAR_DYNAMIC;
-    }
-    if (param->nvalptr)
-    {
-        *param->nvalptr = param->val.nr;
-    }
-    param->nvalptr = NULL;
-
-    return TRUE;
-}
-
-/*! \brief
- * Parses the values for a gmx_boolean parameter.
- *
- * \param[in] name   Name by which the parameter was given.
- * \param[in] nval   Number of values in \p values.
- * \param[in] values Pointer to the list of values.
- * \param     param  Parameter to parse.
- * \returns   TRUE if the values were parsed successfully, FALSE otherwise.
- */
-static gmx_bool
-parse_values_gmx_bool(const char *name, int nval, t_selexpr_value *values, gmx_ana_selparam_t *param)
-{
-    gmx_bool bSetNo;
-    int  len;
-
-    if (param->val.type != NO_VALUE)
-    {
-        gmx_bug("internal error");
-        return FALSE;
-    }
-    if (nval > 1 || (values && values->type != INT_VALUE))
-    {
-        _gmx_selparser_error("gmx_boolean parameter '%s' takes only a yes/no/on/off/0/1 value", param->name);
-        return FALSE;
-    }
-
-    bSetNo = FALSE;
-    /* Check if the parameter name is given with a 'no' prefix */
-    len = strlen(name);
-    if (len > 2 && name[0] == 'n' && name[1] == 'o'
-        && strncmp(name+2, param->name, len-2) == 0)
-    {
-        bSetNo = TRUE;
-    }
-    if (bSetNo && nval > 0)
-    {
-        _gmx_selparser_error("gmx_boolean parameter 'no%s' should not have a value", param->name);
-        return FALSE;
-    }
-    if (values && values->u.i.i1 == 0)
-    {
-        bSetNo = TRUE;
-    }
-
-    *param->val.u.b = bSetNo ? FALSE : TRUE;
-    return TRUE;
-}
-
-/*! \brief
- * Parses the values for an enumeration parameter.
- *
- * \param[in] nval   Number of values in \p values.
- * \param[in] values Pointer to the list of values.
- * \param     param  Parameter to parse.
- * \returns   TRUE if the values were parsed successfully, FALSE otherwise.
- */
-static gmx_bool
-parse_values_enum(int nval, t_selexpr_value *values, gmx_ana_selparam_t *param)
-{
-    int  i, len, match;
-
-    if (nval != 1)
-    {
-        _gmx_selparser_error("a single value is required for parameter '%s'", param->name);
-        return FALSE;
-    }
-    if (values->type != STR_VALUE || param->val.type != STR_VALUE)
-    {
-        gmx_bug("internal error");
-        return FALSE;
-    }
-    if (values->bExpr)
-    {
-        _gmx_selparser_error("expression value for enumerated parameter '%s' not supported", param->name);
-        return FALSE;
-    }
-
-    len = strlen(values->u.s);
-    i = 1;
-    match = 0;
-    while (param->val.u.s[i] != NULL)
-    {
-        if (strncmp(values->u.s, param->val.u.s[i], len) == 0)
-        {
-            /* Check if there is a duplicate match */
-            if (match > 0)
-            {
-                _gmx_selparser_error("ambiguous value for parameter '%s'", param->name);
-                return FALSE;
-            }
-            match = i;
-        }
-        ++i;
-    }
-    if (match == 0)
-    {
-        _gmx_selparser_error("invalid value for parameter '%s'", param->name);
-        return FALSE;
-    }
-    param->val.u.s[0] = param->val.u.s[match];
-    return TRUE;
-}
-
-/*! \brief
- * Replaces constant expressions with their values.
- *
- * \param[in,out] values First element in the value list to process.
- */
-static void
-convert_const_values(t_selexpr_value *values)
-{
-    t_selexpr_value *val;
-
-    val = values;
-    while (val)
-    {
-        if (val->bExpr && val->u.expr->v.type != GROUP_VALUE &&
-            val->u.expr->type == SEL_CONST)
-        {
-            t_selelem *expr = val->u.expr;
-            val->bExpr = FALSE;
-            switch (expr->v.type)
-            {
-                case INT_VALUE:
-                    val->u.i.i1 = val->u.i.i2 = expr->v.u.i[0];
-                    break;
-                case REAL_VALUE:
-                    val->u.r.r1 = val->u.r.r2 = expr->v.u.r[0];
-                    break;
-                case STR_VALUE:
-                    val->u.s = expr->v.u.s[0];
-                    break;
-                case POS_VALUE:
-                    copy_rvec(expr->v.u.p->x[0], val->u.x);
-                    break;
-                default:
-                    gmx_bug("internal error");
-                    break;
-            }
-            _gmx_selelem_free(expr);
-        }
-        val = val->next;
-    }
-}
-
-/*!
- * \param     pparams List of parameters from the selection parser.
- * \param[in] nparam  Number of parameters in \p params.
- * \param     params  Array of parameters to parse.
- * \param     root    Selection element to which child expressions are added.
- * \param[in] scanner Scanner data structure.
- * \returns   TRUE if the parameters were parsed successfully, FALSE otherwise.
- *
- * Initializes the \p params array based on the parameters in \p pparams.
- * See the documentation of \c gmx_ana_selparam_t for different options
- * available for parsing.
- *
- * The list \p pparams and any associated values are freed after the parameters
- * have been processed, no matter is there was an error or not.
- */
-gmx_bool
-_gmx_sel_parse_params(t_selexpr_param *pparams, int nparam, gmx_ana_selparam_t *params,
-                      t_selelem *root, void *scanner)
-{
-    t_selexpr_param    *pparam;
-    gmx_ana_selparam_t *oparam;
-    gmx_bool                bOk, rc;
-    int                 i;
-
-    /* Check that the value pointers of SPAR_VARNUM parameters are NULL and
-     * that they are not NULL for other parameters */
-    bOk = TRUE;
-    for (i = 0; i < nparam; ++i)
-    {
-        if (params[i].val.type != POS_VALUE && (params[i].flags & (SPAR_VARNUM | SPAR_ATOMVAL)))
-        {
-            if (params[i].val.u.ptr != NULL)
-            {
-                _gmx_selparser_error("warning: value pointer of parameter '%s' is not NULL\n"
-                                     "         although it should be for SPAR_VARNUM and SPAR_ATOMVAL parameters\n",
-                                     params[i].name);
-            }
-            if ((params[i].flags & SPAR_VARNUM)
-                && (params[i].flags & SPAR_DYNAMIC) && !params[i].nvalptr)
-            {
-                _gmx_selparser_error("error: nvalptr of parameter '%s' is NULL\n"
-                                     "       but both SPAR_VARNUM and SPAR_DYNAMIC are specified\n",
-                                     params[i].name);
-                bOk = FALSE;
-            }
-        }
-        else
-        {
-            if (params[i].val.u.ptr == NULL)
-            {
-                _gmx_selparser_error("error: value pointer of parameter '%s' is NULL\n",
-                                     params[i].name);
-                bOk = FALSE;
-            }
-        }
-    }
-    if (!bOk)
-    {
-        _gmx_selexpr_free_params(pparams);
-        return FALSE;
-    }
-    /* Parse the parameters */
-    pparam = pparams;
-    i      = 0;
-    while (pparam)
-    {
-        /* Find the parameter and make some checks */
-        if (pparam->name != NULL)
-        {
-            i = -1;
-            oparam = gmx_ana_selparam_find(pparam->name, nparam, params);
-        }
-        else if (i >= 0)
-        {
-            oparam = &params[i];
-            if (oparam->name != NULL)
-            {
-                oparam = NULL;
-                _gmx_selparser_error("too many NULL parameters provided");
-                bOk = FALSE;
-                goto next_param;
-            }
-            ++i;
-        }
-        else
-        {
-            _gmx_selparser_error("all NULL parameters should appear in the beginning of the list");
-            bOk = FALSE;
-            pparam = pparam->next;
-            continue;
-        }
-        if (!oparam)
-        {
-            _gmx_selparser_error("unknown parameter '%s' skipped", pparam->name);
-            bOk = FALSE;
-            goto next_param;
-        }
-        if (oparam->flags & SPAR_SET)
-        {
-            _gmx_selparser_error("parameter '%s' set multiple times, extra values skipped", pparam->name);
-            bOk = FALSE;
-            goto next_param;
-        }
-        oparam->flags |= SPAR_SET;
-        /* Process the values for the parameter */
-        convert_const_values(pparam->value);
-        if (convert_values(pparam->value, oparam->val.type, scanner) != 0)
-        {
-            _gmx_selparser_error("invalid value for parameter '%s'", pparam->name);
-            bOk = FALSE;
-            goto next_param;
-        }
-        if (oparam->val.type == NO_VALUE)
-        {
-            rc = parse_values_gmx_bool(pparam->name, pparam->nval, pparam->value, oparam);
-        }
-        else if (oparam->flags & SPAR_RANGES)
-        {
-            rc = parse_values_range(pparam->nval, pparam->value, oparam);
-        }
-        else if (oparam->flags & SPAR_VARNUM)
-        {
-            if (pparam->nval == 1 && pparam->value->bExpr)
-            {
-                rc = parse_values_varnum_expr(pparam->nval, pparam->value, oparam, root);
-            }
-            else
-            {
-                rc = parse_values_varnum(pparam->nval, pparam->value, oparam, root);
-            }
-        }
-        else if (oparam->flags & SPAR_ENUMVAL)
-        {
-            rc = parse_values_enum(pparam->nval, pparam->value, oparam);
-        }
-        else
-        {
-            rc = parse_values_std(pparam->nval, pparam->value, oparam, root);
-        }
-        if (!rc)
-        {
-            bOk = FALSE;
-        }
-        /* Advance to the next parameter */
-next_param:
-        pparam = pparam->next;
-    }
-    /* Check that all required parameters are present */
-    for (i = 0; i < nparam; ++i)
-    {
-        if (!(params[i].flags & SPAR_OPTIONAL) && !(params[i].flags & SPAR_SET))
-        {
-            _gmx_selparser_error("required parameter '%s' not specified", params[i].name);
-            bOk = FALSE;
-        }
-    }
-    
-    _gmx_selexpr_free_params(pparams);
-    return bOk;
-}
diff --git a/src/gmxlib/selection/parser.c b/src/gmxlib/selection/parser.c
deleted file mode 100644 (file)
index 3e57a98..0000000
+++ /dev/null
@@ -1,2580 +0,0 @@
-/* A Bison parser, made by GNU Bison 2.3.  */
-
-/* Skeleton implementation for Bison's Yacc-like parsers in C
-
-   Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
-   Free Software Foundation, Inc.
-
-   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, or (at your option)
-   any later version.
-
-   This program 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 General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301, USA.  */
-
-/* As a special exception, you may create a larger work that contains
-   part or all of the Bison parser skeleton and distribute that work
-   under terms of your choice, so long as that work isn't itself a
-   parser generator using the skeleton or a modified version thereof
-   as a parser skeleton.  Alternatively, if you modify or redistribute
-   the parser skeleton itself, you may (at your option) remove this
-   special exception, which will cause the skeleton and the resulting
-   Bison output files to be licensed under the GNU General Public
-   License without this special exception.
-
-   This special exception was added by the Free Software Foundation in
-   version 2.2 of Bison.  */
-
-/* C LALR(1) parser skeleton written by Richard Stallman, by
-   simplifying the original so-called "semantic" parser.  */
-
-/* All symbols defined below should begin with yy or YY, to avoid
-   infringing on user name space.  This should be done even for local
-   variables, as they might otherwise be expanded by user macros.
-   There are some unavoidable exceptions within include files to
-   define necessary library symbols; they are noted "INFRINGES ON
-   USER NAME SPACE" below.  */
-
-/* Identify Bison output.  */
-#define YYBISON 1
-
-/* Bison version.  */
-#define YYBISON_VERSION "2.3"
-
-/* Skeleton name.  */
-#define YYSKELETON_NAME "yacc.c"
-
-/* Pure parsers.  */
-#define YYPURE 1
-
-/* Using locations.  */
-#define YYLSP_NEEDED 0
-
-/* Substitute the variable and function names.  */
-#define yyparse _gmx_sel_yybparse
-#define yylex   _gmx_sel_yyblex
-#define yyerror _gmx_sel_yyberror
-#define yylval  _gmx_sel_yyblval
-#define yychar  _gmx_sel_yybchar
-#define yydebug _gmx_sel_yybdebug
-#define yynerrs _gmx_sel_yybnerrs
-
-
-/* Tokens.  */
-#ifndef YYTOKENTYPE
-# define YYTOKENTYPE
-   /* Put the tokens into the symbol table, so that GDB and other debuggers
-      know about them.  */
-   enum yytokentype {
-     INVALID = 258,
-     HELP = 259,
-     HELP_TOPIC = 260,
-     TOK_INT = 261,
-     TOK_REAL = 262,
-     STR = 263,
-     IDENTIFIER = 264,
-     CMD_SEP = 265,
-     GROUP = 266,
-     TO = 267,
-     VARIABLE_NUMERIC = 268,
-     VARIABLE_GROUP = 269,
-     VARIABLE_POS = 270,
-     KEYWORD_NUMERIC = 271,
-     KEYWORD_STR = 272,
-     KEYWORD_POS = 273,
-     KEYWORD_GROUP = 274,
-     METHOD_NUMERIC = 275,
-     METHOD_GROUP = 276,
-     METHOD_POS = 277,
-     MODIFIER = 278,
-     EMPTY_POSMOD = 279,
-     PARAM = 280,
-     END_OF_METHOD = 281,
-     OF = 282,
-     CMP_OP = 283,
-     PARAM_REDUCT = 284,
-     XOR = 285,
-     OR = 286,
-     AND = 287,
-     NOT = 288,
-     UNARY_NEG = 289,
-     NUM_REDUCT = 290
-   };
-#endif
-/* Tokens.  */
-#define INVALID 258
-#define HELP 259
-#define HELP_TOPIC 260
-#define TOK_INT 261
-#define TOK_REAL 262
-#define STR 263
-#define IDENTIFIER 264
-#define CMD_SEP 265
-#define GROUP 266
-#define TO 267
-#define VARIABLE_NUMERIC 268
-#define VARIABLE_GROUP 269
-#define VARIABLE_POS 270
-#define KEYWORD_NUMERIC 271
-#define KEYWORD_STR 272
-#define KEYWORD_POS 273
-#define KEYWORD_GROUP 274
-#define METHOD_NUMERIC 275
-#define METHOD_GROUP 276
-#define METHOD_POS 277
-#define MODIFIER 278
-#define EMPTY_POSMOD 279
-#define PARAM 280
-#define END_OF_METHOD 281
-#define OF 282
-#define CMP_OP 283
-#define PARAM_REDUCT 284
-#define XOR 285
-#define OR 286
-#define AND 287
-#define NOT 288
-#define UNARY_NEG 289
-#define NUM_REDUCT 290
-
-
-
-
-/* Copy the first part of user declarations.  */
-#line 34 "parser.y"
-
-/*! \internal \file parser.c
- * \brief Generated (from parser.y by Bison) parser for the selection language.
- */
-/*! \internal \file parser.h
- * \brief Generated (from parser.y by Bison) parser include file.
- */
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-
-#include <string2.h>
-
-#include "parsetree.h"
-#include "selelem.h"
-
-#include "scanner.h"
-
-static t_selexpr_value *
-process_value_list(t_selexpr_value *values, int *nr);
-static t_selexpr_param *
-process_param_list(t_selexpr_param *params);
-
-static void
-yyerror(yyscan_t, char const *s);
-
-
-/* Enabling traces.  */
-#ifndef YYDEBUG
-# define YYDEBUG 1
-#endif
-
-/* Enabling verbose error messages.  */
-#ifdef YYERROR_VERBOSE
-# undef YYERROR_VERBOSE
-# define YYERROR_VERBOSE 1
-#else
-# define YYERROR_VERBOSE 0
-#endif
-
-/* Enabling the token table.  */
-#ifndef YYTOKEN_TABLE
-# define YYTOKEN_TABLE 0
-#endif
-
-#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
-typedef union YYSTYPE
-#line 62 "parser.y"
-{
-    int                         i;
-    real                        r;
-    char                       *str;
-    struct gmx_ana_selmethod_t *meth;
-
-    struct t_selelem           *sel;
-
-    struct t_selexpr_value     *val;
-    struct t_selexpr_param     *param;
-}
-/* Line 187 of yacc.c.  */
-#line 214 "parser.c"
-       YYSTYPE;
-# define yystype YYSTYPE /* obsolescent; will be withdrawn */
-# define YYSTYPE_IS_DECLARED 1
-# define YYSTYPE_IS_TRIVIAL 1
-#endif
-
-
-
-/* Copy the second part of user declarations.  */
-
-
-/* Line 216 of yacc.c.  */
-#line 227 "parser.c"
-
-#ifdef short
-# undef short
-#endif
-
-#ifdef YYTYPE_UINT8
-typedef YYTYPE_UINT8 yytype_uint8;
-#else
-typedef unsigned char yytype_uint8;
-#endif
-
-#ifdef YYTYPE_INT8
-typedef YYTYPE_INT8 yytype_int8;
-#elif (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-typedef signed char yytype_int8;
-#else
-typedef short int yytype_int8;
-#endif
-
-#ifdef YYTYPE_UINT16
-typedef YYTYPE_UINT16 yytype_uint16;
-#else
-typedef unsigned short int yytype_uint16;
-#endif
-
-#ifdef YYTYPE_INT16
-typedef YYTYPE_INT16 yytype_int16;
-#else
-typedef short int yytype_int16;
-#endif
-
-#ifndef YYSIZE_T
-# ifdef __SIZE_TYPE__
-#  define YYSIZE_T __SIZE_TYPE__
-# elif defined size_t
-#  define YYSIZE_T size_t
-# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-#  include <stddef.h> /* INFRINGES ON USER NAME SPACE */
-#  define YYSIZE_T size_t
-# else
-#  define YYSIZE_T unsigned int
-# endif
-#endif
-
-#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
-
-#ifndef YY_
-# if YYENABLE_NLS
-#  if ENABLE_NLS
-#   include <libintl.h> /* INFRINGES ON USER NAME SPACE */
-#   define YY_(msgid) dgettext ("bison-runtime", msgid)
-#  endif
-# endif
-# ifndef YY_
-#  define YY_(msgid) msgid
-# endif
-#endif
-
-/* Suppress unused-variable warnings by "using" E.  */
-#if ! defined lint || defined __GNUC__
-# define YYUSE(e) ((void) (e))
-#else
-# define YYUSE(e) /* empty */
-#endif
-
-/* Identity function, used to suppress warnings about constant conditions.  */
-#ifndef lint
-# define YYID(n) (n)
-#else
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-static int
-YYID (int i)
-#else
-static int
-YYID (i)
-    int i;
-#endif
-{
-  return i;
-}
-#endif
-
-#if ! defined yyoverflow || YYERROR_VERBOSE
-
-/* The parser invokes alloca or malloc; define the necessary symbols.  */
-
-# ifdef YYSTACK_USE_ALLOCA
-#  if YYSTACK_USE_ALLOCA
-#   ifdef __GNUC__
-#    define YYSTACK_ALLOC __builtin_alloca
-#   elif defined __BUILTIN_VA_ARG_INCR
-#    include <alloca.h> /* INFRINGES ON USER NAME SPACE */
-#   elif defined _AIX
-#    define YYSTACK_ALLOC __alloca
-#   elif defined _MSC_VER
-#    include <malloc.h> /* INFRINGES ON USER NAME SPACE */
-#    define alloca _alloca
-#   else
-#    define YYSTACK_ALLOC alloca
-#    if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-#     include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
-#     ifndef _STDLIB_H
-#      define _STDLIB_H 1
-#     endif
-#    endif
-#   endif
-#  endif
-# endif
-
-# ifdef YYSTACK_ALLOC
-   /* Pacify GCC's `empty if-body' warning.  */
-#  define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
-#  ifndef YYSTACK_ALLOC_MAXIMUM
-    /* The OS might guarantee only one guard page at the bottom of the stack,
-       and a page size can be as small as 4096 bytes.  So we cannot safely
-       invoke alloca (N) if N exceeds 4096.  Use a slightly smaller number
-       to allow for a few compiler-allocated temporary stack slots.  */
-#   define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
-#  endif
-# else
-#  define YYSTACK_ALLOC YYMALLOC
-#  define YYSTACK_FREE YYFREE
-#  ifndef YYSTACK_ALLOC_MAXIMUM
-#   define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
-#  endif
-#  if (defined __cplusplus && ! defined _STDLIB_H \
-       && ! ((defined YYMALLOC || defined malloc) \
-            && (defined YYFREE || defined free)))
-#   include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
-#   ifndef _STDLIB_H
-#    define _STDLIB_H 1
-#   endif
-#  endif
-#  ifndef YYMALLOC
-#   define YYMALLOC malloc
-#   if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
-#   endif
-#  endif
-#  ifndef YYFREE
-#   define YYFREE free
-#   if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-void free (void *); /* INFRINGES ON USER NAME SPACE */
-#   endif
-#  endif
-# endif
-#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
-
-
-#if (! defined yyoverflow \
-     && (! defined __cplusplus \
-        || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
-
-/* A type that is properly aligned for any stack member.  */
-union yyalloc
-{
-  yytype_int16 yyss;
-  YYSTYPE yyvs;
-  };
-
-/* The size of the maximum gap between one aligned stack and the next.  */
-# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
-
-/* The size of an array large to enough to hold all stacks, each with
-   N elements.  */
-# define YYSTACK_BYTES(N) \
-     ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
-      + YYSTACK_GAP_MAXIMUM)
-
-/* Copy COUNT objects from FROM to TO.  The source and destination do
-   not overlap.  */
-# ifndef YYCOPY
-#  if defined __GNUC__ && 1 < __GNUC__
-#   define YYCOPY(To, From, Count) \
-      __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
-#  else
-#   define YYCOPY(To, From, Count)             \
-      do                                       \
-       {                                       \
-         YYSIZE_T yyi;                         \
-         for (yyi = 0; yyi < (Count); yyi++)   \
-           (To)[yyi] = (From)[yyi];            \
-       }                                       \
-      while (YYID (0))
-#  endif
-# endif
-
-/* Relocate STACK from its old location to the new one.  The
-   local variables YYSIZE and YYSTACKSIZE give the old and new number of
-   elements in the stack, and YYPTR gives the new location of the
-   stack.  Advance YYPTR to a properly aligned location for the next
-   stack.  */
-# define YYSTACK_RELOCATE(Stack)                                       \
-    do                                                                 \
-      {                                                                        \
-       YYSIZE_T yynewbytes;                                            \
-       YYCOPY (&yyptr->Stack, Stack, yysize);                          \
-       Stack = &yyptr->Stack;                                          \
-       yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
-       yyptr += yynewbytes / sizeof (*yyptr);                          \
-      }                                                                        \
-    while (YYID (0))
-
-#endif
-
-/* YYFINAL -- State number of the termination state.  */
-#define YYFINAL  2
-/* YYLAST -- Last index in YYTABLE.  */
-#define YYLAST   417
-
-/* YYNTOKENS -- Number of terminals.  */
-#define YYNTOKENS  49
-/* YYNNTS -- Number of nonterminals.  */
-#define YYNNTS  26
-/* YYNRULES -- Number of rules.  */
-#define YYNRULES  91
-/* YYNRULES -- Number of states.  */
-#define YYNSTATES  150
-
-/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX.  */
-#define YYUNDEFTOK  2
-#define YYMAXUTOK   290
-
-#define YYTRANSLATE(YYX)                                               \
-  ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
-
-/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX.  */
-static const yytype_uint8 yytranslate[] =
-{
-       0,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-      42,    43,    36,    34,    45,    35,     2,    37,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,    41,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,    44,     2,    46,    39,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,    47,     2,    48,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     1,     2,     3,     4,
-       5,     6,     7,     8,     9,    10,    11,    12,    13,    14,
-      15,    16,    17,    18,    19,    20,    21,    22,    23,    24,
-      25,    26,    27,    28,    29,    30,    31,    32,    33,    38,
-      40
-};
-
-#if YYDEBUG
-/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
-   YYRHS.  */
-static const yytype_uint16 yyprhs[] =
-{
-       0,     0,     3,     4,     7,    10,    13,    14,    16,    18,
-      20,    22,    25,    29,    33,    37,    39,    41,    44,    47,
-      49,    51,    55,    59,    61,    64,    66,    69,    71,    73,
-      75,    77,    80,    84,    88,    92,    96,    99,   102,   104,
-     106,   109,   113,   117,   121,   123,   125,   128,   132,   136,
-     140,   144,   148,   151,   155,   159,   161,   164,   172,   176,
-     179,   183,   185,   187,   189,   191,   194,   195,   198,   201,
-     202,   204,   208,   210,   213,   217,   219,   223,   225,   228,
-     232,   234,   236,   238,   240,   242,   244,   246,   248,   250,
-     254,   258
-};
-
-/* YYRHS -- A `-1'-separated list of the rules' RHS.  */
-static const yytype_int8 yyrhs[] =
-{
-      50,     0,    -1,    -1,    50,    51,    -1,    52,    10,    -1,
-       1,    10,    -1,    -1,    53,    -1,     6,    -1,    59,    -1,
-      55,    -1,    59,    55,    -1,     9,    41,    60,    -1,     9,
-      41,    62,    -1,     9,    41,    64,    -1,     4,    -1,    54,
-      -1,     4,     5,    -1,    54,     5,    -1,    64,    -1,    60,
-      -1,    42,    55,    43,    -1,    55,    23,    65,    -1,     6,
-      -1,    35,     6,    -1,     7,    -1,    35,     7,    -1,    56,
-      -1,    57,    -1,     8,    -1,     9,    -1,    33,    60,    -1,
-      60,    32,    60,    -1,    60,    31,    60,    -1,    42,    60,
-      43,    -1,    62,    28,    62,    -1,    11,    59,    -1,    11,
-       6,    -1,    24,    -1,    18,    -1,    61,    19,    -1,    61,
-      17,    70,    -1,    61,    16,    70,    -1,    61,    21,    65,
-      -1,     6,    -1,     7,    -1,    61,    16,    -1,    61,    20,
-      65,    -1,    62,    34,    62,    -1,    62,    35,    62,    -1,
-      62,    36,    62,    -1,    62,    37,    62,    -1,    35,    62,
-      -1,    62,    39,    62,    -1,    42,    62,    43,    -1,    59,
-      -1,    61,    17,    -1,    44,    58,    45,    58,    45,    58,
-      46,    -1,    42,    64,    43,    -1,    22,    65,    -1,    18,
-      27,    60,    -1,    14,    -1,    13,    -1,    15,    -1,    66,
-      -1,    66,    26,    -1,    -1,    66,    67,    -1,    25,    68,
-      -1,    -1,    69,    -1,    47,    69,    48,    -1,    72,    -1,
-      69,    72,    -1,    69,    45,    72,    -1,    71,    -1,    47,
-      71,    48,    -1,    73,    -1,    71,    73,    -1,    71,    45,
-      73,    -1,    60,    -1,    64,    -1,    62,    -1,    63,    -1,
-      74,    -1,    56,    -1,    57,    -1,    59,    -1,    74,    -1,
-      56,    12,    56,    -1,    56,    12,    57,    -1,    57,    12,
-      58,    -1
-};
-
-/* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
-static const yytype_uint16 yyrline[] =
-{
-       0,   182,   182,   183,   192,   193,   213,   217,   218,   227,
-     237,   239,   241,   243,   245,   251,   252,   255,   256,   260,
-     261,   266,   267,   279,   280,   284,   285,   288,   289,   292,
-     293,   301,   307,   313,   325,   329,   337,   343,   351,   352,
-     356,   361,   366,   374,   386,   393,   403,   408,   416,   418,
-     420,   422,   424,   426,   428,   435,   442,   454,   459,   463,
-     471,   482,   486,   490,   499,   501,   506,   507,   512,   519,
-     520,   521,   525,   526,   528,   533,   534,   538,   539,   541,
-     545,   547,   549,   551,   553,   557,   562,   567,   572,   576,
-     581,   586
-};
-#endif
-
-#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
-/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
-   First, the terminals, then, starting at YYNTOKENS, nonterminals.  */
-static const char *const yytname[] =
-{
-  "$end", "error", "$undefined", "INVALID", "HELP", "HELP_TOPIC",
-  "TOK_INT", "TOK_REAL", "STR", "IDENTIFIER", "CMD_SEP", "GROUP", "TO",
-  "VARIABLE_NUMERIC", "VARIABLE_GROUP", "VARIABLE_POS", "KEYWORD_NUMERIC",
-  "KEYWORD_STR", "KEYWORD_POS", "KEYWORD_GROUP", "METHOD_NUMERIC",
-  "METHOD_GROUP", "METHOD_POS", "MODIFIER", "EMPTY_POSMOD", "PARAM",
-  "END_OF_METHOD", "OF", "CMP_OP", "PARAM_REDUCT", "XOR", "OR", "AND",
-  "NOT", "'+'", "'-'", "'*'", "'/'", "UNARY_NEG", "'^'", "NUM_REDUCT",
-  "'='", "'('", "')'", "'['", "','", "']'", "'{'", "'}'", "$accept",
-  "commands", "command", "cmd_plain", "help_request", "help_topic",
-  "selection", "integer_number", "real_number", "number", "string",
-  "sel_expr", "pos_mod", "num_expr", "str_expr", "pos_expr",
-  "method_params", "method_param_list", "method_param", "value_list",
-  "value_list_contents", "basic_value_list", "basic_value_list_contents",
-  "value_item", "basic_value_item", "value_item_range", 0
-};
-#endif
-
-# ifdef YYPRINT
-/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
-   token YYLEX-NUM.  */
-static const yytype_uint16 yytoknum[] =
-{
-       0,   256,   257,   258,   259,   260,   261,   262,   263,   264,
-     265,   266,   267,   268,   269,   270,   271,   272,   273,   274,
-     275,   276,   277,   278,   279,   280,   281,   282,   283,   284,
-     285,   286,   287,   288,    43,    45,    42,    47,   289,    94,
-     290,    61,    40,    41,    91,    44,    93,   123,   125
-};
-# endif
-
-/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
-static const yytype_uint8 yyr1[] =
-{
-       0,    49,    50,    50,    51,    51,    52,    52,    52,    52,
-      52,    52,    52,    52,    52,    53,    53,    54,    54,    55,
-      55,    55,    55,    56,    56,    57,    57,    58,    58,    59,
-      59,    60,    60,    60,    60,    60,    60,    60,    61,    61,
-      60,    60,    60,    60,    62,    62,    62,    62,    62,    62,
-      62,    62,    62,    62,    62,    63,    63,    64,    64,    64,
-      64,    60,    62,    64,    65,    65,    66,    66,    67,    68,
-      68,    68,    69,    69,    69,    70,    70,    71,    71,    71,
-      72,    72,    72,    72,    72,    73,    73,    73,    73,    74,
-      74,    74
-};
-
-/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN.  */
-static const yytype_uint8 yyr2[] =
-{
-       0,     2,     0,     2,     2,     2,     0,     1,     1,     1,
-       1,     2,     3,     3,     3,     1,     1,     2,     2,     1,
-       1,     3,     3,     1,     2,     1,     2,     1,     1,     1,
-       1,     2,     3,     3,     3,     3,     2,     2,     1,     1,
-       2,     3,     3,     3,     1,     1,     2,     3,     3,     3,
-       3,     3,     2,     3,     3,     1,     2,     7,     3,     2,
-       3,     1,     1,     1,     1,     2,     0,     2,     2,     0,
-       1,     3,     1,     2,     3,     1,     3,     1,     2,     3,
-       1,     1,     1,     1,     1,     1,     1,     1,     1,     3,
-       3,     3
-};
-
-/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
-   STATE-NUM when YYTABLE doesn't specify something else to do.  Zero
-   means the default is an error.  */
-static const yytype_uint8 yydefact[] =
-{
-       2,     0,     1,     0,    15,    44,    45,    29,    30,     0,
-      62,    61,    63,    39,    66,    38,     0,     0,     0,     0,
-       3,     0,     7,    16,    10,     9,    20,     0,     0,    19,
-       5,    17,     0,    37,    30,    36,     0,    59,    64,    44,
-      39,     0,    31,     0,     0,    52,     0,    20,     0,    19,
-      23,    25,     0,    27,    28,     0,     4,    18,    66,    11,
-       0,     0,    46,     0,    40,    66,    66,     0,     0,     0,
-       0,     0,     0,     0,    12,    13,    14,    60,    69,    65,
-      67,     0,     0,    46,    21,    34,    54,    58,    24,    26,
-       0,    22,    33,    32,     0,    85,    86,    87,    42,    75,
-      77,    88,    41,    47,    43,    35,    48,    49,    50,    51,
-      53,     0,    44,    45,     0,     0,     0,     0,    55,    80,
-       0,    82,    83,    81,    68,    70,    72,    84,     0,     0,
-       0,     0,     0,    78,    44,    45,     0,    56,     0,    73,
-       0,    76,    89,    90,    91,    79,    71,    74,     0,    57
-};
-
-/* YYDEFGOTO[NTERM-NUM].  */
-static const yytype_int8 yydefgoto[] =
-{
-      -1,     1,    20,    21,    22,    23,    24,    95,    96,    55,
-      97,   119,    27,    28,   122,   123,    37,    38,    80,   124,
-     125,   102,    99,   126,   100,   101
-};
-
-/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
-   STATE-NUM.  */
-#define YYPACT_NINF -93
-static const yytype_int16 yypact[] =
-{
-     -93,   155,   -93,    10,    19,    26,   -93,   -93,    -3,    73,
-     -93,   -93,   -93,    22,   -93,   -93,   356,   372,   317,    11,
-     -93,    79,   -93,    86,    70,   317,    29,   384,   180,   -93,
-     -93,   -93,   342,   -93,   -93,   -93,   356,   -93,     6,   -93,
-     -93,   356,   -93,   372,   -10,    57,   -20,   -17,   256,    54,
-     -93,   -93,    88,   -93,   -93,    55,   -93,   -93,   -93,    70,
-     356,   356,   197,   174,   -93,   -93,   -93,   372,   372,   372,
-     372,   372,   372,   342,    29,   180,   -93,    29,   221,   -93,
-     -93,   -17,   223,   -93,   -93,   -93,   -93,   -93,   -93,   -93,
-      11,   -93,    69,   -93,    78,    90,    94,   -93,   -93,   244,
-     -93,   -93,   -93,   -93,   -93,   267,    36,    36,    57,    57,
-      57,    54,    95,    96,   375,   303,    90,    94,   -93,    29,
-     392,   267,   -93,   -93,   -93,   263,   -93,   -93,    71,    35,
-      11,    11,    78,   -93,   105,   106,   178,   174,   303,   -93,
-      11,   -93,   -93,   -93,   -93,   -93,   -93,   -93,    80,   -93
-};
-
-/* YYPGOTO[NTERM-NUM].  */
-static const yytype_int8 yypgoto[] =
-{
-     -93,   -93,   -93,   -93,   -93,   -93,   -13,     0,    14,   -81,
-      -1,    87,    -4,   -16,   -93,     3,   -36,   -93,   -93,   -93,
-      12,    81,    39,   -91,   -92,   -67
-};
-
-/* YYTABLE[YYPACT[STATE-NUM]].  What to do in state STATE-NUM.  If
-   positive, shift that token.  If negative, reduce the rule which
-   number is the opposite.  If zero, do what YYDEFACT says.
-   If YYTABLE_NINF, syntax error.  */
-#define YYTABLE_NINF -27
-static const yytype_int16 yytable[] =
-{
-      25,    45,    48,    58,    29,    46,    83,   133,    35,   128,
-      65,   127,    59,    44,    60,    61,    75,    50,    51,    53,
-      30,    49,    91,    84,    31,    48,    85,    82,    29,   103,
-     104,    78,    79,    54,   139,    76,    -8,   133,    32,    44,
-     145,    50,    51,     7,    34,   139,    52,   147,   127,    36,
-     144,   105,   106,   107,   108,   109,   110,    48,   127,   148,
-      60,    61,   121,    44,    44,    44,    44,    44,    44,   127,
-      52,   127,    70,    71,   120,    72,   111,   118,   116,    33,
-     132,     7,    34,   141,    50,    51,     7,    34,    26,    56,
-      53,    57,   117,    58,    88,    89,    72,    87,    45,   121,
-      90,    61,   130,    42,    54,    47,   131,   -23,   -25,   121,
-      44,   120,    26,    52,   118,   116,   140,   -24,   -26,    74,
-     121,   120,   121,    77,   118,   116,   149,   136,    81,   117,
-     142,    53,   120,   129,   120,   118,   116,   118,   116,   117,
-      53,     0,     0,    98,   143,    54,     0,    92,    93,     0,
-     117,     0,   117,     0,    54,     2,     3,     0,     0,     4,
-      81,     5,     6,     7,     8,    -6,     9,     0,    10,    11,
-      12,     0,     0,    13,     0,     0,     0,    14,     0,    15,
-      50,    51,     7,    34,   112,   113,     7,    34,    16,     9,
-      17,    10,    11,    12,     0,     0,    13,    18,     0,    19,
-      14,     0,    15,    50,    51,     7,    34,     0,    67,    52,
-       0,    16,     0,   114,    68,    69,    70,    71,     0,    72,
-      73,    94,    19,   138,     0,     0,   146,   112,   113,     7,
-      34,     0,     9,     0,    10,    11,    12,     0,     0,    13,
-       0,     0,     0,    14,    94,    15,     0,     0,     0,     0,
-      50,    51,     7,    34,    16,     0,   114,    68,    69,    70,
-      71,     0,    72,    73,     0,    19,    86,     0,   115,   112,
-     113,     7,    34,     0,     9,     0,    10,    11,    12,    52,
-       0,    13,     0,     0,    67,    14,     0,    15,     0,   132,
-      68,    69,    70,    71,     0,    72,    16,     0,   114,    86,
-       0,    68,    69,    70,    71,    73,    72,    19,   138,   112,
-     113,     7,    34,     0,     9,     0,    10,    11,    12,     0,
-       0,    13,     0,    39,     6,    14,     0,    15,     9,     0,
-      10,    11,    12,     0,     0,    13,    16,     0,   114,    14,
-       0,    15,     0,     0,     0,    73,     0,    19,    39,     6,
-      16,     0,    17,     9,     0,    10,    11,    12,     0,    18,
-      13,    19,    39,     6,    14,     0,    15,     9,     0,    10,
-      11,     0,     0,     0,    40,    16,     0,    17,    39,     6,
-      15,   134,   135,     0,    73,    10,    19,     0,    10,    16,
-      40,    17,     0,    40,     0,     0,    15,     0,    41,    15,
-      62,    63,     0,    64,    65,    66,     0,    17,    62,   137,
-      17,    64,    65,    66,    43,     0,     0,    43
-};
-
-static const yytype_int16 yycheck[] =
-{
-       1,    17,    18,    23,     1,    18,    16,    99,     9,    90,
-      20,    78,    25,    17,    31,    32,    32,     6,     7,    19,
-      10,    18,    58,    43,     5,    41,    43,    43,    25,    65,
-      66,    25,    26,    19,   125,    32,    10,   129,    41,    43,
-     132,     6,     7,     8,     9,   136,    35,   138,   115,    27,
-     131,    67,    68,    69,    70,    71,    72,    73,   125,   140,
-      31,    32,    78,    67,    68,    69,    70,    71,    72,   136,
-      35,   138,    36,    37,    78,    39,    73,    78,    78,     6,
-      45,     8,     9,    48,     6,     7,     8,     9,     1,    10,
-      90,     5,    78,    23,     6,     7,    39,    43,   114,   115,
-      45,    32,    12,    16,    90,    18,    12,    12,    12,   125,
-     114,   115,    25,    35,   115,   115,    45,    12,    12,    32,
-     136,   125,   138,    36,   125,   125,    46,   115,    41,   115,
-     130,   131,   136,    94,   138,   136,   136,   138,   138,   125,
-     140,    -1,    -1,    62,   130,   131,    -1,    60,    61,    -1,
-     136,    -1,   138,    -1,   140,     0,     1,    -1,    -1,     4,
-      73,     6,     7,     8,     9,    10,    11,    -1,    13,    14,
-      15,    -1,    -1,    18,    -1,    -1,    -1,    22,    -1,    24,
-       6,     7,     8,     9,     6,     7,     8,     9,    33,    11,
-      35,    13,    14,    15,    -1,    -1,    18,    42,    -1,    44,
-      22,    -1,    24,     6,     7,     8,     9,    -1,    28,    35,
-      -1,    33,    -1,    35,    34,    35,    36,    37,    -1,    39,
-      42,    47,    44,    45,    -1,    -1,    48,     6,     7,     8,
-       9,    -1,    11,    -1,    13,    14,    15,    -1,    -1,    18,
-      -1,    -1,    -1,    22,    47,    24,    -1,    -1,    -1,    -1,
-       6,     7,     8,     9,    33,    -1,    35,    34,    35,    36,
-      37,    -1,    39,    42,    -1,    44,    43,    -1,    47,     6,
-       7,     8,     9,    -1,    11,    -1,    13,    14,    15,    35,
-      -1,    18,    -1,    -1,    28,    22,    -1,    24,    -1,    45,
-      34,    35,    36,    37,    -1,    39,    33,    -1,    35,    43,
-      -1,    34,    35,    36,    37,    42,    39,    44,    45,     6,
-       7,     8,     9,    -1,    11,    -1,    13,    14,    15,    -1,
-      -1,    18,    -1,     6,     7,    22,    -1,    24,    11,    -1,
-      13,    14,    15,    -1,    -1,    18,    33,    -1,    35,    22,
-      -1,    24,    -1,    -1,    -1,    42,    -1,    44,     6,     7,
-      33,    -1,    35,    11,    -1,    13,    14,    15,    -1,    42,
-      18,    44,     6,     7,    22,    -1,    24,    11,    -1,    13,
-      14,    -1,    -1,    -1,    18,    33,    -1,    35,     6,     7,
-      24,     6,     7,    -1,    42,    13,    44,    -1,    13,    33,
-      18,    35,    -1,    18,    -1,    -1,    24,    -1,    42,    24,
-      16,    17,    -1,    19,    20,    21,    -1,    35,    16,    17,
-      35,    19,    20,    21,    42,    -1,    -1,    42
-};
-
-/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
-   symbol of state STATE-NUM.  */
-static const yytype_uint8 yystos[] =
-{
-       0,    50,     0,     1,     4,     6,     7,     8,     9,    11,
-      13,    14,    15,    18,    22,    24,    33,    35,    42,    44,
-      51,    52,    53,    54,    55,    59,    60,    61,    62,    64,
-      10,     5,    41,     6,     9,    59,    27,    65,    66,     6,
-      18,    42,    60,    42,    61,    62,    55,    60,    62,    64,
-       6,     7,    35,    56,    57,    58,    10,     5,    23,    55,
-      31,    32,    16,    17,    19,    20,    21,    28,    34,    35,
-      36,    37,    39,    42,    60,    62,    64,    60,    25,    26,
-      67,    60,    62,    16,    43,    43,    43,    43,     6,     7,
-      45,    65,    60,    60,    47,    56,    57,    59,    70,    71,
-      73,    74,    70,    65,    65,    62,    62,    62,    62,    62,
-      62,    64,     6,     7,    35,    47,    56,    57,    59,    60,
-      61,    62,    63,    64,    68,    69,    72,    74,    58,    71,
-      12,    12,    45,    73,     6,     7,    69,    17,    45,    72,
-      45,    48,    56,    57,    58,    73,    48,    72,    58,    46
-};
-
-#define yyerrok                (yyerrstatus = 0)
-#define yyclearin      (yychar = YYEMPTY)
-#define YYEMPTY                (-2)
-#define YYEOF          0
-
-#define YYACCEPT       goto yyacceptlab
-#define YYABORT                goto yyabortlab
-#define YYERROR                goto yyerrorlab
-
-
-/* Like YYERROR except do call yyerror.  This remains here temporarily
-   to ease the transition to the new meaning of YYERROR, for GCC.
-   Once GCC version 2 has supplanted version 1, this can go.  */
-
-#define YYFAIL         goto yyerrlab
-
-#define YYRECOVERING()  (!!yyerrstatus)
-
-#define YYBACKUP(Token, Value)                                 \
-do                                                             \
-  if (yychar == YYEMPTY && yylen == 1)                         \
-    {                                                          \
-      yychar = (Token);                                                \
-      yylval = (Value);                                                \
-      yytoken = YYTRANSLATE (yychar);                          \
-      YYPOPSTACK (1);                                          \
-      goto yybackup;                                           \
-    }                                                          \
-  else                                                         \
-    {                                                          \
-      yyerror (scanner, YY_("syntax error: cannot back up")); \
-      YYERROR;                                                 \
-    }                                                          \
-while (YYID (0))
-
-
-#define YYTERROR       1
-#define YYERRCODE      256
-
-
-/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
-   If N is 0, then set CURRENT to the empty location which ends
-   the previous symbol: RHS[0] (always defined).  */
-
-#define YYRHSLOC(Rhs, K) ((Rhs)[K])
-#ifndef YYLLOC_DEFAULT
-# define YYLLOC_DEFAULT(Current, Rhs, N)                               \
-    do                                                                 \
-      if (YYID (N))                                                    \
-       {                                                               \
-         (Current).first_line   = YYRHSLOC (Rhs, 1).first_line;        \
-         (Current).first_column = YYRHSLOC (Rhs, 1).first_column;      \
-         (Current).last_line    = YYRHSLOC (Rhs, N).last_line;         \
-         (Current).last_column  = YYRHSLOC (Rhs, N).last_column;       \
-       }                                                               \
-      else                                                             \
-       {                                                               \
-         (Current).first_line   = (Current).last_line   =              \
-           YYRHSLOC (Rhs, 0).last_line;                                \
-         (Current).first_column = (Current).last_column =              \
-           YYRHSLOC (Rhs, 0).last_column;                              \
-       }                                                               \
-    while (YYID (0))
-#endif
-
-
-/* YY_LOCATION_PRINT -- Print the location on the stream.
-   This macro was not mandated originally: define only if we know
-   we won't break user code: when these are the locations we know.  */
-
-#ifndef YY_LOCATION_PRINT
-# if YYLTYPE_IS_TRIVIAL
-#  define YY_LOCATION_PRINT(File, Loc)                 \
-     fprintf (File, "%d.%d-%d.%d",                     \
-             (Loc).first_line, (Loc).first_column,     \
-             (Loc).last_line,  (Loc).last_column)
-# else
-#  define YY_LOCATION_PRINT(File, Loc) ((void) 0)
-# endif
-#endif
-
-
-/* YYLEX -- calling `yylex' with the right arguments.  */
-
-#ifdef YYLEX_PARAM
-# define YYLEX yylex (&yylval, YYLEX_PARAM)
-#else
-# define YYLEX yylex (&yylval, scanner)
-#endif
-
-/* Enable debugging if requested.  */
-#if YYDEBUG
-
-# ifndef YYFPRINTF
-#  include <stdio.h> /* INFRINGES ON USER NAME SPACE */
-#  define YYFPRINTF fprintf
-# endif
-
-# define YYDPRINTF(Args)                       \
-do {                                           \
-  if (yydebug)                                 \
-    YYFPRINTF Args;                            \
-} while (YYID (0))
-
-# define YY_SYMBOL_PRINT(Title, Type, Value, Location)                   \
-do {                                                                     \
-  if (yydebug)                                                           \
-    {                                                                    \
-      YYFPRINTF (stderr, "%s ", Title);                                          \
-      yy_symbol_print (stderr,                                           \
-                 Type, Value, scanner); \
-      YYFPRINTF (stderr, "\n");                                                  \
-    }                                                                    \
-} while (YYID (0))
-
-
-/*--------------------------------.
-| Print this symbol on YYOUTPUT.  |
-`--------------------------------*/
-
-/*ARGSUSED*/
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-static void
-yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, yyscan_t                 scanner)
-#else
-static void
-yy_symbol_value_print (yyoutput, yytype, yyvaluep, scanner)
-    FILE *yyoutput;
-    int yytype;
-    YYSTYPE const * const yyvaluep;
-    yyscan_t                 scanner;
-#endif
-{
-  if (!yyvaluep)
-    return;
-  YYUSE (scanner);
-# ifdef YYPRINT
-  if (yytype < YYNTOKENS)
-    YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
-# else
-  YYUSE (yyoutput);
-# endif
-  switch (yytype)
-    {
-      default:
-       break;
-    }
-}
-
-
-/*--------------------------------.
-| Print this symbol on YYOUTPUT.  |
-`--------------------------------*/
-
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-static void
-yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, yyscan_t                 scanner)
-#else
-static void
-yy_symbol_print (yyoutput, yytype, yyvaluep, scanner)
-    FILE *yyoutput;
-    int yytype;
-    YYSTYPE const * const yyvaluep;
-    yyscan_t                 scanner;
-#endif
-{
-  if (yytype < YYNTOKENS)
-    YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
-  else
-    YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
-
-  yy_symbol_value_print (yyoutput, yytype, yyvaluep, scanner);
-  YYFPRINTF (yyoutput, ")");
-}
-
-/*------------------------------------------------------------------.
-| yy_stack_print -- Print the state stack from its BOTTOM up to its |
-| TOP (included).                                                   |
-`------------------------------------------------------------------*/
-
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-static void
-yy_stack_print (yytype_int16 *bottom, yytype_int16 *top)
-#else
-static void
-yy_stack_print (bottom, top)
-    yytype_int16 *bottom;
-    yytype_int16 *top;
-#endif
-{
-  YYFPRINTF (stderr, "Stack now");
-  for (; bottom <= top; ++bottom)
-    YYFPRINTF (stderr, " %d", *bottom);
-  YYFPRINTF (stderr, "\n");
-}
-
-# define YY_STACK_PRINT(Bottom, Top)                           \
-do {                                                           \
-  if (yydebug)                                                 \
-    yy_stack_print ((Bottom), (Top));                          \
-} while (YYID (0))
-
-
-/*------------------------------------------------.
-| Report that the YYRULE is going to be reduced.  |
-`------------------------------------------------*/
-
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-static void
-yy_reduce_print (YYSTYPE *yyvsp, int yyrule, yyscan_t                 scanner)
-#else
-static void
-yy_reduce_print (yyvsp, yyrule, scanner)
-    YYSTYPE *yyvsp;
-    int yyrule;
-    yyscan_t                 scanner;
-#endif
-{
-  int yynrhs = yyr2[yyrule];
-  int yyi;
-  unsigned long int yylno = yyrline[yyrule];
-  YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
-            yyrule - 1, yylno);
-  /* The symbols being reduced.  */
-  for (yyi = 0; yyi < yynrhs; yyi++)
-    {
-      fprintf (stderr, "   $%d = ", yyi + 1);
-      yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
-                      &(yyvsp[(yyi + 1) - (yynrhs)])
-                                      , scanner);
-      fprintf (stderr, "\n");
-    }
-}
-
-# define YY_REDUCE_PRINT(Rule)         \
-do {                                   \
-  if (yydebug)                         \
-    yy_reduce_print (yyvsp, Rule, scanner); \
-} while (YYID (0))
-
-/* Nonzero means print parse trace.  It is left uninitialized so that
-   multiple parsers can coexist.  */
-int yydebug;
-#else /* !YYDEBUG */
-# define YYDPRINTF(Args)
-# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
-# define YY_STACK_PRINT(Bottom, Top)
-# define YY_REDUCE_PRINT(Rule)
-#endif /* !YYDEBUG */
-
-
-/* YYINITDEPTH -- initial size of the parser's stacks.  */
-#ifndef        YYINITDEPTH
-# define YYINITDEPTH 200
-#endif
-
-/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
-   if the built-in stack extension method is used).
-
-   Do not make this value too large; the results are undefined if
-   YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
-   evaluated with infinite-precision integer arithmetic.  */
-
-#ifndef YYMAXDEPTH
-# define YYMAXDEPTH 10000
-#endif
-
-\f
-
-#if YYERROR_VERBOSE
-
-# ifndef yystrlen
-#  if defined __GLIBC__ && defined _STRING_H
-#   define yystrlen strlen
-#  else
-/* Return the length of YYSTR.  */
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-static YYSIZE_T
-yystrlen (const char *yystr)
-#else
-static YYSIZE_T
-yystrlen (yystr)
-    const char *yystr;
-#endif
-{
-  YYSIZE_T yylen;
-  for (yylen = 0; yystr[yylen]; yylen++)
-    continue;
-  return yylen;
-}
-#  endif
-# endif
-
-# ifndef yystpcpy
-#  if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
-#   define yystpcpy stpcpy
-#  else
-/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
-   YYDEST.  */
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-static char *
-yystpcpy (char *yydest, const char *yysrc)
-#else
-static char *
-yystpcpy (yydest, yysrc)
-    char *yydest;
-    const char *yysrc;
-#endif
-{
-  char *yyd = yydest;
-  const char *yys = yysrc;
-
-  while ((*yyd++ = *yys++) != '\0')
-    continue;
-
-  return yyd - 1;
-}
-#  endif
-# endif
-
-# ifndef yytnamerr
-/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
-   quotes and backslashes, so that it's suitable for yyerror.  The
-   heuristic is that double-quoting is unnecessary unless the string
-   contains an apostrophe, a comma, or backslash (other than
-   backslash-backslash).  YYSTR is taken from yytname.  If YYRES is
-   null, do not copy; instead, return the length of what the result
-   would have been.  */
-static YYSIZE_T
-yytnamerr (char *yyres, const char *yystr)
-{
-  if (*yystr == '"')
-    {
-      YYSIZE_T yyn = 0;
-      char const *yyp = yystr;
-
-      for (;;)
-       switch (*++yyp)
-         {
-         case '\'':
-         case ',':
-           goto do_not_strip_quotes;
-
-         case '\\':
-           if (*++yyp != '\\')
-             goto do_not_strip_quotes;
-           /* Fall through.  */
-         default:
-           if (yyres)
-             yyres[yyn] = *yyp;
-           yyn++;
-           break;
-
-         case '"':
-           if (yyres)
-             yyres[yyn] = '\0';
-           return yyn;
-         }
-    do_not_strip_quotes: ;
-    }
-
-  if (! yyres)
-    return yystrlen (yystr);
-
-  return yystpcpy (yyres, yystr) - yyres;
-}
-# endif
-
-/* Copy into YYRESULT an error message about the unexpected token
-   YYCHAR while in state YYSTATE.  Return the number of bytes copied,
-   including the terminating null byte.  If YYRESULT is null, do not
-   copy anything; just return the number of bytes that would be
-   copied.  As a special case, return 0 if an ordinary "syntax error"
-   message will do.  Return YYSIZE_MAXIMUM if overflow occurs during
-   size calculation.  */
-static YYSIZE_T
-yysyntax_error (char *yyresult, int yystate, int yychar)
-{
-  int yyn = yypact[yystate];
-
-  if (! (YYPACT_NINF < yyn && yyn <= YYLAST))
-    return 0;
-  else
-    {
-      int yytype = YYTRANSLATE (yychar);
-      YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]);
-      YYSIZE_T yysize = yysize0;
-      YYSIZE_T yysize1;
-      int yysize_overflow = 0;
-      enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
-      char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
-      int yyx;
-
-# if 0
-      /* This is so xgettext sees the translatable formats that are
-        constructed on the fly.  */
-      YY_("syntax error, unexpected %s");
-      YY_("syntax error, unexpected %s, expecting %s");
-      YY_("syntax error, unexpected %s, expecting %s or %s");
-      YY_("syntax error, unexpected %s, expecting %s or %s or %s");
-      YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s");
-# endif
-      char *yyfmt;
-      char const *yyf;
-      static char const yyunexpected[] = "syntax error, unexpected %s";
-      static char const yyexpecting[] = ", expecting %s";
-      static char const yyor[] = " or %s";
-      char yyformat[sizeof yyunexpected
-                   + sizeof yyexpecting - 1
-                   + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2)
-                      * (sizeof yyor - 1))];
-      char const *yyprefix = yyexpecting;
-
-      /* Start YYX at -YYN if negative to avoid negative indexes in
-        YYCHECK.  */
-      int yyxbegin = yyn < 0 ? -yyn : 0;
-
-      /* Stay within bounds of both yycheck and yytname.  */
-      int yychecklim = YYLAST - yyn + 1;
-      int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
-      int yycount = 1;
-
-      yyarg[0] = yytname[yytype];
-      yyfmt = yystpcpy (yyformat, yyunexpected);
-
-      for (yyx = yyxbegin; yyx < yyxend; ++yyx)
-       if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
-         {
-           if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
-             {
-               yycount = 1;
-               yysize = yysize0;
-               yyformat[sizeof yyunexpected - 1] = '\0';
-               break;
-             }
-           yyarg[yycount++] = yytname[yyx];
-           yysize1 = yysize + yytnamerr (0, yytname[yyx]);
-           yysize_overflow |= (yysize1 < yysize);
-           yysize = yysize1;
-           yyfmt = yystpcpy (yyfmt, yyprefix);
-           yyprefix = yyor;
-         }
-
-      yyf = YY_(yyformat);
-      yysize1 = yysize + yystrlen (yyf);
-      yysize_overflow |= (yysize1 < yysize);
-      yysize = yysize1;
-
-      if (yysize_overflow)
-       return YYSIZE_MAXIMUM;
-
-      if (yyresult)
-       {
-         /* Avoid sprintf, as that infringes on the user's name space.
-            Don't have undefined behavior even if the translation
-            produced a string with the wrong number of "%s"s.  */
-         char *yyp = yyresult;
-         int yyi = 0;
-         while ((*yyp = *yyf) != '\0')
-           {
-             if (*yyp == '%' && yyf[1] == 's' && yyi < yycount)
-               {
-                 yyp += yytnamerr (yyp, yyarg[yyi++]);
-                 yyf += 2;
-               }
-             else
-               {
-                 yyp++;
-                 yyf++;
-               }
-           }
-       }
-      return yysize;
-    }
-}
-#endif /* YYERROR_VERBOSE */
-\f
-
-/*-----------------------------------------------.
-| Release the memory associated to this symbol.  |
-`-----------------------------------------------*/
-
-/*ARGSUSED*/
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-static void
-yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, yyscan_t                 scanner)
-#else
-static void
-yydestruct (yymsg, yytype, yyvaluep, scanner)
-    const char *yymsg;
-    int yytype;
-    YYSTYPE *yyvaluep;
-    yyscan_t                 scanner;
-#endif
-{
-  YYUSE (yyvaluep);
-  YYUSE (scanner);
-
-  if (!yymsg)
-    yymsg = "Deleting";
-  YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
-
-  switch (yytype)
-    {
-      case 5: /* "HELP_TOPIC" */
-#line 161 "parser.y"
-       { free((yyvaluep->str));                     };
-#line 1317 "parser.c"
-       break;
-      case 8: /* "STR" */
-#line 161 "parser.y"
-       { free((yyvaluep->str));                     };
-#line 1322 "parser.c"
-       break;
-      case 9: /* "IDENTIFIER" */
-#line 161 "parser.y"
-       { free((yyvaluep->str));                     };
-#line 1327 "parser.c"
-       break;
-      case 25: /* "PARAM" */
-#line 162 "parser.y"
-       { if((yyvaluep->str)) free((yyvaluep->str));              };
-#line 1332 "parser.c"
-       break;
-      case 28: /* "CMP_OP" */
-#line 161 "parser.y"
-       { free((yyvaluep->str));                     };
-#line 1337 "parser.c"
-       break;
-      case 51: /* "command" */
-#line 163 "parser.y"
-       { if((yyvaluep->sel)) _gmx_selelem_free((yyvaluep->sel)); };
-#line 1342 "parser.c"
-       break;
-      case 52: /* "cmd_plain" */
-#line 163 "parser.y"
-       { if((yyvaluep->sel)) _gmx_selelem_free((yyvaluep->sel)); };
-#line 1347 "parser.c"
-       break;
-      case 55: /* "selection" */
-#line 164 "parser.y"
-       { _gmx_selelem_free_chain((yyvaluep->sel));  };
-#line 1352 "parser.c"
-       break;
-      case 59: /* "string" */
-#line 161 "parser.y"
-       { free((yyvaluep->str));                     };
-#line 1357 "parser.c"
-       break;
-      case 60: /* "sel_expr" */
-#line 165 "parser.y"
-       { _gmx_selelem_free((yyvaluep->sel));        };
-#line 1362 "parser.c"
-       break;
-      case 62: /* "num_expr" */
-#line 165 "parser.y"
-       { _gmx_selelem_free((yyvaluep->sel));        };
-#line 1367 "parser.c"
-       break;
-      case 63: /* "str_expr" */
-#line 165 "parser.y"
-       { _gmx_selelem_free((yyvaluep->sel));        };
-#line 1372 "parser.c"
-       break;
-      case 64: /* "pos_expr" */
-#line 165 "parser.y"
-       { _gmx_selelem_free((yyvaluep->sel));        };
-#line 1377 "parser.c"
-       break;
-      case 65: /* "method_params" */
-#line 166 "parser.y"
-       { _gmx_selexpr_free_params((yyvaluep->param)); };
-#line 1382 "parser.c"
-       break;
-      case 66: /* "method_param_list" */
-#line 166 "parser.y"
-       { _gmx_selexpr_free_params((yyvaluep->param)); };
-#line 1387 "parser.c"
-       break;
-      case 67: /* "method_param" */
-#line 166 "parser.y"
-       { _gmx_selexpr_free_params((yyvaluep->param)); };
-#line 1392 "parser.c"
-       break;
-      case 68: /* "value_list" */
-#line 167 "parser.y"
-       { _gmx_selexpr_free_values((yyvaluep->val)); };
-#line 1397 "parser.c"
-       break;
-      case 69: /* "value_list_contents" */
-#line 167 "parser.y"
-       { _gmx_selexpr_free_values((yyvaluep->val)); };
-#line 1402 "parser.c"
-       break;
-      case 70: /* "basic_value_list" */
-#line 168 "parser.y"
-       { _gmx_selexpr_free_values((yyvaluep->val)); };
-#line 1407 "parser.c"
-       break;
-      case 71: /* "basic_value_list_contents" */
-#line 168 "parser.y"
-       { _gmx_selexpr_free_values((yyvaluep->val)); };
-#line 1412 "parser.c"
-       break;
-      case 72: /* "value_item" */
-#line 167 "parser.y"
-       { _gmx_selexpr_free_values((yyvaluep->val)); };
-#line 1417 "parser.c"
-       break;
-      case 73: /* "basic_value_item" */
-#line 168 "parser.y"
-       { _gmx_selexpr_free_values((yyvaluep->val)); };
-#line 1422 "parser.c"
-       break;
-      case 74: /* "value_item_range" */
-#line 167 "parser.y"
-       { _gmx_selexpr_free_values((yyvaluep->val)); };
-#line 1427 "parser.c"
-       break;
-
-      default:
-       break;
-    }
-}
-\f
-
-/* Prevent warnings from -Wmissing-prototypes.  */
-
-#ifdef YYPARSE_PARAM
-#if defined __STDC__ || defined __cplusplus
-int yyparse (void *YYPARSE_PARAM);
-#else
-int yyparse ();
-#endif
-#else /* ! YYPARSE_PARAM */
-#if defined __STDC__ || defined __cplusplus
-int yyparse (yyscan_t                 scanner);
-#else
-int yyparse ();
-#endif
-#endif /* ! YYPARSE_PARAM */
-
-
-
-
-
-
-/*----------.
-| yyparse.  |
-`----------*/
-
-#ifdef YYPARSE_PARAM
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-int
-yyparse (void *YYPARSE_PARAM)
-#else
-int
-yyparse (YYPARSE_PARAM)
-    void *YYPARSE_PARAM;
-#endif
-#else /* ! YYPARSE_PARAM */
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-int
-yyparse (yyscan_t                 scanner)
-#else
-int
-yyparse (scanner)
-    yyscan_t                 scanner;
-#endif
-#endif
-{
-  /* The look-ahead symbol.  */
-int yychar;
-
-/* The semantic value of the look-ahead symbol.  */
-YYSTYPE yylval;
-
-/* Number of syntax errors so far.  */
-int yynerrs;
-
-  int yystate;
-  int yyn;
-  int yyresult;
-  /* Number of tokens to shift before error messages enabled.  */
-  int yyerrstatus;
-  /* Look-ahead token as an internal (translated) token number.  */
-  int yytoken = 0;
-#if YYERROR_VERBOSE
-  /* Buffer for error messages, and its allocated size.  */
-  char yymsgbuf[128];
-  char *yymsg = yymsgbuf;
-  YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
-#endif
-
-  /* Three stacks and their tools:
-     `yyss': related to states,
-     `yyvs': related to semantic values,
-     `yyls': related to locations.
-
-     Refer to the stacks thru separate pointers, to allow yyoverflow
-     to reallocate them elsewhere.  */
-
-  /* The state stack.  */
-  yytype_int16 yyssa[YYINITDEPTH];
-  yytype_int16 *yyss = yyssa;
-  yytype_int16 *yyssp;
-
-  /* The semantic value stack.  */
-  YYSTYPE yyvsa[YYINITDEPTH];
-  YYSTYPE *yyvs = yyvsa;
-  YYSTYPE *yyvsp;
-
-
-
-#define YYPOPSTACK(N)   (yyvsp -= (N), yyssp -= (N))
-
-  YYSIZE_T yystacksize = YYINITDEPTH;
-
-  /* The variables used to return semantic value and location from the
-     action routines.  */
-  YYSTYPE yyval;
-
-
-  /* The number of symbols on the RHS of the reduced rule.
-     Keep to zero when no symbol should be popped.  */
-  int yylen = 0;
-
-  YYDPRINTF ((stderr, "Starting parse\n"));
-
-  yystate = 0;
-  yyerrstatus = 0;
-  yynerrs = 0;
-  yychar = YYEMPTY;            /* Cause a token to be read.  */
-
-  /* Initialize stack pointers.
-     Waste one element of value and location stack
-     so that they stay on the same level as the state stack.
-     The wasted elements are never initialized.  */
-
-  yyssp = yyss;
-  yyvsp = yyvs;
-
-  goto yysetstate;
-
-/*------------------------------------------------------------.
-| yynewstate -- Push a new state, which is found in yystate.  |
-`------------------------------------------------------------*/
- yynewstate:
-  /* In all cases, when you get here, the value and location stacks
-     have just been pushed.  So pushing a state here evens the stacks.  */
-  yyssp++;
-
- yysetstate:
-  *yyssp = yystate;
-
-  if (yyss + yystacksize - 1 <= yyssp)
-    {
-      /* Get the current used size of the three stacks, in elements.  */
-      YYSIZE_T yysize = yyssp - yyss + 1;
-
-#ifdef yyoverflow
-      {
-       /* Give user a chance to reallocate the stack.  Use copies of
-          these so that the &'s don't force the real ones into
-          memory.  */
-       YYSTYPE *yyvs1 = yyvs;
-       yytype_int16 *yyss1 = yyss;
-
-
-       /* Each stack pointer address is followed by the size of the
-          data in use in that stack, in bytes.  This used to be a
-          conditional around just the two extra args, but that might
-          be undefined if yyoverflow is a macro.  */
-       yyoverflow (YY_("memory exhausted"),
-                   &yyss1, yysize * sizeof (*yyssp),
-                   &yyvs1, yysize * sizeof (*yyvsp),
-
-                   &yystacksize);
-
-       yyss = yyss1;
-       yyvs = yyvs1;
-      }
-#else /* no yyoverflow */
-# ifndef YYSTACK_RELOCATE
-      goto yyexhaustedlab;
-# else
-      /* Extend the stack our own way.  */
-      if (YYMAXDEPTH <= yystacksize)
-       goto yyexhaustedlab;
-      yystacksize *= 2;
-      if (YYMAXDEPTH < yystacksize)
-       yystacksize = YYMAXDEPTH;
-
-      {
-       yytype_int16 *yyss1 = yyss;
-       union yyalloc *yyptr =
-         (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
-       if (! yyptr)
-         goto yyexhaustedlab;
-       YYSTACK_RELOCATE (yyss);
-       YYSTACK_RELOCATE (yyvs);
-
-#  undef YYSTACK_RELOCATE
-       if (yyss1 != yyssa)
-         YYSTACK_FREE (yyss1);
-      }
-# endif
-#endif /* no yyoverflow */
-
-      yyssp = yyss + yysize - 1;
-      yyvsp = yyvs + yysize - 1;
-
-
-      YYDPRINTF ((stderr, "Stack size increased to %lu\n",
-                 (unsigned long int) yystacksize));
-
-      if (yyss + yystacksize - 1 <= yyssp)
-       YYABORT;
-    }
-
-  YYDPRINTF ((stderr, "Entering state %d\n", yystate));
-
-  goto yybackup;
-
-/*-----------.
-| yybackup.  |
-`-----------*/
-yybackup:
-
-  /* Do appropriate processing given the current state.  Read a
-     look-ahead token if we need one and don't already have one.  */
-
-  /* First try to decide what to do without reference to look-ahead token.  */
-  yyn = yypact[yystate];
-  if (yyn == YYPACT_NINF)
-    goto yydefault;
-
-  /* Not known => get a look-ahead token if don't already have one.  */
-
-  /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol.  */
-  if (yychar == YYEMPTY)
-    {
-      YYDPRINTF ((stderr, "Reading a token: "));
-      yychar = YYLEX;
-    }
-
-  if (yychar <= YYEOF)
-    {
-      yychar = yytoken = YYEOF;
-      YYDPRINTF ((stderr, "Now at end of input.\n"));
-    }
-  else
-    {
-      yytoken = YYTRANSLATE (yychar);
-      YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
-    }
-
-  /* If the proper action on seeing token YYTOKEN is to reduce or to
-     detect an error, take that action.  */
-  yyn += yytoken;
-  if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
-    goto yydefault;
-  yyn = yytable[yyn];
-  if (yyn <= 0)
-    {
-      if (yyn == 0 || yyn == YYTABLE_NINF)
-       goto yyerrlab;
-      yyn = -yyn;
-      goto yyreduce;
-    }
-
-  if (yyn == YYFINAL)
-    YYACCEPT;
-
-  /* Count tokens shifted since error; after three, turn off error
-     status.  */
-  if (yyerrstatus)
-    yyerrstatus--;
-
-  /* Shift the look-ahead token.  */
-  YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
-
-  /* Discard the shifted token unless it is eof.  */
-  if (yychar != YYEOF)
-    yychar = YYEMPTY;
-
-  yystate = yyn;
-  *++yyvsp = yylval;
-
-  goto yynewstate;
-
-
-/*-----------------------------------------------------------.
-| yydefault -- do the default action for the current state.  |
-`-----------------------------------------------------------*/
-yydefault:
-  yyn = yydefact[yystate];
-  if (yyn == 0)
-    goto yyerrlab;
-  goto yyreduce;
-
-
-/*-----------------------------.
-| yyreduce -- Do a reduction.  |
-`-----------------------------*/
-yyreduce:
-  /* yyn is the number of a rule to reduce with.  */
-  yylen = yyr2[yyn];
-
-  /* If YYLEN is nonzero, implement the default value of the action:
-     `$$ = $1'.
-
-     Otherwise, the following line sets YYVAL to garbage.
-     This behavior is undocumented and Bison
-     users should not rely upon it.  Assigning to YYVAL
-     unconditionally makes the parser a bit smaller, and it avoids a
-     GCC warning that YYVAL may be used uninitialized.  */
-  yyval = yyvsp[1-yylen];
-
-
-  YY_REDUCE_PRINT (yyn);
-  switch (yyn)
-    {
-        case 2:
-#line 182 "parser.y"
-    { (yyval.sel) = NULL ;}
-    break;
-
-  case 3:
-#line 184 "parser.y"
-    {
-                 (yyval.sel) = _gmx_sel_append_selection((yyvsp[(2) - (2)].sel), (yyvsp[(1) - (2)].sel), scanner);
-                 if (_gmx_sel_parser_should_finish(scanner))
-                     YYACCEPT;
-             ;}
-    break;
-
-  case 4:
-#line 192 "parser.y"
-    { (yyval.sel) = (yyvsp[(1) - (2)].sel); ;}
-    break;
-
-  case 5:
-#line 194 "parser.y"
-    {
-                 (yyval.sel) = NULL;
-                 _gmx_selparser_error("invalid selection '%s'",
-                                      _gmx_sel_lexer_pselstr(scanner));
-                 _gmx_sel_lexer_clear_method_stack(scanner);
-                 if (_gmx_sel_is_lexer_interactive(scanner))
-                 {
-                     _gmx_sel_lexer_clear_pselstr(scanner);
-                     yyerrok;
-                 }
-                 else
-                 {
-                     YYABORT;
-                 }
-             ;}
-    break;
-
-  case 6:
-#line 213 "parser.y"
-    {
-                 (yyval.sel) = NULL;
-                 _gmx_sel_handle_empty_cmd(scanner);
-             ;}
-    break;
-
-  case 7:
-#line 217 "parser.y"
-    { (yyval.sel) = NULL; ;}
-    break;
-
-  case 8:
-#line 219 "parser.y"
-    {
-                 t_selelem *s, *p;
-                 s = _gmx_sel_init_group_by_id((yyvsp[(1) - (1)].i), scanner);
-                 if (s == NULL) YYERROR;
-                 p = _gmx_sel_init_position(s, NULL, scanner);
-                 if (p == NULL) YYERROR;
-                 (yyval.sel) = _gmx_sel_init_selection(strdup(s->name), p, scanner);
-             ;}
-    break;
-
-  case 9:
-#line 228 "parser.y"
-    {
-                 t_selelem *s, *p;
-                 s = _gmx_sel_init_group_by_name((yyvsp[(1) - (1)].str), scanner);
-                 free((yyvsp[(1) - (1)].str));
-                 if (s == NULL) YYERROR;
-                 p = _gmx_sel_init_position(s, NULL, scanner);
-                 if (p == NULL) YYERROR;
-                 (yyval.sel) = _gmx_sel_init_selection(strdup(s->name), p, scanner);
-             ;}
-    break;
-
-  case 10:
-#line 238 "parser.y"
-    { (yyval.sel) = _gmx_sel_init_selection(NULL, (yyvsp[(1) - (1)].sel), scanner); ;}
-    break;
-
-  case 11:
-#line 240 "parser.y"
-    { (yyval.sel) = _gmx_sel_init_selection((yyvsp[(1) - (2)].str), (yyvsp[(2) - (2)].sel), scanner);   ;}
-    break;
-
-  case 12:
-#line 242 "parser.y"
-    { (yyval.sel) = _gmx_sel_assign_variable((yyvsp[(1) - (3)].str), (yyvsp[(3) - (3)].sel), scanner);  ;}
-    break;
-
-  case 13:
-#line 244 "parser.y"
-    { (yyval.sel) = _gmx_sel_assign_variable((yyvsp[(1) - (3)].str), (yyvsp[(3) - (3)].sel), scanner);  ;}
-    break;
-
-  case 14:
-#line 246 "parser.y"
-    { (yyval.sel) = _gmx_sel_assign_variable((yyvsp[(1) - (3)].str), (yyvsp[(3) - (3)].sel), scanner);  ;}
-    break;
-
-  case 15:
-#line 251 "parser.y"
-    { _gmx_sel_handle_help_cmd(NULL, scanner); ;}
-    break;
-
-  case 17:
-#line 255 "parser.y"
-    { _gmx_sel_handle_help_cmd((yyvsp[(2) - (2)].str), scanner); ;}
-    break;
-
-  case 18:
-#line 256 "parser.y"
-    { _gmx_sel_handle_help_cmd((yyvsp[(2) - (2)].str), scanner); ;}
-    break;
-
-  case 19:
-#line 260 "parser.y"
-    { (yyval.sel) = (yyvsp[(1) - (1)].sel); ;}
-    break;
-
-  case 20:
-#line 262 "parser.y"
-    {
-                 (yyval.sel) = _gmx_sel_init_position((yyvsp[(1) - (1)].sel), NULL, scanner);
-                 if ((yyval.sel) == NULL) YYERROR;
-             ;}
-    break;
-
-  case 21:
-#line 266 "parser.y"
-    { (yyval.sel) = (yyvsp[(2) - (3)].sel); ;}
-    break;
-
-  case 22:
-#line 268 "parser.y"
-    {
-                 (yyval.sel) = _gmx_sel_init_modifier((yyvsp[(2) - (3)].meth), (yyvsp[(3) - (3)].param), (yyvsp[(1) - (3)].sel), scanner);
-                 if ((yyval.sel) == NULL) YYERROR;
-             ;}
-    break;
-
-  case 23:
-#line 279 "parser.y"
-    { (yyval.r) = (yyvsp[(1) - (1)].i); ;}
-    break;
-
-  case 24:
-#line 280 "parser.y"
-    { (yyval.r) = -(yyvsp[(2) - (2)].i); ;}
-    break;
-
-  case 25:
-#line 284 "parser.y"
-    { (yyval.r) = (yyvsp[(1) - (1)].r); ;}
-    break;
-
-  case 26:
-#line 285 "parser.y"
-    { (yyval.r) = -(yyvsp[(2) - (2)].r); ;}
-    break;
-
-  case 27:
-#line 288 "parser.y"
-    { (yyval.r) = (yyvsp[(1) - (1)].r); ;}
-    break;
-
-  case 28:
-#line 289 "parser.y"
-    { (yyval.r) = (yyvsp[(1) - (1)].r); ;}
-    break;
-
-  case 29:
-#line 292 "parser.y"
-    { (yyval.str) = (yyvsp[(1) - (1)].str); ;}
-    break;
-
-  case 30:
-#line 293 "parser.y"
-    { (yyval.str) = (yyvsp[(1) - (1)].str); ;}
-    break;
-
-  case 31:
-#line 302 "parser.y"
-    {
-                 (yyval.sel) = _gmx_selelem_create(SEL_BOOLEAN);
-                 (yyval.sel)->u.boolt = BOOL_NOT;
-                 (yyval.sel)->child = (yyvsp[(2) - (2)].sel);
-             ;}
-    break;
-
-  case 32:
-#line 308 "parser.y"
-    {
-                 (yyval.sel) = _gmx_selelem_create(SEL_BOOLEAN);
-                 (yyval.sel)->u.boolt = BOOL_AND;
-                 (yyval.sel)->child = (yyvsp[(1) - (3)].sel); (yyval.sel)->child->next = (yyvsp[(3) - (3)].sel);
-             ;}
-    break;
-
-  case 33:
-#line 314 "parser.y"
-    {
-                 (yyval.sel) = _gmx_selelem_create(SEL_BOOLEAN);
-                 (yyval.sel)->u.boolt = BOOL_OR;
-                 (yyval.sel)->child = (yyvsp[(1) - (3)].sel); (yyval.sel)->child->next = (yyvsp[(3) - (3)].sel);
-             ;}
-    break;
-
-  case 34:
-#line 325 "parser.y"
-    { (yyval.sel) = (yyvsp[(2) - (3)].sel); ;}
-    break;
-
-  case 35:
-#line 330 "parser.y"
-    {
-                 (yyval.sel) = _gmx_sel_init_comparison((yyvsp[(1) - (3)].sel), (yyvsp[(3) - (3)].sel), (yyvsp[(2) - (3)].str), scanner);
-                 if ((yyval.sel) == NULL) YYERROR;
-             ;}
-    break;
-
-  case 36:
-#line 338 "parser.y"
-    {
-                 (yyval.sel) = _gmx_sel_init_group_by_name((yyvsp[(2) - (2)].str), scanner);
-                 free((yyvsp[(2) - (2)].str));
-                 if ((yyval.sel) == NULL) YYERROR;
-             ;}
-    break;
-
-  case 37:
-#line 344 "parser.y"
-    {
-                 (yyval.sel) = _gmx_sel_init_group_by_id((yyvsp[(2) - (2)].i), scanner);
-                 if ((yyval.sel) == NULL) YYERROR;
-             ;}
-    break;
-
-  case 38:
-#line 351 "parser.y"
-    { (yyval.str) = NULL; ;}
-    break;
-
-  case 39:
-#line 352 "parser.y"
-    { (yyval.str) = (yyvsp[(1) - (1)].str);   ;}
-    break;
-
-  case 40:
-#line 357 "parser.y"
-    {
-                 (yyval.sel) = _gmx_sel_init_keyword((yyvsp[(2) - (2)].meth), NULL, (yyvsp[(1) - (2)].str), scanner);
-                 if ((yyval.sel) == NULL) YYERROR;
-             ;}
-    break;
-
-  case 41:
-#line 362 "parser.y"
-    {
-                 (yyval.sel) = _gmx_sel_init_keyword((yyvsp[(2) - (3)].meth), process_value_list((yyvsp[(3) - (3)].val), NULL), (yyvsp[(1) - (3)].str), scanner);
-                 if ((yyval.sel) == NULL) YYERROR;
-             ;}
-    break;
-
-  case 42:
-#line 367 "parser.y"
-    {
-                 (yyval.sel) = _gmx_sel_init_keyword((yyvsp[(2) - (3)].meth), process_value_list((yyvsp[(3) - (3)].val), NULL), (yyvsp[(1) - (3)].str), scanner);
-                 if ((yyval.sel) == NULL) YYERROR;
-             ;}
-    break;
-
-  case 43:
-#line 375 "parser.y"
-    {
-                 (yyval.sel) = _gmx_sel_init_method((yyvsp[(2) - (3)].meth), (yyvsp[(3) - (3)].param), (yyvsp[(1) - (3)].str), scanner);
-                 if ((yyval.sel) == NULL) YYERROR;
-             ;}
-    break;
-
-  case 44:
-#line 387 "parser.y"
-    {
-                 (yyval.sel) = _gmx_selelem_create(SEL_CONST);
-                 _gmx_selelem_set_vtype((yyval.sel), INT_VALUE);
-                 _gmx_selvalue_reserve(&(yyval.sel)->v, 1);
-                 (yyval.sel)->v.u.i[0] = (yyvsp[(1) - (1)].i);
-             ;}
-    break;
-
-  case 45:
-#line 394 "parser.y"
-    {
-                 (yyval.sel) = _gmx_selelem_create(SEL_CONST);
-                 _gmx_selelem_set_vtype((yyval.sel), REAL_VALUE);
-                 _gmx_selvalue_reserve(&(yyval.sel)->v, 1);
-                 (yyval.sel)->v.u.r[0] = (yyvsp[(1) - (1)].r);
-             ;}
-    break;
-
-  case 46:
-#line 404 "parser.y"
-    {
-                 (yyval.sel) = _gmx_sel_init_keyword((yyvsp[(2) - (2)].meth), NULL, (yyvsp[(1) - (2)].str), scanner);
-                 if ((yyval.sel) == NULL) YYERROR;
-             ;}
-    break;
-
-  case 47:
-#line 409 "parser.y"
-    {
-                 (yyval.sel) = _gmx_sel_init_method((yyvsp[(2) - (3)].meth), (yyvsp[(3) - (3)].param), (yyvsp[(1) - (3)].str), scanner);
-                 if ((yyval.sel) == NULL) YYERROR;
-             ;}
-    break;
-
-  case 48:
-#line 417 "parser.y"
-    { (yyval.sel) = _gmx_sel_init_arithmetic((yyvsp[(1) - (3)].sel), (yyvsp[(3) - (3)].sel), '+', scanner); ;}
-    break;
-
-  case 49:
-#line 419 "parser.y"
-    { (yyval.sel) = _gmx_sel_init_arithmetic((yyvsp[(1) - (3)].sel), (yyvsp[(3) - (3)].sel), '-', scanner); ;}
-    break;
-
-  case 50:
-#line 421 "parser.y"
-    { (yyval.sel) = _gmx_sel_init_arithmetic((yyvsp[(1) - (3)].sel), (yyvsp[(3) - (3)].sel), '*', scanner); ;}
-    break;
-
-  case 51:
-#line 423 "parser.y"
-    { (yyval.sel) = _gmx_sel_init_arithmetic((yyvsp[(1) - (3)].sel), (yyvsp[(3) - (3)].sel), '/', scanner); ;}
-    break;
-
-  case 52:
-#line 425 "parser.y"
-    { (yyval.sel) = _gmx_sel_init_arithmetic((yyvsp[(2) - (2)].sel), NULL, '-', scanner); ;}
-    break;
-
-  case 53:
-#line 427 "parser.y"
-    { (yyval.sel) = _gmx_sel_init_arithmetic((yyvsp[(1) - (3)].sel), (yyvsp[(3) - (3)].sel), '^', scanner); ;}
-    break;
-
-  case 54:
-#line 428 "parser.y"
-    { (yyval.sel) = (yyvsp[(2) - (3)].sel); ;}
-    break;
-
-  case 55:
-#line 436 "parser.y"
-    {
-                 (yyval.sel) = _gmx_selelem_create(SEL_CONST);
-                 _gmx_selelem_set_vtype((yyval.sel), STR_VALUE);
-                 _gmx_selvalue_reserve(&(yyval.sel)->v, 1);
-                 (yyval.sel)->v.u.s[0] = (yyvsp[(1) - (1)].str);
-             ;}
-    break;
-
-  case 56:
-#line 443 "parser.y"
-    {
-                 (yyval.sel) = _gmx_sel_init_keyword((yyvsp[(2) - (2)].meth), NULL, (yyvsp[(1) - (2)].str), scanner);
-                 if ((yyval.sel) == NULL) YYERROR;
-             ;}
-    break;
-
-  case 57:
-#line 455 "parser.y"
-    { (yyval.sel) = _gmx_sel_init_const_position((yyvsp[(2) - (7)].r), (yyvsp[(4) - (7)].r), (yyvsp[(6) - (7)].r)); ;}
-    break;
-
-  case 58:
-#line 459 "parser.y"
-    { (yyval.sel) = (yyvsp[(2) - (3)].sel); ;}
-    break;
-
-  case 59:
-#line 464 "parser.y"
-    {
-                 (yyval.sel) = _gmx_sel_init_method((yyvsp[(1) - (2)].meth), (yyvsp[(2) - (2)].param), NULL, scanner);
-                 if ((yyval.sel) == NULL) YYERROR;
-             ;}
-    break;
-
-  case 60:
-#line 472 "parser.y"
-    {
-                 (yyval.sel) = _gmx_sel_init_position((yyvsp[(3) - (3)].sel), (yyvsp[(1) - (3)].str), scanner);
-                 if ((yyval.sel) == NULL) YYERROR;
-             ;}
-    break;
-
-  case 61:
-#line 483 "parser.y"
-    { (yyval.sel) = _gmx_sel_init_variable_ref((yyvsp[(1) - (1)].sel)); ;}
-    break;
-
-  case 62:
-#line 487 "parser.y"
-    { (yyval.sel) = _gmx_sel_init_variable_ref((yyvsp[(1) - (1)].sel)); ;}
-    break;
-
-  case 63:
-#line 491 "parser.y"
-    { (yyval.sel) = _gmx_sel_init_variable_ref((yyvsp[(1) - (1)].sel)); ;}
-    break;
-
-  case 64:
-#line 500 "parser.y"
-    { (yyval.param) = process_param_list((yyvsp[(1) - (1)].param)); ;}
-    break;
-
-  case 65:
-#line 502 "parser.y"
-    { (yyval.param) = process_param_list((yyvsp[(1) - (2)].param)); ;}
-    break;
-
-  case 66:
-#line 506 "parser.y"
-    { (yyval.param) = NULL;              ;}
-    break;
-
-  case 67:
-#line 508 "parser.y"
-    { (yyvsp[(2) - (2)].param)->next = (yyvsp[(1) - (2)].param); (yyval.param) = (yyvsp[(2) - (2)].param); ;}
-    break;
-
-  case 68:
-#line 513 "parser.y"
-    {
-                 (yyval.param) = _gmx_selexpr_create_param((yyvsp[(1) - (2)].str));
-                 (yyval.param)->value = process_value_list((yyvsp[(2) - (2)].val), &(yyval.param)->nval);
-             ;}
-    break;
-
-  case 69:
-#line 519 "parser.y"
-    { (yyval.val) = NULL; ;}
-    break;
-
-  case 70:
-#line 520 "parser.y"
-    { (yyval.val) = (yyvsp[(1) - (1)].val);   ;}
-    break;
-
-  case 71:
-#line 521 "parser.y"
-    { (yyval.val) = (yyvsp[(2) - (3)].val);   ;}
-    break;
-
-  case 72:
-#line 525 "parser.y"
-    { (yyval.val) = (yyvsp[(1) - (1)].val); ;}
-    break;
-
-  case 73:
-#line 527 "parser.y"
-    { (yyvsp[(2) - (2)].val)->next = (yyvsp[(1) - (2)].val); (yyval.val) = (yyvsp[(2) - (2)].val); ;}
-    break;
-
-  case 74:
-#line 529 "parser.y"
-    { (yyvsp[(3) - (3)].val)->next = (yyvsp[(1) - (3)].val); (yyval.val) = (yyvsp[(3) - (3)].val); ;}
-    break;
-
-  case 75:
-#line 533 "parser.y"
-    { (yyval.val) = (yyvsp[(1) - (1)].val); ;}
-    break;
-
-  case 76:
-#line 534 "parser.y"
-    { (yyval.val) = (yyvsp[(2) - (3)].val); ;}
-    break;
-
-  case 77:
-#line 538 "parser.y"
-    { (yyval.val) = (yyvsp[(1) - (1)].val); ;}
-    break;
-
-  case 78:
-#line 540 "parser.y"
-    { (yyvsp[(2) - (2)].val)->next = (yyvsp[(1) - (2)].val); (yyval.val) = (yyvsp[(2) - (2)].val); ;}
-    break;
-
-  case 79:
-#line 542 "parser.y"
-    { (yyvsp[(3) - (3)].val)->next = (yyvsp[(1) - (3)].val); (yyval.val) = (yyvsp[(3) - (3)].val); ;}
-    break;
-
-  case 80:
-#line 546 "parser.y"
-    { (yyval.val) = _gmx_selexpr_create_value_expr((yyvsp[(1) - (1)].sel)); ;}
-    break;
-
-  case 81:
-#line 548 "parser.y"
-    { (yyval.val) = _gmx_selexpr_create_value_expr((yyvsp[(1) - (1)].sel)); ;}
-    break;
-
-  case 82:
-#line 550 "parser.y"
-    { (yyval.val) = _gmx_selexpr_create_value_expr((yyvsp[(1) - (1)].sel)); ;}
-    break;
-
-  case 83:
-#line 552 "parser.y"
-    { (yyval.val) = _gmx_selexpr_create_value_expr((yyvsp[(1) - (1)].sel)); ;}
-    break;
-
-  case 84:
-#line 553 "parser.y"
-    { (yyval.val) = (yyvsp[(1) - (1)].val); ;}
-    break;
-
-  case 85:
-#line 558 "parser.y"
-    {
-                 (yyval.val) = _gmx_selexpr_create_value(INT_VALUE);
-                 (yyval.val)->u.i.i1 = (yyval.val)->u.i.i2 = (yyvsp[(1) - (1)].r);
-             ;}
-    break;
-
-  case 86:
-#line 563 "parser.y"
-    {
-                 (yyval.val) = _gmx_selexpr_create_value(REAL_VALUE);
-                 (yyval.val)->u.r.r1 = (yyval.val)->u.r.r2 = (yyvsp[(1) - (1)].r);
-             ;}
-    break;
-
-  case 87:
-#line 568 "parser.y"
-    {
-                 (yyval.val) = _gmx_selexpr_create_value(STR_VALUE);
-                 (yyval.val)->u.s = (yyvsp[(1) - (1)].str);
-             ;}
-    break;
-
-  case 88:
-#line 572 "parser.y"
-    { (yyval.val) = (yyvsp[(1) - (1)].val); ;}
-    break;
-
-  case 89:
-#line 577 "parser.y"
-    {
-                 (yyval.val) = _gmx_selexpr_create_value(INT_VALUE);
-                 (yyval.val)->u.i.i1 = (yyvsp[(1) - (3)].r); (yyval.val)->u.i.i2 = (yyvsp[(3) - (3)].r);
-             ;}
-    break;
-
-  case 90:
-#line 582 "parser.y"
-    {
-                 (yyval.val) = _gmx_selexpr_create_value(REAL_VALUE);
-                 (yyval.val)->u.r.r1 = (yyvsp[(1) - (3)].r); (yyval.val)->u.r.r2 = (yyvsp[(3) - (3)].r);
-             ;}
-    break;
-
-  case 91:
-#line 587 "parser.y"
-    {
-                 (yyval.val) = _gmx_selexpr_create_value(REAL_VALUE);
-                 (yyval.val)->u.r.r1 = (yyvsp[(1) - (3)].r); (yyval.val)->u.r.r2 = (yyvsp[(3) - (3)].r);
-             ;}
-    break;
-
-
-/* Line 1267 of yacc.c.  */
-#line 2309 "parser.c"
-      default: break;
-    }
-  YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
-
-  YYPOPSTACK (yylen);
-  yylen = 0;
-  YY_STACK_PRINT (yyss, yyssp);
-
-  *++yyvsp = yyval;
-
-
-  /* Now `shift' the result of the reduction.  Determine what state
-     that goes to, based on the state we popped back to and the rule
-     number reduced by.  */
-
-  yyn = yyr1[yyn];
-
-  yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
-  if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
-    yystate = yytable[yystate];
-  else
-    yystate = yydefgoto[yyn - YYNTOKENS];
-
-  goto yynewstate;
-
-
-/*------------------------------------.
-| yyerrlab -- here on detecting error |
-`------------------------------------*/
-yyerrlab:
-  /* If not already recovering from an error, report this error.  */
-  if (!yyerrstatus)
-    {
-      ++yynerrs;
-#if ! YYERROR_VERBOSE
-      yyerror (scanner, YY_("syntax error"));
-#else
-      {
-       YYSIZE_T yysize = yysyntax_error (0, yystate, yychar);
-       if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM)
-         {
-           YYSIZE_T yyalloc = 2 * yysize;
-           if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM))
-             yyalloc = YYSTACK_ALLOC_MAXIMUM;
-           if (yymsg != yymsgbuf)
-             YYSTACK_FREE (yymsg);
-           yymsg = (char *) YYSTACK_ALLOC (yyalloc);
-           if (yymsg)
-             yymsg_alloc = yyalloc;
-           else
-             {
-               yymsg = yymsgbuf;
-               yymsg_alloc = sizeof yymsgbuf;
-             }
-         }
-
-       if (0 < yysize && yysize <= yymsg_alloc)
-         {
-           (void) yysyntax_error (yymsg, yystate, yychar);
-           yyerror (scanner, yymsg);
-         }
-       else
-         {
-           yyerror (scanner, YY_("syntax error"));
-           if (yysize != 0)
-             goto yyexhaustedlab;
-         }
-      }
-#endif
-    }
-
-
-
-  if (yyerrstatus == 3)
-    {
-      /* If just tried and failed to reuse look-ahead token after an
-        error, discard it.  */
-
-      if (yychar <= YYEOF)
-       {
-         /* Return failure if at end of input.  */
-         if (yychar == YYEOF)
-           YYABORT;
-       }
-      else
-       {
-         yydestruct ("Error: discarding",
-                     yytoken, &yylval, scanner);
-         yychar = YYEMPTY;
-       }
-    }
-
-  /* Else will try to reuse look-ahead token after shifting the error
-     token.  */
-  goto yyerrlab1;
-
-
-/*---------------------------------------------------.
-| yyerrorlab -- error raised explicitly by YYERROR.  |
-`---------------------------------------------------*/
-yyerrorlab:
-
-  /* Pacify compilers like GCC when the user code never invokes
-     YYERROR and the label yyerrorlab therefore never appears in user
-     code.  */
-  if (/*CONSTCOND*/ 0)
-     goto yyerrorlab;
-
-  /* Do not reclaim the symbols of the rule which action triggered
-     this YYERROR.  */
-  YYPOPSTACK (yylen);
-  yylen = 0;
-  YY_STACK_PRINT (yyss, yyssp);
-  yystate = *yyssp;
-  goto yyerrlab1;
-
-
-/*-------------------------------------------------------------.
-| yyerrlab1 -- common code for both syntax error and YYERROR.  |
-`-------------------------------------------------------------*/
-yyerrlab1:
-  yyerrstatus = 3;     /* Each real token shifted decrements this.  */
-
-  for (;;)
-    {
-      yyn = yypact[yystate];
-      if (yyn != YYPACT_NINF)
-       {
-         yyn += YYTERROR;
-         if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
-           {
-             yyn = yytable[yyn];
-             if (0 < yyn)
-               break;
-           }
-       }
-
-      /* Pop the current state because it cannot handle the error token.  */
-      if (yyssp == yyss)
-       YYABORT;
-
-
-      yydestruct ("Error: popping",
-                 yystos[yystate], yyvsp, scanner);
-      YYPOPSTACK (1);
-      yystate = *yyssp;
-      YY_STACK_PRINT (yyss, yyssp);
-    }
-
-  if (yyn == YYFINAL)
-    YYACCEPT;
-
-  *++yyvsp = yylval;
-
-
-  /* Shift the error token.  */
-  YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
-
-  yystate = yyn;
-  goto yynewstate;
-
-
-/*-------------------------------------.
-| yyacceptlab -- YYACCEPT comes here.  |
-`-------------------------------------*/
-yyacceptlab:
-  yyresult = 0;
-  goto yyreturn;
-
-/*-----------------------------------.
-| yyabortlab -- YYABORT comes here.  |
-`-----------------------------------*/
-yyabortlab:
-  yyresult = 1;
-  goto yyreturn;
-
-#ifndef yyoverflow
-/*-------------------------------------------------.
-| yyexhaustedlab -- memory exhaustion comes here.  |
-`-------------------------------------------------*/
-yyexhaustedlab:
-  yyerror (scanner, YY_("memory exhausted"));
-  yyresult = 2;
-  /* Fall through.  */
-#endif
-
-yyreturn:
-  if (yychar != YYEOF && yychar != YYEMPTY)
-     yydestruct ("Cleanup: discarding lookahead",
-                yytoken, &yylval, scanner);
-  /* Do not reclaim the symbols of the rule which action triggered
-     this YYABORT or YYACCEPT.  */
-  YYPOPSTACK (yylen);
-  YY_STACK_PRINT (yyss, yyssp);
-  while (yyssp != yyss)
-    {
-      yydestruct ("Cleanup: popping",
-                 yystos[*yyssp], yyvsp, scanner);
-      YYPOPSTACK (1);
-    }
-#ifndef yyoverflow
-  if (yyss != yyssa)
-    YYSTACK_FREE (yyss);
-#endif
-#if YYERROR_VERBOSE
-  if (yymsg != yymsgbuf)
-    YYSTACK_FREE (yymsg);
-#endif
-  /* Make sure YYID is used.  */
-  return YYID (yyresult);
-}
-
-
-#line 593 "parser.y"
-
-
-static t_selexpr_value *
-process_value_list(t_selexpr_value *values, int *nr)
-{
-    t_selexpr_value *val, *pval, *nval;
-
-    /* Count values (if needed) and reverse list */
-    if (nr)
-    {
-        *nr  = 0;
-    }
-    pval = NULL;
-    val  = values;
-    while (val)
-    {
-        if (nr)
-        {
-            ++*nr;
-        }
-        nval = val->next;
-        val->next = pval;
-        pval = val;
-        val = nval;
-    }
-    values = pval;
-
-    return values;
-}
-
-static t_selexpr_param *
-process_param_list(t_selexpr_param *params)
-{
-    t_selexpr_param *par, *ppar, *npar;
-
-    /* Reverse list */
-    ppar = NULL;
-    par  = params;
-    while (par)
-    {
-        npar = par->next;
-        par->next = ppar;
-        ppar = par;
-        par = npar;
-    }
-    params = ppar;
-
-    return params;
-}
-
-static void
-yyerror(yyscan_t scanner, char const *s)
-{
-    _gmx_selparser_error("%s", s);
-}
-
-
-
diff --git a/src/gmxlib/selection/parser.h b/src/gmxlib/selection/parser.h
deleted file mode 100644 (file)
index e240cb3..0000000
+++ /dev/null
@@ -1,138 +0,0 @@
-/* A Bison parser, made by GNU Bison 2.3.  */
-
-/* Skeleton interface for Bison's Yacc-like parsers in C
-
-   Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
-   Free Software Foundation, Inc.
-
-   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, or (at your option)
-   any later version.
-
-   This program 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 General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301, USA.  */
-
-/* As a special exception, you may create a larger work that contains
-   part or all of the Bison parser skeleton and distribute that work
-   under terms of your choice, so long as that work isn't itself a
-   parser generator using the skeleton or a modified version thereof
-   as a parser skeleton.  Alternatively, if you modify or redistribute
-   the parser skeleton itself, you may (at your option) remove this
-   special exception, which will cause the skeleton and the resulting
-   Bison output files to be licensed under the GNU General Public
-   License without this special exception.
-
-   This special exception was added by the Free Software Foundation in
-   version 2.2 of Bison.  */
-
-/* Tokens.  */
-#ifndef YYTOKENTYPE
-# define YYTOKENTYPE
-   /* Put the tokens into the symbol table, so that GDB and other debuggers
-      know about them.  */
-   enum yytokentype {
-     INVALID = 258,
-     HELP = 259,
-     HELP_TOPIC = 260,
-     TOK_INT = 261,
-     TOK_REAL = 262,
-     STR = 263,
-     IDENTIFIER = 264,
-     CMD_SEP = 265,
-     GROUP = 266,
-     TO = 267,
-     VARIABLE_NUMERIC = 268,
-     VARIABLE_GROUP = 269,
-     VARIABLE_POS = 270,
-     KEYWORD_NUMERIC = 271,
-     KEYWORD_STR = 272,
-     KEYWORD_POS = 273,
-     KEYWORD_GROUP = 274,
-     METHOD_NUMERIC = 275,
-     METHOD_GROUP = 276,
-     METHOD_POS = 277,
-     MODIFIER = 278,
-     EMPTY_POSMOD = 279,
-     PARAM = 280,
-     END_OF_METHOD = 281,
-     OF = 282,
-     CMP_OP = 283,
-     PARAM_REDUCT = 284,
-     XOR = 285,
-     OR = 286,
-     AND = 287,
-     NOT = 288,
-     UNARY_NEG = 289,
-     NUM_REDUCT = 290
-   };
-#endif
-/* Tokens.  */
-#define INVALID 258
-#define HELP 259
-#define HELP_TOPIC 260
-#define TOK_INT 261
-#define TOK_REAL 262
-#define STR 263
-#define IDENTIFIER 264
-#define CMD_SEP 265
-#define GROUP 266
-#define TO 267
-#define VARIABLE_NUMERIC 268
-#define VARIABLE_GROUP 269
-#define VARIABLE_POS 270
-#define KEYWORD_NUMERIC 271
-#define KEYWORD_STR 272
-#define KEYWORD_POS 273
-#define KEYWORD_GROUP 274
-#define METHOD_NUMERIC 275
-#define METHOD_GROUP 276
-#define METHOD_POS 277
-#define MODIFIER 278
-#define EMPTY_POSMOD 279
-#define PARAM 280
-#define END_OF_METHOD 281
-#define OF 282
-#define CMP_OP 283
-#define PARAM_REDUCT 284
-#define XOR 285
-#define OR 286
-#define AND 287
-#define NOT 288
-#define UNARY_NEG 289
-#define NUM_REDUCT 290
-
-
-
-
-#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
-typedef union YYSTYPE
-#line 62 "parser.y"
-{
-    int                         i;
-    real                        r;
-    char                       *str;
-    struct gmx_ana_selmethod_t *meth;
-
-    struct t_selelem           *sel;
-
-    struct t_selexpr_value     *val;
-    struct t_selexpr_param     *param;
-}
-/* Line 1489 of yacc.c.  */
-#line 131 "parser.h"
-       YYSTYPE;
-# define yystype YYSTYPE /* obsolescent; will be withdrawn */
-# define YYSTYPE_IS_DECLARED 1
-# define YYSTYPE_IS_TRIVIAL 1
-#endif
-
-
-
diff --git a/src/gmxlib/selection/parser.y b/src/gmxlib/selection/parser.y
deleted file mode 100644 (file)
index 551e0cf..0000000
+++ /dev/null
@@ -1,649 +0,0 @@
-/*
- *
- *                This source code is part of
- *
- *                 G   R   O   M   A   C   S
- *
- *          GROningen MAchine for Chemical Simulations
- *
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
- * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
- * Copyright (c) 2001-2009, The GROMACS development team,
- * check out http://www.gromacs.org for more information.
-
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * If you want to redistribute modifications, please consider that
- * scientific software is very special. Version control is crucial -
- * bugs must be traceable. We will be happy to consider code for
- * inclusion in the official distribution, but derived work must not
- * be called official GROMACS. Details are found in the README & COPYING
- * files - if they are missing, get the official version at www.gromacs.org.
- *
- * To help us fund GROMACS development, we humbly ask that you cite
- * the papers on the package - you can find them in the top README file.
- *
- * For more info, check our website at http://www.gromacs.org
- */
-/*! \internal \file
- * \brief Grammar description and parser for the selection language.
- */
-%{
-/*! \internal \file parser.c
- * \brief Generated (from parser.y by Bison) parser for the selection language.
- */
-/*! \internal \file parser.h
- * \brief Generated (from parser.y by Bison) parser include file.
- */
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-
-#include <string2.h>
-
-#include "parsetree.h"
-#include "selelem.h"
-
-#include "scanner.h"
-
-static t_selexpr_value *
-process_value_list(t_selexpr_value *values, int *nr);
-static t_selexpr_param *
-process_param_list(t_selexpr_param *params);
-
-static void
-yyerror(yyscan_t, char const *s);
-%}
-
-%union{
-    int                         i;
-    real                        r;
-    char                       *str;
-    struct gmx_ana_selmethod_t *meth;
-
-    struct t_selelem           *sel;
-
-    struct t_selexpr_value     *val;
-    struct t_selexpr_param     *param;
-};
-/* NOTE: The Intel compiler seems to report warnings for the above line about
- * "definition at end of file not followed by a semicolon or a declarator".
- * This is due to the compiler misinterpreting #line directives in the
- * generated files parser.c/.h, and changing them would be more trouble than
- * it's worth. */
-
-/* Invalid token to report lexer errors */
-%token INVALID
-
-/* Tokens for help requests */
-%token         HELP
-%token <str>   HELP_TOPIC
-
-/* Simple input tokens */
-%token <i>     TOK_INT
-%token <r>     TOK_REAL
-%token <str>   STR
-%token <str>   IDENTIFIER
-%token         CMD_SEP
-
-/* Simple keyword tokens */
-%token         GROUP
-%token         TO
-
-/* Variable tokens */
-%token <sel>   VARIABLE_NUMERIC
-%token <sel>   VARIABLE_GROUP
-%token <sel>   VARIABLE_POS
-
-/* Selection method tokens */
-%token <meth>  KEYWORD_NUMERIC
-%token <meth>  KEYWORD_STR
-%token <str>   KEYWORD_POS
-%token <meth>  KEYWORD_GROUP
-%token <meth>  METHOD_NUMERIC
-%token <meth>  METHOD_GROUP
-%token <meth>  METHOD_POS
-%token <meth>  MODIFIER
-/* Empty token that should precede any non-position KEYWORD/METHOD token that
- * is not preceded by KEYWORD_POS. This is used to work around reduce/reduce
- * conflicts that appear when a lookahead token would require a reduction of
- * a rule with empty RHS before shifting, and there is an alternative reduction
- * available. Replacing the empty RHS with a dummy token makes these conflicts
- * only shift/reduce conflicts. Another alternative would be to remove the
- * pos_mod non-terminal completely and split each rule that uses it into two,
- * but this would require duplicating six rules in the grammar. */
-%token         EMPTY_POSMOD
-
-%token <str>   PARAM
-%token         END_OF_METHOD
-
-%token          OF
-/* Comparison operators have lower precedence than parameter reduction
- * to make it possible to parse, e.g., "mindist from resnr 1 < 2" without
- * parenthesis. */
-%nonassoc <str> CMP_OP
-/* A dummy token that determines the precedence of parameter reduction */
-%nonassoc       PARAM_REDUCT
-/* Boolean operator tokens */
-%left           OR XOR
-%left           AND
-%left           NOT
-/* Arithmetic operator tokens */
-%left           '+' '-'
-%left           '*' '/'
-%right          UNARY_NEG   /* Dummy token for unary negation precedence */
-%right          '^'
-%nonassoc       NUM_REDUCT  /* Dummy token for numerical keyword reduction precedence */
-
-/* Simple non-terminals */
-%type <r>     integer_number
-%type <r>     real_number number
-%type <str>   string
-%type <str>   pos_mod
-
-/* Expression non-terminals */
-%type <sel>   commands command cmd_plain
-%type <sel>   selection
-%type <sel>   sel_expr
-%type <sel>   num_expr
-%type <sel>   str_expr
-%type <sel>   pos_expr
-
-/* Parameter/value non-terminals */
-%type <param> method_params method_param_list method_param
-%type <val>   value_list value_list_contents value_item value_item_range
-%type <val>   basic_value_list basic_value_list_contents basic_value_item
-
-%destructor { free($$);                     } HELP_TOPIC STR IDENTIFIER CMP_OP string
-%destructor { if($$) free($$);              } PARAM
-%destructor { if($$) _gmx_selelem_free($$); } command cmd_plain
-%destructor { _gmx_selelem_free_chain($$);  } selection
-%destructor { _gmx_selelem_free($$);        } sel_expr num_expr str_expr pos_expr
-%destructor { _gmx_selexpr_free_params($$); } method_params method_param_list method_param
-%destructor { _gmx_selexpr_free_values($$); } value_list value_list_contents value_item value_item_range
-%destructor { _gmx_selexpr_free_values($$); } basic_value_list basic_value_list_contents basic_value_item
-
-%expect 50
-%debug
-%pure-parser
-
-/* If you change these, you also need to update the prototype in parsetree.c. */
-%name-prefix="_gmx_sel_yyb"
-%parse-param { yyscan_t                 scanner }
-%lex-param   { yyscan_t                 scanner }
-
-%%
-
-/* The start rule: allow one or more commands */
-commands:    /* empty */        { $$ = NULL }
-           | commands command
-             {
-                 $$ = _gmx_sel_append_selection($2, $1, scanner);
-                 if (_gmx_sel_parser_should_finish(scanner))
-                     YYACCEPT;
-             }
-;
-
-/* A command is formed from an actual command and a separator */
-command:     cmd_plain CMD_SEP  { $$ = $1; }
-           | error CMD_SEP
-             {
-                 $$ = NULL;
-                 _gmx_selparser_error("invalid selection '%s'",
-                                      _gmx_sel_lexer_pselstr(scanner));
-                 _gmx_sel_lexer_clear_method_stack(scanner);
-                 if (_gmx_sel_is_lexer_interactive(scanner))
-                 {
-                     _gmx_sel_lexer_clear_pselstr(scanner);
-                     yyerrok;
-                 }
-                 else
-                 {
-                     YYABORT;
-                 }
-             }
-;
-
-/* Commands can be selections or variable assignments */
-cmd_plain:   /* empty */
-             {
-                 $$ = NULL;
-                 _gmx_sel_handle_empty_cmd(scanner);
-             }
-           | help_request       { $$ = NULL; }
-           | TOK_INT
-             {
-                 t_selelem *s, *p;
-                 s = _gmx_sel_init_group_by_id($1, scanner);
-                 if (s == NULL) YYERROR;
-                 p = _gmx_sel_init_position(s, NULL, scanner);
-                 if (p == NULL) YYERROR;
-                 $$ = _gmx_sel_init_selection(strdup(s->name), p, scanner);
-             }
-           | string
-             {
-                 t_selelem *s, *p;
-                 s = _gmx_sel_init_group_by_name($1, scanner);
-                 free($1);
-                 if (s == NULL) YYERROR;
-                 p = _gmx_sel_init_position(s, NULL, scanner);
-                 if (p == NULL) YYERROR;
-                 $$ = _gmx_sel_init_selection(strdup(s->name), p, scanner);
-             }
-           | selection
-             { $$ = _gmx_sel_init_selection(NULL, $1, scanner); }
-           | string selection
-             { $$ = _gmx_sel_init_selection($1, $2, scanner);   }
-           | IDENTIFIER '=' sel_expr
-             { $$ = _gmx_sel_assign_variable($1, $3, scanner);  }
-           | IDENTIFIER '=' num_expr
-             { $$ = _gmx_sel_assign_variable($1, $3, scanner);  }
-           | IDENTIFIER '=' pos_expr
-             { $$ = _gmx_sel_assign_variable($1, $3, scanner);  }
-;
-
-/* Help requests */
-help_request:
-             HELP                   { _gmx_sel_handle_help_cmd(NULL, scanner); }
-           | help_topic
-;
-
-help_topic:  HELP HELP_TOPIC        { _gmx_sel_handle_help_cmd($2, scanner); }
-           | help_topic HELP_TOPIC  { _gmx_sel_handle_help_cmd($2, scanner); }
-;
-
-/* Selection is made of an expression and zero or more modifiers */
-selection:   pos_expr           { $$ = $1; }
-           | sel_expr
-             {
-                 $$ = _gmx_sel_init_position($1, NULL, scanner);
-                 if ($$ == NULL) YYERROR;
-             }
-           | '(' selection ')'  { $$ = $2; }
-           | selection MODIFIER method_params
-             {
-                 $$ = _gmx_sel_init_modifier($2, $3, $1, scanner);
-                 if ($$ == NULL) YYERROR;
-             }
-;
-
-/********************************************************************
- * BASIC NON-TERMINAL SYMBOLS
- ********************************************************************/
-
-integer_number:
-             TOK_INT            { $$ = $1; }
-           | '-' TOK_INT        { $$ = -$2; }
-;
-
-real_number:
-             TOK_REAL           { $$ = $1; }
-           | '-' TOK_REAL       { $$ = -$2; }
-;
-
-number:      integer_number     { $$ = $1; }
-           | real_number        { $$ = $1; }
-;
-
-string:      STR                { $$ = $1; }
-           | IDENTIFIER         { $$ = $1; }
-;
-
-/********************************************************************
- * ATOM SELECTION EXPRESSIONS
- ********************************************************************/
-
-/* Boolean expressions and grouping */
-sel_expr:    NOT sel_expr
-             {
-                 $$ = _gmx_selelem_create(SEL_BOOLEAN);
-                 $$->u.boolt = BOOL_NOT;
-                 $$->child = $2;
-             }
-           | sel_expr AND sel_expr
-             {
-                 $$ = _gmx_selelem_create(SEL_BOOLEAN);
-                 $$->u.boolt = BOOL_AND;
-                 $$->child = $1; $$->child->next = $3;
-             }
-           | sel_expr OR  sel_expr
-             {
-                 $$ = _gmx_selelem_create(SEL_BOOLEAN);
-                 $$->u.boolt = BOOL_OR;
-                 $$->child = $1; $$->child->next = $3;
-             }
-/*           | sel_expr XOR sel_expr
-             {
-                 $$ = _gmx_selelem_create(SEL_BOOLEAN);
-                 $$->u.boolt = BOOL_XOR;
-                 $$->child = $1; $$->child->next = $3;
-             }*/
-           | '(' sel_expr ')'   { $$ = $2; }
-;
-
-/* Numeric comparisons */
-sel_expr:    num_expr CMP_OP num_expr
-             {
-                 $$ = _gmx_sel_init_comparison($1, $3, $2, scanner);
-                 if ($$ == NULL) YYERROR;
-             }
-;
-
-/* External groups */
-sel_expr:    GROUP string
-             {
-                 $$ = _gmx_sel_init_group_by_name($2, scanner);
-                 free($2);
-                 if ($$ == NULL) YYERROR;
-             }
-           | GROUP TOK_INT
-             {
-                 $$ = _gmx_sel_init_group_by_id($2, scanner);
-                 if ($$ == NULL) YYERROR;
-             }
-;
-
-/* Position modifiers for selection methods */
-pos_mod:     EMPTY_POSMOD       { $$ = NULL; }
-           | KEYWORD_POS        { $$ = $1;   }
-;
-
-/* Keyword selections */
-sel_expr:    pos_mod KEYWORD_GROUP
-             {
-                 $$ = _gmx_sel_init_keyword($2, NULL, $1, scanner);
-                 if ($$ == NULL) YYERROR;
-             }
-           | pos_mod KEYWORD_STR basic_value_list
-             {
-                 $$ = _gmx_sel_init_keyword($2, process_value_list($3, NULL), $1, scanner);
-                 if ($$ == NULL) YYERROR;
-             }
-           | pos_mod KEYWORD_NUMERIC basic_value_list
-             {
-                 $$ = _gmx_sel_init_keyword($2, process_value_list($3, NULL), $1, scanner);
-                 if ($$ == NULL) YYERROR;
-             }
-;
-
-/* Custom selection methods */
-sel_expr:    pos_mod METHOD_GROUP method_params
-             {
-                 $$ = _gmx_sel_init_method($2, $3, $1, scanner);
-                 if ($$ == NULL) YYERROR;
-             }
-;
-
-/********************************************************************
- * NUMERICAL EXPRESSIONS
- ********************************************************************/
-
-/* Basic numerical values */
-num_expr:    TOK_INT
-             {
-                 $$ = _gmx_selelem_create(SEL_CONST);
-                 _gmx_selelem_set_vtype($$, INT_VALUE);
-                 _gmx_selvalue_reserve(&$$->v, 1);
-                 $$->v.u.i[0] = $1;
-             }
-           | TOK_REAL
-             {
-                 $$ = _gmx_selelem_create(SEL_CONST);
-                 _gmx_selelem_set_vtype($$, REAL_VALUE);
-                 _gmx_selvalue_reserve(&$$->v, 1);
-                 $$->v.u.r[0] = $1;
-             }
-;
-
-/* Numeric selection methods */
-num_expr:    pos_mod KEYWORD_NUMERIC    %prec NUM_REDUCT
-             {
-                 $$ = _gmx_sel_init_keyword($2, NULL, $1, scanner);
-                 if ($$ == NULL) YYERROR;
-             }
-           | pos_mod METHOD_NUMERIC method_params
-             {
-                 $$ = _gmx_sel_init_method($2, $3, $1, scanner);
-                 if ($$ == NULL) YYERROR;
-             }
-;
-
-/* Arithmetic evaluation and grouping */
-num_expr:    num_expr '+' num_expr
-             { $$ = _gmx_sel_init_arithmetic($1, $3, '+', scanner); }
-           | num_expr '-' num_expr
-             { $$ = _gmx_sel_init_arithmetic($1, $3, '-', scanner); }
-           | num_expr '*' num_expr
-             { $$ = _gmx_sel_init_arithmetic($1, $3, '*', scanner); }
-           | num_expr '/' num_expr
-             { $$ = _gmx_sel_init_arithmetic($1, $3, '/', scanner); }
-           | '-' num_expr %prec UNARY_NEG
-             { $$ = _gmx_sel_init_arithmetic($2, NULL, '-', scanner); }
-           | num_expr '^' num_expr
-             { $$ = _gmx_sel_init_arithmetic($1, $3, '^', scanner); }
-           | '(' num_expr ')'   { $$ = $2; }
-;
-
-/********************************************************************
- * STRING EXPRESSIONS
- ********************************************************************/
-
-str_expr:    string
-             {
-                 $$ = _gmx_selelem_create(SEL_CONST);
-                 _gmx_selelem_set_vtype($$, STR_VALUE);
-                 _gmx_selvalue_reserve(&$$->v, 1);
-                 $$->v.u.s[0] = $1;
-             }
-           | pos_mod KEYWORD_STR
-             {
-                 $$ = _gmx_sel_init_keyword($2, NULL, $1, scanner);
-                 if ($$ == NULL) YYERROR;
-             }
-;
-
-/********************************************************************
- * POSITION EXPRESSIONS
- ********************************************************************/
-
-/* Constant position expressions */
-pos_expr:    '[' number ',' number ',' number ']'
-             { $$ = _gmx_sel_init_const_position($2, $4, $6); }
-;
-
-/* Grouping of position expressions */
-pos_expr:    '(' pos_expr ')'   { $$ = $2; }
-;
-
-/* Expressions with a position value */
-pos_expr:    METHOD_POS method_params
-             {
-                 $$ = _gmx_sel_init_method($1, $2, NULL, scanner);
-                 if ($$ == NULL) YYERROR;
-             }
-;
-
-/* Evaluation of positions using a keyword */
-pos_expr:    KEYWORD_POS OF sel_expr    %prec PARAM_REDUCT
-             {
-                 $$ = _gmx_sel_init_position($3, $1, scanner);
-                 if ($$ == NULL) YYERROR;
-             }
-;
-
-/********************************************************************
- * VARIABLES
- ********************************************************************/
-
-sel_expr:    VARIABLE_GROUP
-             { $$ = _gmx_sel_init_variable_ref($1); }
-;
-
-num_expr:    VARIABLE_NUMERIC
-             { $$ = _gmx_sel_init_variable_ref($1); }
-;
-
-pos_expr:    VARIABLE_POS
-             { $$ = _gmx_sel_init_variable_ref($1); }
-;
-
-/********************************************************************
- * METHOD PARAMETERS
- ********************************************************************/
-
-method_params:
-             method_param_list
-             { $$ = process_param_list($1); }
-           | method_param_list END_OF_METHOD
-             { $$ = process_param_list($1); }
-;
-
-method_param_list:
-             /* empty */        { $$ = NULL;              }
-           | method_param_list method_param
-                                { $2->next = $1; $$ = $2; }
-;
-
-method_param:
-             PARAM value_list
-             {
-                 $$ = _gmx_selexpr_create_param($1);
-                 $$->value = process_value_list($2, &$$->nval);
-             }
-;
-
-value_list:  /* empty */                         { $$ = NULL; }
-           | value_list_contents                 { $$ = $1;   }
-           | '{' value_list_contents '}'         { $$ = $2;   }
-;
-
-value_list_contents:
-             value_item          { $$ = $1; }
-           | value_list_contents value_item
-                                 { $2->next = $1; $$ = $2; }
-           | value_list_contents ',' value_item
-                                 { $3->next = $1; $$ = $3; }
-;
-
-basic_value_list:
-             basic_value_list_contents           { $$ = $1; }
-           | '{' basic_value_list_contents '}'   { $$ = $2; }
-;
-
-basic_value_list_contents:
-             basic_value_item    { $$ = $1; }
-           | basic_value_list_contents basic_value_item
-                                 { $2->next = $1; $$ = $2; }
-           | basic_value_list_contents ',' basic_value_item
-                                 { $3->next = $1; $$ = $3; }
-;
-
-value_item:  sel_expr            %prec PARAM_REDUCT
-             { $$ = _gmx_selexpr_create_value_expr($1); }
-           | pos_expr            %prec PARAM_REDUCT
-             { $$ = _gmx_selexpr_create_value_expr($1); }
-           | num_expr            %prec PARAM_REDUCT
-             { $$ = _gmx_selexpr_create_value_expr($1); }
-           | str_expr            %prec PARAM_REDUCT
-             { $$ = _gmx_selexpr_create_value_expr($1); }
-           | value_item_range    { $$ = $1; }
-;
-
-basic_value_item:
-             integer_number      %prec PARAM_REDUCT
-             {
-                 $$ = _gmx_selexpr_create_value(INT_VALUE);
-                 $$->u.i.i1 = $$->u.i.i2 = $1;
-             }
-           | real_number         %prec PARAM_REDUCT
-             {
-                 $$ = _gmx_selexpr_create_value(REAL_VALUE);
-                 $$->u.r.r1 = $$->u.r.r2 = $1;
-             }
-           | string              %prec PARAM_REDUCT
-             {
-                 $$ = _gmx_selexpr_create_value(STR_VALUE);
-                 $$->u.s = $1;
-             }
-           | value_item_range    { $$ = $1; }
-;
-
-value_item_range:
-             integer_number TO integer_number
-             {
-                 $$ = _gmx_selexpr_create_value(INT_VALUE);
-                 $$->u.i.i1 = $1; $$->u.i.i2 = $3;
-             }
-           | integer_number TO real_number
-             {
-                 $$ = _gmx_selexpr_create_value(REAL_VALUE);
-                 $$->u.r.r1 = $1; $$->u.r.r2 = $3;
-             }
-           | real_number TO number
-             {
-                 $$ = _gmx_selexpr_create_value(REAL_VALUE);
-                 $$->u.r.r1 = $1; $$->u.r.r2 = $3;
-             }
-;
-
-%%
-
-static t_selexpr_value *
-process_value_list(t_selexpr_value *values, int *nr)
-{
-    t_selexpr_value *val, *pval, *nval;
-
-    /* Count values (if needed) and reverse list */
-    if (nr)
-    {
-        *nr  = 0;
-    }
-    pval = NULL;
-    val  = values;
-    while (val)
-    {
-        if (nr)
-        {
-            ++*nr;
-        }
-        nval = val->next;
-        val->next = pval;
-        pval = val;
-        val = nval;
-    }
-    values = pval;
-
-    return values;
-}
-
-static t_selexpr_param *
-process_param_list(t_selexpr_param *params)
-{
-    t_selexpr_param *par, *ppar, *npar;
-
-    /* Reverse list */
-    ppar = NULL;
-    par  = params;
-    while (par)
-    {
-        npar = par->next;
-        par->next = ppar;
-        ppar = par;
-        par = npar;
-    }
-    params = ppar;
-
-    return params;
-}
-
-static void
-yyerror(yyscan_t scanner, char const *s)
-{
-    _gmx_selparser_error("%s", s);
-}
-
-
diff --git a/src/gmxlib/selection/parsetree.c b/src/gmxlib/selection/parsetree.c
deleted file mode 100644 (file)
index 2da5106..0000000
+++ /dev/null
@@ -1,1510 +0,0 @@
-/*
- *
- *                This source code is part of
- *
- *                 G   R   O   M   A   C   S
- *
- *          GROningen MAchine for Chemical Simulations
- *
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
- * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
- * Copyright (c) 2001-2009, The GROMACS development team,
- * check out http://www.gromacs.org for more information.
-
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * If you want to redistribute modifications, please consider that
- * scientific software is very special. Version control is crucial -
- * bugs must be traceable. We will be happy to consider code for
- * inclusion in the official distribution, but derived work must not
- * be called official GROMACS. Details are found in the README & COPYING
- * files - if they are missing, get the official version at www.gromacs.org.
- *
- * To help us fund GROMACS development, we humbly ask that you cite
- * the papers on the package - you can find them in the top README file.
- *
- * For more info, check our website at http://www.gromacs.org
- */
-/*! \internal \file
- * \brief Implementation of functions of in parsetree.h.
- */
-/*! \internal
- * \page selparser Selection parsing
- *
- * The selection parser is implemented in the following files:
- *  - scanner.l:
- *    Tokenizer implemented using Flex, splits the input into tokens
- *    (scanner.c and scanner_flex.h are generated from this file).
- *  - scanner.h, scanner_internal.h, scanner_internal.c:
- *    Helper functions for scanner.l and for interfacing between
- *    scanner.l and parser.y. Functions in scanner_internal.h are only
- *    used from scanner.l, while scanner.h is used from the parser.
- *  - symrec.h, symrec.c:
- *    Functions used by the tokenizer to handle the symbol table, i.e.,
- *    the recognized keywords. Some basic keywords are hardcoded into
- *    scanner.l, but all method and variable references go through the
- *    symbol table, as do position evaluation keywords.
- *  - parser.y:
- *    Semantic rules for parsing the grammar
- *    (parser.c and parser.h are generated from this file by Bison).
- *  - parsetree.h, parsetree.c:
- *    Functions called from actions in parser.y to construct the
- *    evaluation elements corresponding to different grammar elements.
- *    parsetree.c also defines the external interface of the parser,
- *    i.e., the \c gmx_ana_selcollection_parse_*() functions declared
- *    in selection.h.
- *  - params.c:
- *    Defines a function that processes the parameters of selection
- *    methods and initializes the children of the method element.
- *
- * The basic control flow in the parser is as follows: when a
- * fmx_ana_selcollection_parse_*() gets called, it performs some
- * initialization, and then calls the _gmx_sel_yyparse() function generated
- * by Bison. This function then calls _gmx_sel_yylex() to repeatedly read
- * tokens from the input (more complex tasks related to token recognition
- * and bookkeeping are done by functions in scanner_internal.c) and uses the
- * grammar rules to decide what to do with them. Whenever a grammar rule
- * matches, a corresponding function in parsetree.c is called to construct
- * either a temporary representation for the object or a \c t_selelem object
- * (some simple rules are handled internally in parser.y).
- * When a complete selection has been parsed, the functions in parsetree.c
- * also take care of updating the \c gmx_ana_selcollection_t structure
- * appropriately.
- *
- * The rest of this page describes the resulting \c t_selelem object tree.
- * Before the selections can be evaluated, this tree needs to be passed to
- * the selection compiler, which is described on a separate page:
- * \ref selcompiler
- *
- *
- * \section selparser_tree Element tree constructed by the parser
- *
- * The parser initializes the following fields in all selection elements:
- * \c t_selelem::name, \c t_selelem::type, \c t_selelem::v\c .type,
- * \c t_selelem::flags, \c t_selelem::child, \c t_selelem::next, and
- * \c t_selelem::refcount.
- * Some other fields are also initialized for particular element types as
- * discussed below.
- * Fields that are not initialized are set to zero, NULL, or other similar
- * value.
- *
- *
- * \subsection selparser_tree_root Root elements
- *
- * The parser creates a \ref SEL_ROOT selection element for each variable
- * assignment and each selection. However, there are two exceptions that do
- * not result in a \ref SEL_ROOT element (in these cases, only the symbol
- * table is modified):
- *  - Variable assignments that assign a variable to another variable.
- *  - Variable assignments that assign a non-group constant.
- *  .
- * The \ref SEL_ROOT elements are linked together in a chain in the same order
- * as in the input.
- *
- * The children of the \ref SEL_ROOT elements can be used to distinguish
- * the two types of root elements from each other:
- *  - For variable assignments, the first and only child is always
- *    a \ref SEL_SUBEXPR element.
- *  - For selections, the first child is a \ref SEL_EXPRESSION or a
- *    \ref SEL_MODIFIER element that evaluates the final positions (if the
- *    selection defines a constant position, the child is a \ref SEL_CONST).
- *    The rest of the children are \ref SEL_MODIFIER elements with
- *    \ref NO_VALUE, in the order given by the user.
- *  .
- * The name of the selection/variable is stored in \c t_selelem::cgrp\c .name.
- * It is set to either the name provided by the user or the selection string
- * for selections not explicitly named by the user.
- * \ref SEL_ROOT or \ref SEL_SUBEXPR elements do not appear anywhere else.
- *
- *
- * \subsection selparser_tree_const Constant elements
- *
- * \ref SEL_CONST elements are created for every constant that is required
- * for later evaluation.
- * Currently, \ref SEL_CONST elements can be present for
- *  - selections that consist of a constant position,
- *  - \ref GROUP_VALUE method parameters if provided using external index
- *    groups,
- *  .
- * For group-valued elements, the value is stored in \c t_selelem::cgrp;
- * other types of values are stored in \c t_selelem::v.
- * Constants that appear as parameters for selection methods are not present
- * in the selection tree unless they have \ref GROUP_VALUE.
- * \ref SEL_CONST elements have no children.
- *
- *
- * \subsection selparser_tree_method Method evaluation elements
- *
- * \ref SEL_EXPRESSION and \ref SEL_MODIFIER elements are treated very
- * similarly. The \c gmx_ana_selmethod_t structure corresponding to the
- * evaluation method is in \c t_selelem::method, and the method data in
- * \c t_selelem::mdata has been allocated using sel_datafunc().
- * If a non-standard reference position type was set, \c t_selelem::pc has
- * also been created, but only the type has been set.
- * All children of these elements are of the type \ref SEL_SUBEXPRREF, and
- * each describes a selection that needs to be evaluated to obtain a value
- * for one parameter of the method.
- * No children are present for parameters that were given a constant
- * non-\ref GROUP_VALUE value.
- * The children are sorted in the order in which the parameters appear in the
- * \ref gmx_ana_selmethod_t structure.
- *
- * In addition to actual selection keywords, \ref SEL_EXPRESSION elements
- * are used internally to implement numerical comparisons (e.g., "x < 5")
- * and keyword matching (e.g., "resnr 1 to 3" or "name CA").
- *
- *
- * \subsection selparser_tree_subexpr Subexpression elements
- *
- * \ref SEL_SUBEXPR elements only appear for variables, as described above.
- * \c t_selelem::name points to the name of the variable (from the
- * \ref SEL_ROOT element).
- * The element always has exactly one child, which represents the value of
- * the variable.
- * \ref SEL_SUBEXPR element is the only element type that can have
- * \c t_selelem::refcount different from 1.
- *
- * \ref SEL_SUBEXPRREF elements are used for two purposes:
- *  - Variable references that need to be evaluated (i.e., there is a
- *    \ref SEL_SUBEXPR element for the variable) are represented using
- *    \ref SEL_SUBEXPRREF elements.
- *    In this case, \c t_selelem::param is NULL, and the first and only
- *    child of the element is the \ref SEL_SUBEXPR element of the variable.
- *    Such references can appear anywhere where the variable value
- *    (the child of the \ref SEL_SUBEXPR element) would be valid.
- *  - Children of \ref SEL_EXPRESSION and \ref SEL_MODIFIER elements are
- *    always of this type. For these elements, \c t_selelem::param is
- *    initialized to point to the parameter that receives the value from
- *    the expression.
- *    Each such element has exactly one child, which can be of any type;
- *    the \ref SEL_SUBEXPR element of a variable is used if the value comes
- *    from a variable, otherwise the child type is not \ref SEL_SUBEXPR.
- *
- *
- * \subsection selparser_tree_gmx_bool Boolean elements
- *
- * One \ref SEL_BOOLEAN element is created for each gmx_boolean keyword in the
- * input, and the tree structure represents the evaluation order.
- * The \c t_selelem::boolt type gives the type of the operation.
- * Each element has exactly two children (one for \ref BOOL_NOT elements),
- * which are in the order given in the input.
- * The children always have \ref GROUP_VALUE, but different element types
- * are possible.
- *
- *
- * \subsection selparser_tree_arith Arithmetic elements
- *
- * One \ref SEL_ARITHMETIC element is created for each arithmetic operation in
- * the input, and the tree structure represents the evaluation order.
- * The \c t_selelem::optype type gives the name of the operation.
- * Each element has exactly two children (one for unary negation elements),
- * which are in the order given in the input.
- */
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdio.h>
-#include <stdarg.h>
-
-#include <futil.h>
-#include <smalloc.h>
-#include <string2.h>
-#include <gmx_fatal.h>
-
-#include <poscalc.h>
-#include <selection.h>
-#include <selmethod.h>
-
-#include "keywords.h"
-#include "parsetree.h"
-#include "selcollection.h"
-#include "selelem.h"
-#include "selhelp.h"
-#include "symrec.h"
-
-#include "scanner.h"
-
-/* In parser.y */
-/*! \brief
- * Parser function generated by Bison.
- */
-int
-_gmx_sel_yybparse(void *scanner);
-
-/*!
- * It is a simple wrapper for fprintf(stderr, ...).
- */
-void
-_gmx_selparser_error(const char *fmt, ...)
-{
-    va_list ap;
-    va_start(ap, fmt);
-    fprintf(stderr, "selection parser: ");
-    vfprintf(stderr, fmt, ap);
-    fprintf(stderr, "\n");
-    va_end(ap);
-}
-
-/*!
- * \param[in] type  Type for the new value.
- * \returns   Pointer to the newly allocated value.
- */
-t_selexpr_value *
-_gmx_selexpr_create_value(e_selvalue_t type)
-{
-    t_selexpr_value *value;
-    snew(value, 1);
-    value->type  = type;
-    value->bExpr = FALSE;
-    value->next  = NULL;
-    return value;
-}
-
-/*!
- * \param[in] expr  Expression for the value.
- * \returns   Pointer to the newly allocated value.
- */
-t_selexpr_value *
-_gmx_selexpr_create_value_expr(t_selelem *expr)
-{
-    t_selexpr_value *value;
-    snew(value, 1);
-    value->type   = expr->v.type;
-    value->bExpr  = TRUE;
-    value->u.expr = expr;
-    value->next   = NULL;
-    return value;
-}
-
-/*!
- * \param[in] name Name for the new parameter.
- * \returns   Pointer to the newly allocated parameter.
- *
- * No copy of \p name is made.
- */
-t_selexpr_param *
-_gmx_selexpr_create_param(char *name)
-{
-    t_selexpr_param *param;
-    snew(param, 1);
-    param->name = name;
-    param->next = NULL;
-    return param;
-}
-
-/*!
- * \param value Pointer to the beginning of the value list to free.
- *
- * The expressions referenced by the values are also freed
- * (to prevent this, set the expression to NULL before calling the function).
- */
-void
-_gmx_selexpr_free_values(t_selexpr_value *value)
-{
-    t_selexpr_value *old;
-
-    while (value)
-    {
-        if (value->bExpr)
-        {
-            if (value->u.expr)
-            {
-                _gmx_selelem_free(value->u.expr);
-            }
-        }
-        else if (value->type == STR_VALUE)
-        {
-            sfree(value->u.s);
-        }
-        old = value;
-        value = value->next;
-        sfree(old);
-    }
-}
-
-/*!
- * \param param Pointer the the beginning of the parameter list to free.
- *
- * The values of the parameters are freed with free_selexpr_values().
- */
-void
-_gmx_selexpr_free_params(t_selexpr_param *param)
-{
-    t_selexpr_param *old;
-
-    while (param)
-    {
-        _gmx_selexpr_free_values(param->value);
-        old = param;
-        param = param->next;
-        sfree(old->name);
-        sfree(old);
-    }
-}
-
-/*!
- * \param[in,out] sel  Root of the selection element tree to initialize.
- * \returns       0 on success, an error code on error.
- *
- * Propagates the \ref SEL_DYNAMIC flag from the children of \p sel to \p sel
- * (if any child of \p sel is dynamic, \p sel is also marked as such).
- * The \ref SEL_DYNAMIC flag is also set for \ref SEL_EXPRESSION elements with
- * a dynamic method.
- * Also, sets one of the \ref SEL_SINGLEVAL, \ref SEL_ATOMVAL, or
- * \ref SEL_VARNUMVAL flags, either based on the children or on the type of
- * the selection method.
- * If the types of the children conflict, an error is returned.
- *
- * The flags of the children of \p sel are also updated if not done earlier.
- * The flags are initialized only once for any element; if \ref SEL_FLAGSSET
- * is set for an element, the function returns immediately, and the recursive
- * operation does not descend beyond such elements.
- */
-int
-_gmx_selelem_update_flags(t_selelem *sel)
-{
-    t_selelem          *child;
-    int                 rc;
-    gmx_bool                bUseChildType=FALSE;
-    gmx_bool                bOnlySingleChildren;
-
-    /* Return if the flags have already been set */
-    if (sel->flags & SEL_FLAGSSET)
-    {
-        return 0;
-    }
-    /* Set the flags based on the current element type */
-    switch (sel->type)
-    {
-        case SEL_CONST:
-            sel->flags |= SEL_SINGLEVAL;
-            bUseChildType = FALSE;
-            break;
-
-        case SEL_EXPRESSION:
-            if (sel->u.expr.method->flags & SMETH_DYNAMIC)
-            {
-                sel->flags |= SEL_DYNAMIC;
-            }
-            if (sel->u.expr.method->flags & SMETH_SINGLEVAL)
-            {
-                sel->flags |= SEL_SINGLEVAL;
-            }
-            else if (sel->u.expr.method->flags & SMETH_VARNUMVAL)
-            {
-                sel->flags |= SEL_VARNUMVAL;
-            }
-            else
-            {
-                sel->flags |= SEL_ATOMVAL;
-            }
-            bUseChildType = FALSE;
-            break;
-
-        case SEL_ARITHMETIC:
-            sel->flags |= SEL_ATOMVAL;
-            bUseChildType = FALSE;
-            break;
-
-        case SEL_MODIFIER:
-            if (sel->v.type != NO_VALUE)
-            {
-                sel->flags |= SEL_VARNUMVAL;
-            }
-            bUseChildType = FALSE;
-            break;
-
-        case SEL_ROOT:
-            bUseChildType = FALSE;
-            break;
-
-        case SEL_BOOLEAN:
-        case SEL_SUBEXPR:
-        case SEL_SUBEXPRREF:
-            bUseChildType = TRUE;
-            break;
-    }
-    /* Loop through children to propagate their flags upwards */
-    bOnlySingleChildren = TRUE;
-    child = sel->child;
-    while (child)
-    {
-        /* Update the child */
-        rc = _gmx_selelem_update_flags(child);
-        if (rc != 0)
-        {
-            return rc;
-        }
-        /* Propagate the dynamic flag */
-        sel->flags |= (child->flags & SEL_DYNAMIC);
-        /* Propagate the type flag if necessary and check for problems */
-        if (bUseChildType)
-        {
-            if ((sel->flags & SEL_VALTYPEMASK)
-                && !(sel->flags & child->flags & SEL_VALTYPEMASK))
-            {
-                _gmx_selparser_error("invalid combination of selection expressions");
-                return EINVAL;
-            }
-            sel->flags |= (child->flags & SEL_VALTYPEMASK);
-        }
-        if (!(child->flags & SEL_SINGLEVAL))
-        {
-            bOnlySingleChildren = FALSE;
-        }
-
-        child = child->next;
-    }
-    /* For arithmetic expressions consisting only of single values,
-     * the result is also a single value. */
-    if (sel->type == SEL_ARITHMETIC && bOnlySingleChildren)
-    {
-        sel->flags = (sel->flags & ~SEL_VALTYPEMASK) | SEL_SINGLEVAL;
-    }
-    /* For root elements, the type should be propagated here, after the
-     * children have been updated. */
-    if (sel->type == SEL_ROOT)
-    {
-        sel->flags |= (sel->child->flags & SEL_VALTYPEMASK);
-    }
-    /* Mark that the flags are set */
-    sel->flags |= SEL_FLAGSSET;
-    return 0;
-}
-
-/*!
- * \param[in,out] sel    Selection element to initialize.
- * \param[in]     scanner Scanner data structure.
- *
- * A deep copy of the parameters is made to allow several
- * expressions with the same method to coexist peacefully.
- * Calls sel_datafunc() if one is specified for the method.
- */
-void
-_gmx_selelem_init_method_params(t_selelem *sel, yyscan_t scanner)
-{
-    int                 nparams;
-    gmx_ana_selparam_t *orgparam;
-    gmx_ana_selparam_t *param;
-    int                 i;
-    void               *mdata;
-
-    nparams   = sel->u.expr.method->nparams;
-    orgparam  = sel->u.expr.method->param;
-    snew(param, nparams);
-    memcpy(param, orgparam, nparams*sizeof(gmx_ana_selparam_t));
-    for (i = 0; i < nparams; ++i)
-    {
-        param[i].flags &= ~SPAR_SET;
-        _gmx_selvalue_setstore(&param[i].val, NULL);
-        if (param[i].flags & SPAR_VARNUM)
-        {
-            param[i].val.nr = -1;
-        }
-        /* Duplicate the enum value array if it is given statically */
-        if ((param[i].flags & SPAR_ENUMVAL) && orgparam[i].val.u.ptr != NULL)
-        {
-            int n;
-
-            /* Count the values */
-            n = 1;
-            while (orgparam[i].val.u.s[n] != NULL)
-            {
-                ++n;
-            }
-            _gmx_selvalue_reserve(&param[i].val, n+1);
-            memcpy(param[i].val.u.s, orgparam[i].val.u.s,
-                   (n+1)*sizeof(param[i].val.u.s[0]));
-        }
-    }
-    mdata = NULL;
-    if (sel->u.expr.method->init_data)
-    {
-        mdata = sel->u.expr.method->init_data(nparams, param);
-        if (mdata == NULL)
-        {
-            gmx_fatal(FARGS, "Method data initialization failed");
-        }
-    }
-    if (sel->u.expr.method->set_poscoll)
-    {
-        gmx_ana_selcollection_t *sc = _gmx_sel_lexer_selcollection(scanner);
-
-        sel->u.expr.method->set_poscoll(sc->pcc, mdata);
-    }
-    /* Store the values */
-    sel->u.expr.method->param = param;
-    sel->u.expr.mdata         = mdata;
-}
-
-/*!
- * \param[in,out] sel    Selection element to initialize.
- * \param[in]     method Selection method to set.
- * \param[in]     scanner Scanner data structure.
- *
- * Makes a copy of \p method and stores it in \p sel->u.expr.method,
- * and calls _gmx_selelem_init_method_params();
- */
-void
-_gmx_selelem_set_method(t_selelem *sel, gmx_ana_selmethod_t *method,
-                        yyscan_t scanner)
-{
-    int      i;
-
-    _gmx_selelem_set_vtype(sel, method->type);
-    sel->name   = method->name;
-    snew(sel->u.expr.method, 1);
-    memcpy(sel->u.expr.method, method, sizeof(gmx_ana_selmethod_t));
-    _gmx_selelem_init_method_params(sel, scanner);
-}
-
-/*! \brief
- * Initializes the reference position calculation for a \ref SEL_EXPRESSION
- * element.
- *
- * \param[in,out] pcc    Position calculation collection to use.
- * \param[in,out] sel    Selection element to initialize.
- * \param[in]     rpost  Reference position type to use (NULL = default).
- * \returns       0 on success, a non-zero error code on error.
- */
-static int
-set_refpos_type(gmx_ana_poscalc_coll_t *pcc, t_selelem *sel, const char *rpost)
-{
-    int  rc;
-
-    if (!rpost)
-    {
-        return 0;
-    }
-
-    rc = 0;
-    if (sel->u.expr.method->pupdate)
-    {
-        /* By default, use whole residues/molecules. */
-        rc = gmx_ana_poscalc_create_enum(&sel->u.expr.pc, pcc, rpost,
-                                         POS_COMPLWHOLE);
-    }
-    else
-    {
-        _gmx_selparser_error("warning: '%s' modifier for '%s' ignored",
-                             rpost, sel->u.expr.method->name);
-    }
-    return rc;
-}
-
-/*!
- * \param[in]  left    Selection element for the left hand side.
- * \param[in]  right   Selection element for the right hand side.
- * \param[in]  op      String representation of the operator.
- * \param[in]  scanner Scanner data structure.
- * \returns    The created selection element.
- *
- * This function handles the creation of a \c t_selelem object for
- * arithmetic expressions.
- */
-t_selelem *
-_gmx_sel_init_arithmetic(t_selelem *left, t_selelem *right, char op,
-                         yyscan_t scanner)
-{
-    t_selelem         *sel;
-    char               buf[2];
-
-    buf[0] = op;
-    buf[1] = 0;
-    sel = _gmx_selelem_create(SEL_ARITHMETIC);
-    sel->v.type        = REAL_VALUE;
-    switch(op)
-    {
-        case '+': sel->u.arith.type = ARITH_PLUS; break;
-        case '-': sel->u.arith.type = (right ? ARITH_MINUS : ARITH_NEG); break;
-        case '*': sel->u.arith.type = ARITH_MULT; break;
-        case '/': sel->u.arith.type = ARITH_DIV;  break;
-        case '^': sel->u.arith.type = ARITH_EXP;  break;
-    }
-    sel->u.arith.opstr = strdup(buf);
-    sel->name          = sel->u.arith.opstr;
-    sel->child         = left;
-    sel->child->next   = right;
-    return sel;
-}
-
-/*!
- * \param[in]  left   Selection element for the left hand side.
- * \param[in]  right  Selection element for the right hand side.
- * \param[in]  cmpop  String representation of the comparison operator.
- * \param[in]  scanner Scanner data structure.
- * \returns    The created selection element.
- *
- * This function handles the creation of a \c t_selelem object for
- * comparison expressions.
- */
-t_selelem *
-_gmx_sel_init_comparison(t_selelem *left, t_selelem *right, char *cmpop,
-                         yyscan_t scanner)
-{
-    t_selelem         *sel;
-    t_selexpr_param   *params, *param;
-    const char        *name;
-    int                rc;
-
-    sel = _gmx_selelem_create(SEL_EXPRESSION);
-    _gmx_selelem_set_method(sel, &sm_compare, scanner);
-    /* Create the parameter for the left expression */
-    name               = left->v.type == INT_VALUE ? "int1" : "real1";
-    params = param     = _gmx_selexpr_create_param(strdup(name));
-    param->nval        = 1;
-    param->value       = _gmx_selexpr_create_value_expr(left);
-    /* Create the parameter for the right expression */
-    name               = right->v.type == INT_VALUE ? "int2" : "real2";
-    param              = _gmx_selexpr_create_param(strdup(name));
-    param->nval        = 1;
-    param->value       = _gmx_selexpr_create_value_expr(right);
-    params->next       = param;
-    /* Create the parameter for the operator */
-    param              = _gmx_selexpr_create_param(strdup("op"));
-    param->nval        = 1;
-    param->value       = _gmx_selexpr_create_value(STR_VALUE);
-    param->value->u.s  = cmpop;
-    params->next->next = param;
-    if (!_gmx_sel_parse_params(params, sel->u.expr.method->nparams,
-                               sel->u.expr.method->param, sel, scanner))
-    {
-        _gmx_selparser_error("error in comparison initialization");
-        _gmx_selelem_free(sel);
-        return NULL;
-    }
-
-    return sel;
-}
-
-/*!
- * \param[in]  method Method to use.
- * \param[in]  args   Pointer to the first argument.
- * \param[in]  rpost  Reference position type to use (NULL = default).
- * \param[in]  scanner Scanner data structure.
- * \returns    The created selection element.
- *
- * This function handles the creation of a \c t_selelem object for
- * selection methods that do not take parameters.
- */
-t_selelem *
-_gmx_sel_init_keyword(gmx_ana_selmethod_t *method, t_selexpr_value *args,
-                      const char *rpost, yyscan_t scanner)
-{
-    gmx_ana_selcollection_t *sc = _gmx_sel_lexer_selcollection(scanner);
-    t_selelem         *root, *child;
-    t_selexpr_param   *params, *param;
-    t_selexpr_value   *arg;
-    int                nargs;
-    int                rc;
-
-    if (method->nparams > 0)
-    {
-        gmx_bug("internal error");
-        return NULL;
-    }
-
-    root = _gmx_selelem_create(SEL_EXPRESSION);
-    child = root;
-    _gmx_selelem_set_method(child, method, scanner);
-
-    /* Initialize the evaluation of keyword matching if values are provided */
-    if (args)
-    {
-        gmx_ana_selmethod_t *kwmethod;
-        switch (method->type)
-        {
-            case INT_VALUE:  kwmethod = &sm_keyword_int;  break;
-            case REAL_VALUE: kwmethod = &sm_keyword_real; break;
-            case STR_VALUE:  kwmethod = &sm_keyword_str;  break;
-            default:
-                _gmx_selparser_error("unknown type for keyword selection");
-                _gmx_selexpr_free_values(args);
-                goto on_error;
-        }
-        /* Count the arguments */
-        nargs = 0;
-        arg   = args;
-        while (arg)
-        {
-            ++nargs;
-            arg = arg->next;
-        }
-        /* Initialize the selection element */
-        root = _gmx_selelem_create(SEL_EXPRESSION);
-        _gmx_selelem_set_method(root, kwmethod, scanner);
-        params = param = _gmx_selexpr_create_param(NULL);
-        param->nval    = 1;
-        param->value   = _gmx_selexpr_create_value_expr(child);
-        param          = _gmx_selexpr_create_param(NULL);
-        param->nval    = nargs;
-        param->value   = args;
-        params->next   = param;
-        if (!_gmx_sel_parse_params(params, root->u.expr.method->nparams,
-                                   root->u.expr.method->param, root, scanner))
-        {
-            _gmx_selparser_error("error in keyword selection initialization");
-            goto on_error;
-        }
-    }
-    rc = set_refpos_type(sc->pcc, child, rpost);
-    if (rc != 0)
-    {
-        goto on_error;
-    }
-
-    return root;
-
-/* On error, free all memory and return NULL. */
-on_error:
-    _gmx_selelem_free(root);
-    return NULL;
-}
-
-/*!
- * \param[in]  method Method to use for initialization.
- * \param[in]  params Pointer to the first parameter.
- * \param[in]  rpost  Reference position type to use (NULL = default).
- * \param[in]  scanner Scanner data structure.
- * \returns    The created selection element.
- *
- * This function handles the creation of a \c t_selelem object for
- * selection methods that take parameters.
- *
- * Part of the behavior of the \c same selection keyword is hardcoded into
- * this function (or rather, into _gmx_selelem_custom_init_same()) to allow the
- * use of any keyword in \c "same KEYWORD as" without requiring special
- * handling somewhere else (or sacrificing the simple syntax).
- */
-t_selelem *
-_gmx_sel_init_method(gmx_ana_selmethod_t *method, t_selexpr_param *params,
-                     const char *rpost, yyscan_t scanner)
-{
-    gmx_ana_selcollection_t *sc = _gmx_sel_lexer_selcollection(scanner);
-    t_selelem       *root;
-    int              rc;
-
-    _gmx_sel_finish_method(scanner);
-    /* The "same" keyword needs some custom massaging of the parameters. */
-    rc = _gmx_selelem_custom_init_same(&method, params, scanner);
-    if (rc != 0)
-    {
-        _gmx_selexpr_free_params(params);
-        return NULL;
-    }
-    root = _gmx_selelem_create(SEL_EXPRESSION);
-    _gmx_selelem_set_method(root, method, scanner);
-    /* Process the parameters */
-    if (!_gmx_sel_parse_params(params, root->u.expr.method->nparams,
-                               root->u.expr.method->param, root, scanner))
-    {
-        _gmx_selelem_free(root);
-        return NULL;
-    }
-    rc = set_refpos_type(sc->pcc, root, rpost);
-    if (rc != 0)
-    {
-        _gmx_selelem_free(root);
-        return NULL;
-    }
-
-    return root;
-}
-
-/*!
- * \param[in]  method Modifier to use for initialization.
- * \param[in]  params Pointer to the first parameter.
- * \param[in]  sel    Selection element that the modifier should act on.
- * \param[in]  scanner Scanner data structure.
- * \returns    The created selection element.
- *
- * This function handles the creation of a \c t_selelem object for
- * selection modifiers.
- */
-t_selelem *
-_gmx_sel_init_modifier(gmx_ana_selmethod_t *method, t_selexpr_param *params,
-                       t_selelem *sel, yyscan_t scanner)
-{
-    t_selelem         *root;
-    t_selelem         *mod;
-    t_selexpr_param   *vparam;
-    int                i;
-
-    _gmx_sel_finish_method(scanner);
-    mod = _gmx_selelem_create(SEL_MODIFIER);
-    _gmx_selelem_set_method(mod, method, scanner);
-    if (method->type == NO_VALUE)
-    {
-        t_selelem *child;
-
-        child = sel;
-        while (child->next)
-        {
-            child = child->next;
-        }
-        child->next = mod;
-        root        = sel;
-    }
-    else
-    {
-        vparam        = _gmx_selexpr_create_param(NULL);
-        vparam->nval  = 1;
-        vparam->value = _gmx_selexpr_create_value_expr(sel);
-        vparam->next  = params;
-        params        = vparam;
-        root          = mod;
-    }
-    /* Process the parameters */
-    if (!_gmx_sel_parse_params(params, mod->u.expr.method->nparams,
-                               mod->u.expr.method->param, mod, scanner))
-    {
-        _gmx_selelem_free(mod);
-        return NULL;
-    }
-
-    return root;
-}
-
-/*!
- * \param[in]  expr    Input selection element for the position calculation.
- * \param[in]  type    Reference position type or NULL for default.
- * \param[in]  scanner Scanner data structure.
- * \returns    The created selection element.
- *
- * This function handles the creation of a \c t_selelem object for
- * evaluation of reference positions.
- */
-t_selelem *
-_gmx_sel_init_position(t_selelem *expr, const char *type, yyscan_t scanner)
-{
-    t_selelem       *root;
-    t_selexpr_param *params;
-
-    root = _gmx_selelem_create(SEL_EXPRESSION);
-    _gmx_selelem_set_method(root, &sm_keyword_pos, scanner);
-    _gmx_selelem_set_kwpos_type(root, type);
-    /* Create the parameters for the parameter parser. */
-    params        = _gmx_selexpr_create_param(NULL);
-    params->nval  = 1;
-    params->value = _gmx_selexpr_create_value_expr(expr);
-    /* Parse the parameters. */
-    if (!_gmx_sel_parse_params(params, root->u.expr.method->nparams,
-                               root->u.expr.method->param, root, scanner))
-    {
-        _gmx_selelem_free(root);
-        return NULL;
-    }
-
-    return root;
-}
-
-/*!
- * \param[in] x,y,z  Coordinates for the position.
- * \returns   The creates selection element.
- */
-t_selelem *
-_gmx_sel_init_const_position(real x, real y, real z)
-{
-    t_selelem *sel;
-    rvec       pos;
-
-    sel = _gmx_selelem_create(SEL_CONST);
-    _gmx_selelem_set_vtype(sel, POS_VALUE);
-    _gmx_selvalue_reserve(&sel->v, 1);
-    pos[XX] = x;
-    pos[YY] = y;
-    pos[ZZ] = z;
-    gmx_ana_pos_init_const(sel->v.u.p, pos);
-    return sel;
-}
-
-/*!
- * \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.
- *
- * See gmx_ana_indexgrps_find() for information on how \p name is matched
- * against the index groups.
- */
-t_selelem *
-_gmx_sel_init_group_by_name(const char *name, yyscan_t scanner)
-{
-    gmx_ana_indexgrps_t *grps = _gmx_sel_lexer_indexgrps(scanner);
-    t_selelem *sel;
-
-    if (!grps)
-    {
-        return NULL;
-    }
-    sel = _gmx_selelem_create(SEL_CONST);
-    _gmx_selelem_set_vtype(sel, GROUP_VALUE); 
-    /* FIXME: The constness should not be cast away */
-    if (!gmx_ana_indexgrps_find(&sel->u.cgrp, grps, (char *)name))
-    {
-        _gmx_selelem_free(sel);
-        return NULL;
-    }
-    sel->name = sel->u.cgrp.name;
-    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.
- */
-t_selelem *
-_gmx_sel_init_group_by_id(int id, yyscan_t scanner)
-{
-    gmx_ana_indexgrps_t *grps = _gmx_sel_lexer_indexgrps(scanner);
-    t_selelem *sel;
-
-    if (!grps)
-    {
-        return NULL;
-    }
-    sel = _gmx_selelem_create(SEL_CONST);
-    _gmx_selelem_set_vtype(sel, GROUP_VALUE);
-    if (!gmx_ana_indexgrps_extract(&sel->u.cgrp, grps, id))
-    {
-        _gmx_selelem_free(sel);
-        return NULL;
-    }
-    sel->name = sel->u.cgrp.name;
-    return sel;
-}
-
-/*!
- * \param[in,out] sel  Value of the variable.
- * \returns       The created selection element that references \p sel.
- *
- * The reference count of \p sel is updated, but no other modifications are
- * made.
- */
-t_selelem *
-_gmx_sel_init_variable_ref(t_selelem *sel)
-{
-    t_selelem *ref;
-
-    if (sel->v.type == POS_VALUE && sel->type == SEL_CONST)
-    {
-        ref = sel;
-    }
-    else
-    {
-        ref = _gmx_selelem_create(SEL_SUBEXPRREF);
-        _gmx_selelem_set_vtype(ref, sel->v.type);
-        ref->name  = sel->name;
-        ref->child = sel;
-    }
-    sel->refcount++;
-    return ref;
-}
-
-/*! \brief
- * Initializes default values for position keyword evaluation.
- *
- * \param[in,out] root       Root of the element tree to initialize.
- * \param[in]     sc         Selection collection to use defaults from.
- * \param[in]     bSelection Whether the element evaluates the positions for a
- *   selection.
- */
-static void
-init_pos_keyword_defaults(t_selelem *root, gmx_ana_selcollection_t *sc, gmx_bool bSelection)
-{
-    t_selelem               *child;
-    int                      flags;
-
-    /* Selections use largest static group by default, while
-     * reference positions use the whole residue/molecule. */
-    if (root->type == SEL_EXPRESSION)
-    {
-        flags = bSelection ? POS_COMPLMAX : POS_COMPLWHOLE;
-        if (bSelection && sc->bMaskOnly)
-        {
-            flags |= POS_MASKONLY;
-        }
-        if (bSelection && sc->bVelocities)
-        {
-            flags |= POS_VELOCITIES;
-        }
-        if (bSelection && sc->bForces)
-        {
-            flags |= POS_FORCES;
-        }
-        _gmx_selelem_set_kwpos_type(root, bSelection ? sc->spost : sc->rpost);
-        _gmx_selelem_set_kwpos_flags(root, flags);
-    }
-    /* Change the defaults once we are no longer processing modifiers */
-    if (root->type != SEL_ROOT && root->type != SEL_MODIFIER
-        && root->type != SEL_SUBEXPRREF && root->type != SEL_SUBEXPR)
-    {
-        bSelection = FALSE;
-    }
-    /* Recurse into children */
-    child = root->child;
-    while (child)
-    {
-        init_pos_keyword_defaults(child, sc, bSelection);
-        child = child->next;
-    }
-}
-
-/*!
- * \param[in]  name     Name for the selection
- *     (if NULL, a default name is constructed).
- * \param[in]  sel      The selection element that evaluates the selection.
- * \param      scanner  Scanner data structure.
- * \returns    The created root selection element.
- *
- * This function handles the creation of root (\ref SEL_ROOT) \c t_selelem
- * objects for selections.
- */
-t_selelem *
-_gmx_sel_init_selection(char *name, t_selelem *sel, yyscan_t scanner)
-{
-    gmx_ana_selcollection_t *sc = _gmx_sel_lexer_selcollection(scanner);
-    t_selelem               *root;
-    int                      rc;
-
-    if (sel->v.type != POS_VALUE)
-    {
-        gmx_bug("each selection must evaluate to a position");
-        /* FIXME: Better handling of this error */
-        sfree(name);
-        return NULL;
-    }
-
-    root = _gmx_selelem_create(SEL_ROOT);
-    root->child = sel;
-    /* Assign the name (this is done here to free it automatically in the case
-     * of an error below). */
-    if (name)
-    {
-        root->name = root->u.cgrp.name = name;
-    }
-    /* Update the flags */
-    rc = _gmx_selelem_update_flags(root);
-    if (rc != 0)
-    {
-        _gmx_selelem_free(root);
-        return NULL;
-    }
-    /* Initialize defaults for position keywords */
-    init_pos_keyword_defaults(sel, sc, TRUE);
-
-    /* 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)
-    {
-        t_selelem *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->name = root->u.cgrp.name =
-                strdup(child->child->child->u.cgrp.name);
-        }
-    }
-    /* If there still is no name, use the selection string */
-    if (!root->name)
-    {
-        root->name = root->u.cgrp.name
-            = strdup(_gmx_sel_lexer_pselstr(scanner));
-    }
-
-    /* Print out some information if the parser is interactive */
-    if (_gmx_sel_is_lexer_interactive(scanner))
-    {
-        fprintf(stderr, "Selection '%s' parsed\n",
-                _gmx_sel_lexer_pselstr(scanner));
-    }
-
-    return root;
-}
-
-
-/*!
- * \param[in]  name     Name of the variable (should not be freed after this
- *   function).
- * \param[in]  expr     The selection element that evaluates the variable.
- * \param      scanner  Scanner data structure.
- * \returns    The created root selection element.
- *
- * This function handles the creation of root \c t_selelem objects for
- * variable assignments. A \ref SEL_ROOT element and a \ref SEL_SUBEXPR
- * element are both created.
- */
-t_selelem *
-_gmx_sel_assign_variable(char *name, t_selelem *expr, yyscan_t scanner)
-{
-    gmx_ana_selcollection_t *sc = _gmx_sel_lexer_selcollection(scanner);
-    const char              *pselstr = _gmx_sel_lexer_pselstr(scanner);
-    t_selelem               *root = NULL;
-    int                      rc;
-
-    rc = _gmx_selelem_update_flags(expr);
-    if (rc != 0)
-    {
-        sfree(name);
-        _gmx_selelem_free(expr);
-        return NULL;
-    }
-    /* Check if this is a constant non-group value */
-    if (expr->type == SEL_CONST && expr->v.type != GROUP_VALUE)
-    {
-        /* If so, just assign the constant value to the variable */
-        if (!_gmx_sel_add_var_symbol(sc->symtab, name, expr))
-        {
-            _gmx_selelem_free(expr);
-            sfree(name);
-            return NULL;
-        }
-        _gmx_selelem_free(expr);
-        sfree(name);
-        goto finish;
-    }
-    /* Check if we are assigning a variable to another variable */
-    if (expr->type == SEL_SUBEXPRREF)
-    {
-        /* If so, make a simple alias */
-        if (!_gmx_sel_add_var_symbol(sc->symtab, name, expr->child))
-        {
-            _gmx_selelem_free(expr);
-            sfree(name);
-            return NULL;
-        }
-        _gmx_selelem_free(expr);
-        sfree(name);
-        goto finish;
-    }
-    /* Create the root element */
-    root = _gmx_selelem_create(SEL_ROOT);
-    root->name          = name;
-    root->u.cgrp.name   = name;
-    /* Create the subexpression element */
-    root->child = _gmx_selelem_create(SEL_SUBEXPR);
-    _gmx_selelem_set_vtype(root->child, expr->v.type);
-    root->child->name   = name;
-    root->child->child  = expr;
-    /* Update flags */
-    rc = _gmx_selelem_update_flags(root);
-    if (rc != 0)
-    {
-        _gmx_selelem_free(root);
-        return NULL;
-    }
-    /* Add the variable to the symbol table */
-    if (!_gmx_sel_add_var_symbol(sc->symtab, name, root->child))
-    {
-        _gmx_selelem_free(root);
-        return NULL;
-    }
-finish:
-    srenew(sc->varstrs, sc->nvars + 1);
-    sc->varstrs[sc->nvars] = strdup(pselstr);
-    ++sc->nvars;
-    if (_gmx_sel_is_lexer_interactive(scanner))
-    {
-        fprintf(stderr, "Variable '%s' parsed\n", pselstr);
-    }
-    return root;
-}
-
-/*!
- * \param         sel   Selection to append (can be NULL, in which
- *   case nothing is done).
- * \param         last  Last selection, or NULL if not present or not known.
- * \param         scanner  Scanner data structure.
- * \returns       The last selection after the append.
- *
- * Appends \p sel after the last root element, and returns either \p sel
- * (if it was non-NULL) or the last element (if \p sel was NULL).
- */
-t_selelem *
-_gmx_sel_append_selection(t_selelem *sel, t_selelem *last, yyscan_t scanner)
-{
-    gmx_ana_selcollection_t *sc = _gmx_sel_lexer_selcollection(scanner);
-
-    /* Append sel after last, or the last element of sc if last is NULL */
-    if (last)
-    {
-        last->next = sel;
-    }
-    else
-    {
-        if (sc->root)
-        {
-            last = sc->root;
-            while (last->next)
-            {
-                last = last->next;
-            }
-            last->next = sel;
-        }
-        else
-        {
-            sc->root = sel;
-        }
-    }
-    /* Initialize a selection object if necessary */
-    if (sel)
-    {
-        last = sel;
-        /* Add the new selection to the collection if it is not a variable. */
-        if (sel->child->type != SEL_SUBEXPR)
-        {
-            int        i;
-
-            sc->nr++;
-            srenew(sc->sel, sc->nr);
-            i = sc->nr - 1;
-            snew(sc->sel[i], 1);
-            sc->sel[i]->name   = strdup(sel->name);
-            sc->sel[i]->selstr = strdup(_gmx_sel_lexer_pselstr(scanner));
-
-            if (sel->child->type == SEL_CONST)
-            {
-                gmx_ana_pos_copy(&sc->sel[i]->p, sel->child->v.u.p, TRUE);
-                sc->sel[i]->bDynamic = FALSE;
-            }
-            else
-            {
-                t_selelem *child;
-
-                child = sel->child;
-                child->flags     &= ~SEL_ALLOCVAL;
-                _gmx_selvalue_setstore(&child->v, &sc->sel[i]->p);
-                /* We should also skip any modifiers to determine the dynamic
-                 * status. */
-                while (child->type == SEL_MODIFIER)
-                {
-                    child = child->child;
-                    if (child->type == SEL_SUBEXPRREF)
-                    {
-                        child = child->child;
-                        /* Because most subexpression elements are created
-                         * during compilation, we need to check for them
-                         * explicitly here.
-                         */
-                        if (child->type == SEL_SUBEXPR)
-                        {
-                            child = child->child;
-                        }
-                    }
-                }
-                /* For variable references, we should skip the
-                 * SEL_SUBEXPRREF and SEL_SUBEXPR elements. */
-                if (child->type == SEL_SUBEXPRREF)
-                {
-                    child = child->child->child;
-                }
-                sc->sel[i]->bDynamic = (child->child->flags & SEL_DYNAMIC);
-            }
-            /* The group will be set after compilation */
-            sc->sel[i]->g        = NULL;
-            sc->sel[i]->selelem  = sel;
-            gmx_ana_selection_init_coverfrac(sc->sel[i], CFRAC_NONE);
-        }
-    }
-    /* Clear the selection string now that we've saved it */
-    _gmx_sel_lexer_clear_pselstr(scanner);
-    return last;
-}
-
-/*!
- * \param[in] scanner Scanner data structure.
- * \returns   TRUE if the parser should finish, FALSE if parsing should
- *   continue.
- *
- * This function is called always after _gmx_sel_append_selection() to
- * check whether a sufficient number of selections has already been provided.
- * This is used to terminate interactive parsers when the correct number of
- * selections has been provided.
- */
-gmx_bool
-_gmx_sel_parser_should_finish(yyscan_t scanner)
-{
-    gmx_ana_selcollection_t *sc = _gmx_sel_lexer_selcollection(scanner);
-    return sc->nr == _gmx_sel_lexer_exp_selcount(scanner);
-}
-
-/*!
- * \param[in] scanner Scanner data structure.
- */
-void
-_gmx_sel_handle_empty_cmd(yyscan_t scanner)
-{
-    gmx_ana_selcollection_t *sc = _gmx_sel_lexer_selcollection(scanner);
-    gmx_ana_indexgrps_t     *grps = _gmx_sel_lexer_indexgrps(scanner);
-    int                      i;
-
-    if (!_gmx_sel_is_lexer_interactive(scanner))
-        return;
-
-    if (grps)
-    {
-        fprintf(stderr, "Available index groups:\n");
-        gmx_ana_indexgrps_print(_gmx_sel_lexer_indexgrps(scanner), 0);
-    }
-    if (sc->nvars > 0 || sc->nr > 0)
-    {
-        fprintf(stderr, "Currently provided selections:\n");
-        for (i = 0; i < sc->nvars; ++i)
-        {
-            fprintf(stderr, "     %s\n", sc->varstrs[i]);
-        }
-        for (i = 0; i < sc->nr; ++i)
-        {
-            fprintf(stderr, " %2d. %s\n", i+1, sc->sel[i]->selstr);
-        }
-    }
-}
-
-/*!
- * \param[in] topic   Topic for which help was requested, or NULL for general
- *                    help.
- * \param[in] scanner Scanner data structure.
- *
- * \p topic is freed by this function.
- */
-void
-_gmx_sel_handle_help_cmd(char *topic, yyscan_t scanner)
-{
-    gmx_ana_selcollection_t *sc = _gmx_sel_lexer_selcollection(scanner);
-
-    _gmx_sel_print_help(sc, topic);
-    if (topic)
-    {
-        sfree(topic);
-    }
-}
-
-/*! \brief
- * Internal helper function used by gmx_ana_selcollection_parse_*() to do the actual work.
- *
- * \param[in]     maxnr   Maximum number of selections to parse
- *   (if -1, parse as many as provided by the user).
- * \param[in,out] scanner Scanner data structure.
- * \returns       0 on success, -1 on error.
- */
-static int
-run_parser(int maxnr, yyscan_t scanner)
-{
-    gmx_ana_selcollection_t *sc = _gmx_sel_lexer_selcollection(scanner);
-    gmx_bool bOk;
-    int  nr;
-
-    nr  = sc->nr;
-    bOk = !_gmx_sel_yybparse(scanner);
-    _gmx_sel_free_lexer(scanner);
-    nr = sc->nr - nr;
-    if (maxnr > 0 && nr != maxnr)
-    {
-        return -1;
-    }
-    return bOk ? 0 : -1;
-}
-
-/*!
- * \param[in,out] sc    Selection collection to use for output.
- * \param[in]     nr    Number of selections to parse
- *   (if -1, parse as many as provided by the user).
- * \param[in]     grps  External index groups (can be NULL).
- * \param[in]     bInteractive Whether the parser should behave interactively.
- * \returns       0 on success, -1 on error.
- *
- * The number of selections parsed can be accessed with
- * gmx_ana_selcollection_get_count() (note that if you call the parser
- * multiple times, this function returns the total count).
- */
-int
-gmx_ana_selcollection_parse_stdin(gmx_ana_selcollection_t *sc, int nr,
-                                  gmx_ana_indexgrps_t *grps, gmx_bool bInteractive)
-{
-    yyscan_t scanner;
-    int      rc;
-
-    rc = _gmx_sel_init_lexer(&scanner, sc, bInteractive, nr, grps);
-    if (rc != 0)
-    {
-        return rc;
-    }
-    /* We don't set the lexer input here, which causes it to use a special
-     * internal implementation for reading from stdin. */
-    return run_parser(nr, scanner);
-}
-
-/*!
- * \param[in,out] sc    Selection collection to use for output.
- * \param[in]     fnm   Name of the file to parse selections from.
- * \param[in]     grps  External index groups (can be NULL).
- * \returns       0 on success, -1 on error.
- *
- * The number of selections parsed can be accessed with
- * gmx_ana_selcollection_get_count() (note that if you call the parser
- * multiple times, this function returns the total count).
- */
-int
-gmx_ana_selcollection_parse_file(gmx_ana_selcollection_t *sc, const char *fnm,
-                                 gmx_ana_indexgrps_t *grps)
-{
-    yyscan_t scanner;
-    FILE *fp;
-    int   rc;
-
-    rc = _gmx_sel_init_lexer(&scanner, sc, FALSE, -1, grps);
-    if (rc != 0)
-    {
-        return rc;
-    }
-    fp = ffopen(fnm, "r");
-    _gmx_sel_set_lex_input_file(scanner, fp);
-    rc = run_parser(-1, scanner);
-    ffclose(fp);
-    return rc;
-}
-
-/*!
- * \param[in,out] sc    Selection collection to use for output.
- * \param[in]     str   String to parse selections from.
- * \param[in]     grps  External index groups (can be NULL).
- * \returns       0 on success, -1 on error.
- *
- * The number of selections parsed can be accessed with
- * gmx_ana_selcollection_get_count() (note that if you call the parser
- * multiple times, this function returns the total count).
- */
-int
-gmx_ana_selcollection_parse_str(gmx_ana_selcollection_t *sc, const char *str,
-                                gmx_ana_indexgrps_t *grps)
-{
-    yyscan_t scanner;
-    int      rc;
-
-    rc = _gmx_sel_init_lexer(&scanner, sc, FALSE, -1, grps);
-    if (rc != 0)
-    {
-        return rc;
-    }
-    _gmx_sel_set_lex_input_str(scanner, str);
-    return run_parser(-1, scanner);
-}
diff --git a/src/gmxlib/selection/parsetree.h b/src/gmxlib/selection/parsetree.h
deleted file mode 100644 (file)
index 8d97d15..0000000
+++ /dev/null
@@ -1,207 +0,0 @@
-/*
- *
- *                This source code is part of
- *
- *                 G   R   O   M   A   C   S
- *
- *          GROningen MAchine for Chemical Simulations
- *
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
- * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
- * Copyright (c) 2001-2009, The GROMACS development team,
- * check out http://www.gromacs.org for more information.
-
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * If you want to redistribute modifications, please consider that
- * scientific software is very special. Version control is crucial -
- * bugs must be traceable. We will be happy to consider code for
- * inclusion in the official distribution, but derived work must not
- * be called official GROMACS. Details are found in the README & COPYING
- * files - if they are missing, get the official version at www.gromacs.org.
- *
- * To help us fund GROMACS development, we humbly ask that you cite
- * the papers on the package - you can find them in the top README file.
- *
- * For more info, check our website at http://www.gromacs.org
- */
-/*! \internal \file
- * \brief Handling of intermediate selection parser data.
- *
- * The data types declared in this header are used by the parser to store
- * intermediate data when constructing method expressions.
- * In particular, the parameters for the method are stored.
- * The intermediate data is freed once a \c t_selelem object can be
- * constructed.
- * 
- * This is an implementation header: there should be no need to use it outside
- * this directory.
- */
-#ifndef SELECTION_PARSETREE_H
-#define SELECTION_PARSETREE_H
-
-/*#include <typedefs.h>*/
-#include <types/simple.h>
-
-
-#include <selvalue.h>
-
-struct t_selelem;
-struct gmx_ana_indexgrps_t;
-struct gmx_ana_selmethod_t;
-struct gmx_ana_selparam_t;
-
-/*! \internal \brief
- * Describes a parsed value, possibly resulting from expression evaluation.
- */
-typedef struct t_selexpr_value
-{
-    /** Type of the value. */
-    e_selvalue_t            type;
-    /** TRUE if the value is the result of an expression. */
-    gmx_bool                    bExpr;
-    union {
-        /** The integer value/range (\p type INT_VALUE); */
-        struct {
-            /** Beginning of the range. */
-            int             i1;
-            /** End of the range; equals \p i1 for a single integer. */
-            int             i2;
-        }                   i;
-        /** The real value/range (\p type REAL_VALUE); */
-        struct {
-            /** Beginning of the range. */
-            real            r1;
-            /** End of the range; equals \p r1 for a single number. */
-            real            r2;
-        }                   r;
-        /** The string value (\p type STR_VALUE); */
-        char               *s;
-        /** The position value (\p type POS_VALUE); */
-        rvec                x;
-        /** The expression if \p bExpr is TRUE. */
-        struct t_selelem   *expr;
-    }                       u;
-    /** Pointer to the next value. */
-    struct t_selexpr_value *next;
-} t_selexpr_value;
-
-/*! \internal \brief
- * Describes a parsed method parameter.
- */
-typedef struct t_selexpr_param
-{
-    /** Name of the parameter. */
-    char                   *name;
-    /** Number of values given for this parameter. */
-    int                     nval;
-    /** Pointer to the first value. */
-    struct t_selexpr_value *value;
-    /** Pointer to the next parameter. */
-    struct t_selexpr_param *next;
-} t_selexpr_param;
-
-/** Error reporting function for the selection parser. */
-void
-_gmx_selparser_error(const char *fmt, ...);
-
-/** Allocates and initializes a constant \c t_selexpr_value. */
-t_selexpr_value *
-_gmx_selexpr_create_value(e_selvalue_t type);
-/** Allocates and initializes an expression \c t_selexpr_value. */
-t_selexpr_value *
-_gmx_selexpr_create_value_expr(struct t_selelem *expr);
-/** Allocates and initializes a \c t_selexpr_param. */
-t_selexpr_param *
-_gmx_selexpr_create_param(char *name);
-
-/** Frees the memory allocated for a chain of values. */
-void
-_gmx_selexpr_free_values(t_selexpr_value *value);
-/** Frees the memory allocated for a chain of parameters. */
-void
-_gmx_selexpr_free_params(t_selexpr_param *param);
-
-/** Propagates the flags for selection elements. */
-int
-_gmx_selelem_update_flags(struct t_selelem *sel);
-
-/** Initializes the method parameter data of \ref SEL_EXPRESSION and
- * \ref SEL_MODIFIER elements. */
-void
-_gmx_selelem_init_method_params(struct t_selelem *sel, void *scanner);
-/** Initializes the method for a \ref SEL_EXPRESSION selection element. */
-void
-_gmx_selelem_set_method(struct t_selelem *sel,
-                        struct gmx_ana_selmethod_t *method, void *scanner);
-
-/** Creates a \c t_selelem for arithmetic expression evaluation. */
-struct t_selelem *
-_gmx_sel_init_arithmetic(struct t_selelem *left, struct t_selelem *right,
-                         char op, void *scanner);
-/** Creates a \c t_selelem for comparsion expression evaluation. */
-struct t_selelem *
-_gmx_sel_init_comparison(struct t_selelem *left, struct t_selelem *right,
-                         char *cmpop, void *scanner);
-/** Creates a \c t_selelem for a keyword expression from the parsed data. */
-struct t_selelem *
-_gmx_sel_init_keyword(struct gmx_ana_selmethod_t *method,
-                      t_selexpr_value *args, const char *rpost, void *scanner);
-/** Creates a \c t_selelem for a method expression from the parsed data. */
-struct t_selelem *
-_gmx_sel_init_method(struct gmx_ana_selmethod_t *method,
-                     t_selexpr_param *params, const char *rpost,
-                     void *scanner);
-/** Creates a \c t_selelem for a modifier expression from the parsed data. */
-struct t_selelem *
-_gmx_sel_init_modifier(struct gmx_ana_selmethod_t *mod, t_selexpr_param *params,
-                       struct t_selelem *sel, void *scanner);
-/** Creates a \c t_selelem for evaluation of reference positions. */
-struct t_selelem *
-_gmx_sel_init_position(struct t_selelem *expr, const char *type, void *scanner);
-
-/** Creates a \c t_selelem for a constant position. */
-struct t_selelem *
-_gmx_sel_init_const_position(real x, real y, real z);
-/** Creates a \c t_selelem for a index group expression using group name. */
-struct t_selelem *
-_gmx_sel_init_group_by_name(const char *name, void *scanner);
-/** Creates a \c t_selelem for a index group expression using group index. */
-struct t_selelem *
-_gmx_sel_init_group_by_id(int id, void *scanner);
-/** Creates a \c t_selelem for a variable reference */
-struct t_selelem *
-_gmx_sel_init_variable_ref(struct t_selelem *sel);
-
-/** Creates a root \c t_selelem for a selection. */
-struct t_selelem *
-_gmx_sel_init_selection(char *name, struct t_selelem *sel, void *scanner);
-/** Creates a root \c t_selelem elements for a variable assignment. */
-struct t_selelem *
-_gmx_sel_assign_variable(char *name, struct t_selelem *expr, void *scanner);
-/** Appends a root \c t_selelem to a selection collection. */
-struct t_selelem *
-_gmx_sel_append_selection(struct t_selelem *sel, struct t_selelem *last,
-                          void *scanner);
-/** Check whether the parser should finish. */
-gmx_bool
-_gmx_sel_parser_should_finish(void *scanner);
-
-/** Handle empty commands. */
-void
-_gmx_sel_handle_empty_cmd(void *scanner);
-/** Process help commands. */
-void
-_gmx_sel_handle_help_cmd(char *topic, void *scanner);
-
-/* In params.c */
-/** Initializes an array of parameters based on input from the selection parser. */
-gmx_bool
-_gmx_sel_parse_params(t_selexpr_param *pparams, int nparam,
-                      struct gmx_ana_selparam_t *param, struct t_selelem *root,
-                      void *scanner);
-
-#endif
diff --git a/src/gmxlib/selection/regenerate_parser.sh b/src/gmxlib/selection/regenerate_parser.sh
deleted file mode 100755 (executable)
index 5b597dc..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/bin/bash
-#
-# This script runs Bison and/or Flex to regenerate the files as follows:
-#   parser.y  -> parser.c, parser.h
-#   scanner.l -> scanner.c, scanner_flex.h
-# The commands are run only if the generated files are older than the
-# Bison/Flex input files, or if a '-f' flag is provided.
-
-FORCE=
-if [ "x$1" == "x-f" ] ; then
-    FORCE=1
-fi
-
-# For convenience, change to the directory where the files are located
-# if the script is run from the root of the source tree.
-dirname=src/gmxlib/selection
-if [[ -f $dirname/parser.y && -f $dirname/scanner.l ]] ; then
-    cd $dirname
-fi
-
-[[ $FORCE || parser.y  -nt parser.c ]]  && bison -d -t -o parser.c parser.y
-[[ $FORCE || scanner.l -nt scanner.c ]] && flex -o scanner.c scanner.l
diff --git a/src/gmxlib/selection/scanner.c b/src/gmxlib/selection/scanner.c
deleted file mode 100644 (file)
index de74a3d..0000000
+++ /dev/null
@@ -1,2215 +0,0 @@
-#line 2 "scanner.c"
-
-#line 4 "scanner.c"
-
-#define  YY_INT_ALIGNED short int
-
-/* A lexical scanner generated by flex */
-
-#define FLEX_SCANNER
-#define YY_FLEX_MAJOR_VERSION 2
-#define YY_FLEX_MINOR_VERSION 5
-#define YY_FLEX_SUBMINOR_VERSION 35
-#if YY_FLEX_SUBMINOR_VERSION > 0
-#define FLEX_BETA
-#endif
-
-/* First, we deal with  platform-specific or compiler-specific issues. */
-
-/* begin standard C headers. */
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-#include <stdlib.h>
-
-/* end standard C headers. */
-
-/* flex integer type definitions */
-
-#ifndef FLEXINT_H
-#define FLEXINT_H
-
-/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
-
-#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
-
-/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
- * if you want the limit (max/min) macros for int types. 
- */
-#ifndef __STDC_LIMIT_MACROS
-#define __STDC_LIMIT_MACROS 1
-#endif
-
-#include <inttypes.h>
-typedef int8_t flex_int8_t;
-typedef uint8_t flex_uint8_t;
-typedef int16_t flex_int16_t;
-typedef uint16_t flex_uint16_t;
-typedef int32_t flex_int32_t;
-typedef uint32_t flex_uint32_t;
-#else
-typedef signed char flex_int8_t;
-typedef short int flex_int16_t;
-typedef int flex_int32_t;
-typedef unsigned char flex_uint8_t; 
-typedef unsigned short int flex_uint16_t;
-typedef unsigned int flex_uint32_t;
-
-/* Limits of integral types. */
-#ifndef INT8_MIN
-#define INT8_MIN               (-128)
-#endif
-#ifndef INT16_MIN
-#define INT16_MIN              (-32767-1)
-#endif
-#ifndef INT32_MIN
-#define INT32_MIN              (-2147483647-1)
-#endif
-#ifndef INT8_MAX
-#define INT8_MAX               (127)
-#endif
-#ifndef INT16_MAX
-#define INT16_MAX              (32767)
-#endif
-#ifndef INT32_MAX
-#define INT32_MAX              (2147483647)
-#endif
-#ifndef UINT8_MAX
-#define UINT8_MAX              (255U)
-#endif
-#ifndef UINT16_MAX
-#define UINT16_MAX             (65535U)
-#endif
-#ifndef UINT32_MAX
-#define UINT32_MAX             (4294967295U)
-#endif
-
-#endif /* ! C99 */
-
-#endif /* ! FLEXINT_H */
-
-#ifdef __cplusplus
-
-/* The "const" storage-class-modifier is valid. */
-#define YY_USE_CONST
-
-#else  /* ! __cplusplus */
-
-/* C99 requires __STDC__ to be defined as 1. */
-#if defined (__STDC__)
-
-#define YY_USE_CONST
-
-#endif /* defined (__STDC__) */
-#endif /* ! __cplusplus */
-
-#ifdef YY_USE_CONST
-#define yyconst const
-#else
-#define yyconst
-#endif
-
-/* Returned upon end-of-file. */
-#define YY_NULL 0
-
-/* Promotes a possibly negative, possibly signed char to an unsigned
- * integer for use as an array index.  If the signed char is negative,
- * we want to instead treat it as an 8-bit unsigned char, hence the
- * double cast.
- */
-#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
-
-/* An opaque pointer. */
-#ifndef YY_TYPEDEF_YY_SCANNER_T
-#define YY_TYPEDEF_YY_SCANNER_T
-typedef void* yyscan_t;
-#endif
-
-/* For convenience, these vars (plus the bison vars far below)
-   are macros in the reentrant scanner. */
-#define yyin yyg->yyin_r
-#define yyout yyg->yyout_r
-#define yyextra yyg->yyextra_r
-#define yyleng yyg->yyleng_r
-#define yytext yyg->yytext_r
-#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno)
-#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column)
-#define yy_flex_debug yyg->yy_flex_debug_r
-
-/* Enter a start condition.  This macro really ought to take a parameter,
- * but we do it the disgusting crufty way forced on us by the ()-less
- * definition of BEGIN.
- */
-#define BEGIN yyg->yy_start = 1 + 2 *
-
-/* Translate the current start state into a value that can be later handed
- * to BEGIN to return to the state.  The YYSTATE alias is for lex
- * compatibility.
- */
-#define YY_START ((yyg->yy_start - 1) / 2)
-#define YYSTATE YY_START
-
-/* Action number for EOF rule of a given start state. */
-#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
-
-/* Special action meaning "start processing a new file". */
-#define YY_NEW_FILE _gmx_sel_yyrestart(yyin ,yyscanner )
-
-#define YY_END_OF_BUFFER_CHAR 0
-
-/* Size of default input buffer. */
-#ifndef YY_BUF_SIZE
-#ifdef __ia64__
-/* On IA-64, the buffer size is 16k, not 8k.
- * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case.
- * Ditto for the __ia64__ case accordingly.
- */
-#define YY_BUF_SIZE 32768
-#else
-#define YY_BUF_SIZE 16384
-#endif /* __ia64__ */
-#endif
-
-/* The state buf must be large enough to hold one state per character in the main buffer.
- */
-#define YY_STATE_BUF_SIZE   ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
-
-#ifndef YY_TYPEDEF_YY_BUFFER_STATE
-#define YY_TYPEDEF_YY_BUFFER_STATE
-typedef struct yy_buffer_state *YY_BUFFER_STATE;
-#endif
-
-#define EOB_ACT_CONTINUE_SCAN 0
-#define EOB_ACT_END_OF_FILE 1
-#define EOB_ACT_LAST_MATCH 2
-
-    #define YY_LESS_LINENO(n)
-    
-/* Return all but the first "n" matched characters back to the input stream. */
-#define yyless(n) \
-       do \
-               { \
-               /* Undo effects of setting up yytext. */ \
-        int yyless_macro_arg = (n); \
-        YY_LESS_LINENO(yyless_macro_arg);\
-               *yy_cp = yyg->yy_hold_char; \
-               YY_RESTORE_YY_MORE_OFFSET \
-               yyg->yy_c_buf_p = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
-               YY_DO_BEFORE_ACTION; /* set up yytext again */ \
-               } \
-       while ( 0 )
-
-#define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner )
-
-#ifndef YY_TYPEDEF_YY_SIZE_T
-#define YY_TYPEDEF_YY_SIZE_T
-typedef size_t yy_size_t;
-#endif
-
-#ifndef YY_STRUCT_YY_BUFFER_STATE
-#define YY_STRUCT_YY_BUFFER_STATE
-struct yy_buffer_state
-       {
-       FILE *yy_input_file;
-
-       char *yy_ch_buf;                /* input buffer */
-       char *yy_buf_pos;               /* current position in input buffer */
-
-       /* Size of input buffer in bytes, not including room for EOB
-        * characters.
-        */
-       yy_size_t yy_buf_size;
-
-       /* Number of characters read into yy_ch_buf, not including EOB
-        * characters.
-        */
-       int yy_n_chars;
-
-       /* Whether we "own" the buffer - i.e., we know we created it,
-        * and can realloc() it to grow it, and should free() it to
-        * delete it.
-        */
-       int yy_is_our_buffer;
-
-       /* Whether this is an "interactive" input source; if so, and
-        * if we're using stdio for input, then we want to use getc()
-        * instead of fread(), to make sure we stop fetching input after
-        * each newline.
-        */
-       int yy_is_interactive;
-
-       /* Whether we're considered to be at the beginning of a line.
-        * If so, '^' rules will be active on the next match, otherwise
-        * not.
-        */
-       int yy_at_bol;
-
-    int yy_bs_lineno; /**< The line count. */
-    int yy_bs_column; /**< The column count. */
-    
-       /* Whether to try to fill the input buffer when we reach the
-        * end of it.
-        */
-       int yy_fill_buffer;
-
-       int yy_buffer_status;
-
-#define YY_BUFFER_NEW 0
-#define YY_BUFFER_NORMAL 1
-       /* When an EOF's been seen but there's still some text to process
-        * then we mark the buffer as YY_EOF_PENDING, to indicate that we
-        * shouldn't try reading from the input source any more.  We might
-        * still have a bunch of tokens to match, though, because of
-        * possible backing-up.
-        *
-        * When we actually see the EOF, we change the status to "new"
-        * (via _gmx_sel_yyrestart()), so that the user can continue scanning by
-        * just pointing yyin at a new input file.
-        */
-#define YY_BUFFER_EOF_PENDING 2
-
-       };
-#endif /* !YY_STRUCT_YY_BUFFER_STATE */
-
-/* We provide macros for accessing buffer states in case in the
- * future we want to put the buffer states in a more general
- * "scanner state".
- *
- * Returns the top of the stack, or NULL.
- */
-#define YY_CURRENT_BUFFER ( yyg->yy_buffer_stack \
-                          ? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] \
-                          : NULL)
-
-/* Same as previous macro, but useful when we know that the buffer stack is not
- * NULL or when we need an lvalue. For internal use only.
- */
-#define YY_CURRENT_BUFFER_LVALUE yyg->yy_buffer_stack[yyg->yy_buffer_stack_top]
-
-void _gmx_sel_yyrestart (FILE *input_file ,yyscan_t yyscanner );
-void _gmx_sel_yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner );
-YY_BUFFER_STATE _gmx_sel_yy_create_buffer (FILE *file,int size ,yyscan_t yyscanner );
-void _gmx_sel_yy_delete_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
-void _gmx_sel_yy_flush_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
-void _gmx_sel_yypush_buffer_state (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner );
-void _gmx_sel_yypop_buffer_state (yyscan_t yyscanner );
-
-static void _gmx_sel_yyensure_buffer_stack (yyscan_t yyscanner );
-static void _gmx_sel_yy_load_buffer_state (yyscan_t yyscanner );
-static void _gmx_sel_yy_init_buffer (YY_BUFFER_STATE b,FILE *file ,yyscan_t yyscanner );
-
-#define YY_FLUSH_BUFFER _gmx_sel_yy_flush_buffer(YY_CURRENT_BUFFER ,yyscanner)
-
-YY_BUFFER_STATE _gmx_sel_yy_scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner );
-YY_BUFFER_STATE _gmx_sel_yy_scan_string (yyconst char *yy_str ,yyscan_t yyscanner );
-YY_BUFFER_STATE _gmx_sel_yy_scan_bytes (yyconst char *bytes,int len ,yyscan_t yyscanner );
-
-void *_gmx_sel_yyalloc (yy_size_t ,yyscan_t yyscanner );
-void *_gmx_sel_yyrealloc (void *,yy_size_t ,yyscan_t yyscanner );
-void _gmx_sel_yyfree (void * ,yyscan_t yyscanner );
-
-#define yy_new_buffer _gmx_sel_yy_create_buffer
-
-#define yy_set_interactive(is_interactive) \
-       { \
-       if ( ! YY_CURRENT_BUFFER ){ \
-        _gmx_sel_yyensure_buffer_stack (yyscanner); \
-               YY_CURRENT_BUFFER_LVALUE =    \
-            _gmx_sel_yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \
-       } \
-       YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
-       }
-
-#define yy_set_bol(at_bol) \
-       { \
-       if ( ! YY_CURRENT_BUFFER ){\
-        _gmx_sel_yyensure_buffer_stack (yyscanner); \
-               YY_CURRENT_BUFFER_LVALUE =    \
-            _gmx_sel_yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \
-       } \
-       YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
-       }
-
-#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
-
-#define _gmx_sel_yywrap(n) 1
-#define YY_SKIP_YYWRAP
-
-typedef unsigned char YY_CHAR;
-
-typedef int yy_state_type;
-
-#define yytext_ptr yytext_r
-
-static yy_state_type yy_get_previous_state (yyscan_t yyscanner );
-static yy_state_type yy_try_NUL_trans (yy_state_type current_state  ,yyscan_t yyscanner);
-static int yy_get_next_buffer (yyscan_t yyscanner );
-static void yy_fatal_error (yyconst char msg[] ,yyscan_t yyscanner );
-
-/* Done after the current pattern has been matched and before the
- * corresponding action - sets up yytext.
- */
-#define YY_DO_BEFORE_ACTION \
-       yyg->yytext_ptr = yy_bp; \
-       yyleng = (size_t) (yy_cp - yy_bp); \
-       yyg->yy_hold_char = *yy_cp; \
-       *yy_cp = '\0'; \
-       yyg->yy_c_buf_p = yy_cp;
-
-#define YY_NUM_RULES 26
-#define YY_END_OF_BUFFER 27
-/* This struct is not used in this scanner,
-   but its presence is necessary. */
-struct yy_trans_info
-       {
-       flex_int32_t yy_verify;
-       flex_int32_t yy_nxt;
-       };
-static yyconst flex_int16_t yy_accept[89] =
-    {   0,
-        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
-       27,   25,   23,    6,   20,   25,    1,   25,   25,    2,
-        6,   21,   25,   22,   25,   24,   22,   22,   22,   22,
-       22,   22,   25,   22,   22,   22,   22,   22,   11,    8,
-       10,   10,    9,   23,   21,    0,    4,    0,    1,   17,
-        3,    3,    2,   24,   24,   22,    5,   22,   22,   22,
-       18,   15,   22,   18,   16,   13,   22,   12,   22,   22,
-        8,    9,    0,    0,    3,   17,   22,   20,   19,   13,
-       22,    0,    3,    3,   22,    7,   14,    0
-    } ;
-
-static yyconst flex_int32_t yy_ec[256] =
-    {   0,
-        1,    1,    1,    1,    1,    1,    1,    1,    2,    3,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    2,    4,    5,    6,    1,    1,    7,    1,    1,
-        1,    1,    8,    1,    8,    9,    1,   10,   10,   10,
-       10,   10,   10,   10,   10,   10,   10,    1,   11,   12,
-       13,   12,    1,    1,   14,   14,   14,   14,   15,   14,
-       14,   14,   14,   14,   14,   14,   14,   14,   14,   14,
-       14,   14,   14,   14,   14,   14,   14,   14,   14,   14,
-        1,   16,    1,    1,   17,    1,   18,   14,   14,   19,
-
-       20,   21,   22,   23,   14,   14,   14,   24,   14,   25,
-       26,   27,   14,   28,   29,   30,   31,   14,   14,   32,
-       33,   14,    1,   34,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1
-    } ;
-
-static yyconst flex_int32_t yy_meta[35] =
-    {   0,
-        1,    1,    2,    1,    1,    1,    1,    1,    3,    4,
-        1,    1,    1,    4,    4,    1,    4,    4,    4,    4,
-        4,    4,    4,    4,    4,    4,    4,    4,    4,    4,
-        4,    4,    4,    1
-    } ;
-
-static yyconst flex_int16_t yy_base[94] =
-    {   0,
-        0,    0,  131,  130,   10,   12,  132,  131,   45,    0,
-      153,  158,  150,  158,  138,   75,    0,  143,  139,   72,
-      158,  135,  134,    0,  143,  136,  119,  115,  116,  113,
-      114,  113,  104,   62,  111,   68,  116,  115,  158,  132,
-      158,  158,    0,  131,  158,   79,  158,  127,    0,  158,
-       84,   87,   91,  122,   31,    0,  158,  111,  103,   98,
-        0,    0,   99,  158,    0,   96,  104,    0,   95,   99,
-      120,    0,   34,  107,   76,    0,   82,    0,    0,    0,
-       83,   99,   98,   95,   76,    0,    0,  158,  111,  115,
-      117,   94,   84
-
-    } ;
-
-static yyconst flex_int16_t yy_def[94] =
-    {   0,
-       88,    1,    1,    1,    1,    1,    1,    1,   88,    9,
-       88,   88,   88,   88,   88,   89,   90,   88,   88,   91,
-       88,   88,   88,   92,   88,   91,   92,   92,   92,   92,
-       92,   92,   88,   92,   92,   92,   92,   92,   88,   88,
-       88,   88,   93,   88,   88,   89,   88,   88,   90,   88,
-       88,   88,   91,   91,   91,   92,   88,   92,   92,   92,
-       92,   92,   92,   88,   92,   92,   92,   92,   92,   92,
-       88,   93,   88,   88,   91,   92,   92,   92,   92,   92,
-       92,   88,   88,   88,   92,   92,   92,    0,   88,   88,
-       88,   88,   88
-
-    } ;
-
-static yyconst flex_int16_t yy_nxt[193] =
-    {   0,
-       12,   13,   14,   15,   16,   17,   18,   12,   19,   20,
-       21,   22,   23,   24,   24,   25,   26,   27,   24,   24,
-       24,   28,   24,   24,   29,   30,   24,   24,   24,   31,
-       24,   32,   24,   33,   35,   36,   35,   36,   74,   88,
-       75,   82,   37,   83,   37,   39,   40,   41,   39,   39,
-       39,   39,   39,   39,   39,   42,   39,   39,   43,   43,
-       39,   39,   43,   43,   43,   43,   43,   43,   43,   43,
-       43,   43,   43,   43,   43,   43,   43,   43,   39,   47,
-       52,   53,   65,   47,   88,   75,   55,   72,   67,   61,
-       48,   55,   68,   51,   48,   61,   51,   56,   73,   52,
-
-       53,   73,   87,   73,   84,   55,   73,   83,   83,   86,
-       55,   46,   85,   46,   46,   49,   84,   49,   49,   54,
-       54,   71,   81,   68,   80,   78,   79,   78,   77,   76,
-       88,   46,   44,   71,   70,   69,   66,   64,   63,   62,
-       61,   60,   59,   58,   88,   57,   45,   45,   51,   50,
-       45,   44,   88,   38,   38,   34,   34,   11,   88,   88,
-       88,   88,   88,   88,   88,   88,   88,   88,   88,   88,
-       88,   88,   88,   88,   88,   88,   88,   88,   88,   88,
-       88,   88,   88,   88,   88,   88,   88,   88,   88,   88,
-       88,   88
-
-    } ;
-
-static yyconst flex_int16_t yy_chk[193] =
-    {   0,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    5,    5,    6,    6,   55,   55,
-       55,   73,    5,   73,    6,    9,    9,    9,    9,    9,
-        9,    9,    9,    9,    9,    9,    9,    9,    9,    9,
-        9,    9,    9,    9,    9,    9,    9,    9,    9,    9,
-        9,    9,    9,    9,    9,    9,    9,    9,    9,   16,
-       20,   20,   34,   46,   75,   75,   20,   93,   36,   34,
-       16,   20,   36,   51,   46,   36,   52,   92,   51,   53,
-
-       53,   52,   85,   51,   84,   53,   52,   83,   82,   81,
-       53,   89,   77,   89,   89,   90,   74,   90,   90,   91,
-       91,   71,   70,   69,   67,   66,   63,   60,   59,   58,
-       54,   48,   44,   40,   38,   37,   35,   33,   32,   31,
-       30,   29,   28,   27,   26,   25,   23,   22,   19,   18,
-       15,   13,   11,    8,    7,    4,    3,   88,   88,   88,
-       88,   88,   88,   88,   88,   88,   88,   88,   88,   88,
-       88,   88,   88,   88,   88,   88,   88,   88,   88,   88,
-       88,   88,   88,   88,   88,   88,   88,   88,   88,   88,
-       88,   88
-
-    } ;
-
-/* The intent behind this definition is that it'll catch
- * any uses of REJECT which flex missed.
- */
-#define REJECT reject_used_but_not_detected
-#define yymore() yymore_used_but_not_detected
-#define YY_MORE_ADJ 0
-#define YY_RESTORE_YY_MORE_OFFSET
-#line 1 "scanner.l"
-/*
- *
- *                This source code is part of
- *
- *                 G   R   O   M   A   C   S
- *
- *          GROningen MAchine for Chemical Simulations
- *
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
- * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
- * Copyright (c) 2001-2009, The GROMACS development team,
- * check out http://www.gromacs.org for more information.
-
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * If you want to redistribute modifications, please consider that
- * scientific software is very special. Version control is crucial -
- * bugs must be traceable. We will be happy to consider code for
- * inclusion in the official distribution, but derived work must not
- * be called official GROMACS. Details are found in the README & COPYING
- * files - if they are missing, get the official version at www.gromacs.org.
- *
- * To help us fund GROMACS development, we humbly ask that you cite
- * the papers on the package - you can find them in the top README file.
- *
- * For more info, check our website at http://www.gromacs.org
- */
-/*! \cond \internal \file scanner.l
- * \brief
- * Tokenizer for the selection language.
- * \endcond
- */
-/*! \internal \file scanner.c
- * \brief
- * Generated (from scanner.l by Flex) tokenizer for the selection language.
- */
-#line 41 "scanner.l"
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <string2.h>
-
-#include "parser.h"
-#include "scanner.h"
-#include "scanner_internal.h"
-
-/* This macro is here to make the actions a bit shorter, since nearly every
- * action needs this call. */
-#define ADD_TOKEN _gmx_sel_lexer_add_token(yytext, yyleng, state)
-
-#define YY_NO_UNISTD_H 1
-
-
-
-
-#line 571 "scanner.c"
-
-#define INITIAL 0
-#define matchof 1
-#define matchbool 2
-#define cmdstart 3
-#define help 4
-
-#ifndef YY_NO_UNISTD_H
-/* Special case for "unistd.h", since it is non-ANSI. We include it way
- * down here because we want the user's section 1 to have been scanned first.
- * The user has a chance to override it with an option.
- */
-#include <unistd.h>
-#endif
-
-#ifndef YY_EXTRA_TYPE
-#define YY_EXTRA_TYPE void *
-#endif
-
-/* Holds the entire state of the reentrant scanner. */
-struct yyguts_t
-    {
-
-    /* User-defined. Not touched by flex. */
-    YY_EXTRA_TYPE yyextra_r;
-
-    /* The rest are the same as the globals declared in the non-reentrant scanner. */
-    FILE *yyin_r, *yyout_r;
-    size_t yy_buffer_stack_top; /**< index of top of stack. */
-    size_t yy_buffer_stack_max; /**< capacity of stack. */
-    YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */
-    char yy_hold_char;
-    int yy_n_chars;
-    int yyleng_r;
-    char *yy_c_buf_p;
-    int yy_init;
-    int yy_start;
-    int yy_did_buffer_switch_on_eof;
-    int yy_start_stack_ptr;
-    int yy_start_stack_depth;
-    int *yy_start_stack;
-    yy_state_type yy_last_accepting_state;
-    char* yy_last_accepting_cpos;
-
-    int yylineno_r;
-    int yy_flex_debug_r;
-
-    char *yytext_r;
-    int yy_more_flag;
-    int yy_more_len;
-
-    }; /* end struct yyguts_t */
-
-static int yy_init_globals (yyscan_t yyscanner );
-
-int _gmx_sel_yylex_init (yyscan_t* scanner);
-
-int _gmx_sel_yylex_init_extra (YY_EXTRA_TYPE user_defined,yyscan_t* scanner);
-
-/* Accessor methods to globals.
-   These are made visible to non-reentrant scanners for convenience. */
-
-int _gmx_sel_yylex_destroy (yyscan_t yyscanner );
-
-int _gmx_sel_yyget_debug (yyscan_t yyscanner );
-
-void _gmx_sel_yyset_debug (int debug_flag ,yyscan_t yyscanner );
-
-YY_EXTRA_TYPE _gmx_sel_yyget_extra (yyscan_t yyscanner );
-
-void _gmx_sel_yyset_extra (YY_EXTRA_TYPE user_defined ,yyscan_t yyscanner );
-
-FILE *_gmx_sel_yyget_in (yyscan_t yyscanner );
-
-void _gmx_sel_yyset_in  (FILE * in_str ,yyscan_t yyscanner );
-
-FILE *_gmx_sel_yyget_out (yyscan_t yyscanner );
-
-void _gmx_sel_yyset_out  (FILE * out_str ,yyscan_t yyscanner );
-
-int _gmx_sel_yyget_leng (yyscan_t yyscanner );
-
-char *_gmx_sel_yyget_text (yyscan_t yyscanner );
-
-int _gmx_sel_yyget_lineno (yyscan_t yyscanner );
-
-void _gmx_sel_yyset_lineno (int line_number ,yyscan_t yyscanner );
-
-/* Macros after this point can all be overridden by user definitions in
- * section 1.
- */
-
-#ifndef YY_SKIP_YYWRAP
-#ifdef __cplusplus
-extern "C" int _gmx_sel_yywrap (yyscan_t yyscanner );
-#else
-extern int _gmx_sel_yywrap (yyscan_t yyscanner );
-#endif
-#endif
-
-    static void yyunput (int c,char *buf_ptr  ,yyscan_t yyscanner);
-    
-#ifndef yytext_ptr
-static void yy_flex_strncpy (char *,yyconst char *,int ,yyscan_t yyscanner);
-#endif
-
-#ifdef YY_NEED_STRLEN
-static int yy_flex_strlen (yyconst char * ,yyscan_t yyscanner);
-#endif
-
-#ifndef YY_NO_INPUT
-
-#ifdef __cplusplus
-static int yyinput (yyscan_t yyscanner );
-#else
-static int input (yyscan_t yyscanner );
-#endif
-
-#endif
-
-/* Amount of stuff to slurp up with each read. */
-#ifndef YY_READ_BUF_SIZE
-#ifdef __ia64__
-/* On IA-64, the buffer size is 16k, not 8k */
-#define YY_READ_BUF_SIZE 16384
-#else
-#define YY_READ_BUF_SIZE 8192
-#endif /* __ia64__ */
-#endif
-
-/* Copy whatever the last rule matched to the standard output. */
-#ifndef ECHO
-/* This used to be an fputs(), but since the string might contain NUL's,
- * we now use fwrite().
- */
-#define ECHO do { if (fwrite( yytext, yyleng, 1, yyout )) {} } while (0)
-#endif
-
-/* Gets input and stuffs it into "buf".  number of characters read, or YY_NULL,
- * is returned in "result".
- */
-#ifndef YY_INPUT
-#define YY_INPUT(buf,result,max_size) \
-       if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
-               { \
-               int c = '*'; \
-               size_t n; \
-               for ( n = 0; n < max_size && \
-                            (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
-                       buf[n] = (char) c; \
-               if ( c == '\n' ) \
-                       buf[n++] = (char) c; \
-               if ( c == EOF && ferror( yyin ) ) \
-                       YY_FATAL_ERROR( "input in flex scanner failed" ); \
-               result = n; \
-               } \
-       else \
-               { \
-               errno=0; \
-               while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \
-                       { \
-                       if( errno != EINTR) \
-                               { \
-                               YY_FATAL_ERROR( "input in flex scanner failed" ); \
-                               break; \
-                               } \
-                       errno=0; \
-                       clearerr(yyin); \
-                       } \
-               }\
-\
-
-#endif
-
-/* No semi-colon after return; correct usage is to write "yyterminate();" -
- * we don't want an extra ';' after the "return" because that will cause
- * some compilers to complain about unreachable statements.
- */
-#ifndef yyterminate
-#define yyterminate() return YY_NULL
-#endif
-
-/* Number of entries by which start-condition stack grows. */
-#ifndef YY_START_STACK_INCR
-#define YY_START_STACK_INCR 25
-#endif
-
-/* Report a fatal error. */
-#ifndef YY_FATAL_ERROR
-#define YY_FATAL_ERROR(msg) yy_fatal_error( msg , yyscanner)
-#endif
-
-/* end tables serialization structures and prototypes */
-
-/* Default declaration of generated scanner - a define so the user can
- * easily add parameters.
- */
-#ifndef YY_DECL
-#define YY_DECL_IS_OURS 1
-
-extern int _gmx_sel_yylex (yyscan_t yyscanner);
-
-#define YY_DECL int _gmx_sel_yylex (yyscan_t yyscanner)
-#endif /* !YY_DECL */
-
-/* Code executed at the beginning of each rule, after yytext and yyleng
- * have been set up.
- */
-#ifndef YY_USER_ACTION
-#define YY_USER_ACTION
-#endif
-
-/* Code executed at the end of each rule. */
-#ifndef YY_BREAK
-#define YY_BREAK break;
-#endif
-
-#define YY_RULE_SETUP \
-       YY_USER_ACTION
-
-/** The main scanner function which does all the work.
- */
-YY_DECL
-{
-       register yy_state_type yy_current_state;
-       register char *yy_cp, *yy_bp;
-       register int yy_act;
-    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
-
-#line 80 "scanner.l"
-
-
-
-    gmx_sel_lexer_t *state = _gmx_sel_yyget_extra(yyscanner);
-    int              retval;
-    /* Return a token if one is pending */
-    retval = _gmx_sel_lexer_process_pending(yylval, state);
-    if (retval != 0)
-    {
-        return retval;
-    }
-    /* Handle the start conditions for 'of' matching */
-    if (state->bMatchOf)
-    {
-        BEGIN(matchof);
-        state->bMatchOf = FALSE;
-    }
-    else if (state->bMatchBool)
-    {
-        BEGIN(matchbool);
-        state->bMatchBool = FALSE;
-    }
-    else if (state->bCmdStart)
-    {
-        BEGIN(cmdstart);
-    }
-    else if (YYSTATE != help)
-    {
-        BEGIN(0);
-    }
-
-
-#line 834 "scanner.c"
-
-       if ( !yyg->yy_init )
-               {
-               yyg->yy_init = 1;
-
-#ifdef YY_USER_INIT
-               YY_USER_INIT;
-#endif
-
-               if ( ! yyg->yy_start )
-                       yyg->yy_start = 1;      /* first start state */
-
-               if ( ! yyin )
-                       yyin = stdin;
-
-               if ( ! yyout )
-                       yyout = stdout;
-
-               if ( ! YY_CURRENT_BUFFER ) {
-                       _gmx_sel_yyensure_buffer_stack (yyscanner);
-                       YY_CURRENT_BUFFER_LVALUE =
-                               _gmx_sel_yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner);
-               }
-
-               _gmx_sel_yy_load_buffer_state(yyscanner );
-               }
-
-       while ( 1 )             /* loops until end-of-file is reached */
-               {
-               yy_cp = yyg->yy_c_buf_p;
-
-               /* Support of yytext. */
-               *yy_cp = yyg->yy_hold_char;
-
-               /* yy_bp points to the position in yy_ch_buf of the start of
-                * the current run.
-                */
-               yy_bp = yy_cp;
-
-               yy_current_state = yyg->yy_start;
-yy_match:
-               do
-                       {
-                       register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
-                       if ( yy_accept[yy_current_state] )
-                               {
-                               yyg->yy_last_accepting_state = yy_current_state;
-                               yyg->yy_last_accepting_cpos = yy_cp;
-                               }
-                       while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
-                               {
-                               yy_current_state = (int) yy_def[yy_current_state];
-                               if ( yy_current_state >= 89 )
-                                       yy_c = yy_meta[(unsigned int) yy_c];
-                               }
-                       yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
-                       ++yy_cp;
-                       }
-               while ( yy_current_state != 88 );
-               yy_cp = yyg->yy_last_accepting_cpos;
-               yy_current_state = yyg->yy_last_accepting_state;
-
-yy_find_action:
-               yy_act = yy_accept[yy_current_state];
-
-               YY_DO_BEFORE_ACTION;
-
-do_action:     /* This label is used only to access EOF actions. */
-
-               switch ( yy_act )
-       { /* beginning of action switch */
-                       case 0: /* must back up */
-                       /* undo the effects of YY_DO_BEFORE_ACTION */
-                       *yy_cp = yyg->yy_hold_char;
-                       yy_cp = yyg->yy_last_accepting_cpos;
-                       yy_current_state = yyg->yy_last_accepting_state;
-                       goto yy_find_action;
-
-case 1:
-YY_RULE_SETUP
-#line 112 "scanner.l"
-
-       YY_BREAK
-case 2:
-YY_RULE_SETUP
-#line 113 "scanner.l"
-{ yylval->i   = strtol(yytext, NULL, 10);    ADD_TOKEN; return TOK_INT; }
-       YY_BREAK
-case 3:
-YY_RULE_SETUP
-#line 114 "scanner.l"
-{ yylval->r   = strtod(yytext, NULL);        ADD_TOKEN; return TOK_REAL; }
-       YY_BREAK
-case 4:
-YY_RULE_SETUP
-#line 115 "scanner.l"
-{ yylval->str = gmx_strndup(yytext+1, yyleng-2); ADD_TOKEN; return STR;  }
-       YY_BREAK
-case 5:
-/* rule 5 can match eol */
-YY_RULE_SETUP
-#line 117 "scanner.l"
-{ _gmx_sel_lexer_add_token(" ", 1, state); }
-       YY_BREAK
-case 6:
-/* rule 6 can match eol */
-YY_RULE_SETUP
-#line 118 "scanner.l"
-{
-                    if (yytext[0] == ';' || state->bInteractive)
-                    {
-                        rtrim(state->pselstr);
-                        return CMD_SEP;
-                    }
-                    else
-                    {
-                        _gmx_sel_lexer_add_token(" ", 1, state);
-                    }
-                }
-       YY_BREAK
-case 7:
-YY_RULE_SETUP
-#line 130 "scanner.l"
-{ BEGIN(help); return HELP; }
-       YY_BREAK
-
-case 8:
-YY_RULE_SETUP
-#line 132 "scanner.l"
-
-       YY_BREAK
-case 9:
-YY_RULE_SETUP
-#line 133 "scanner.l"
-{ yylval->str = gmx_strndup(yytext, yyleng); return HELP_TOPIC; }
-       YY_BREAK
-case 10:
-/* rule 10 can match eol */
-YY_RULE_SETUP
-#line 134 "scanner.l"
-{ return CMD_SEP; }
-       YY_BREAK
-case 11:
-YY_RULE_SETUP
-#line 135 "scanner.l"
-{ return INVALID; }
-       YY_BREAK
-
-
-case 12:
-YY_RULE_SETUP
-#line 139 "scanner.l"
-{ ADD_TOKEN; yylval->i = 1; return TOK_INT; }
-       YY_BREAK
-case 13:
-YY_RULE_SETUP
-#line 140 "scanner.l"
-{ ADD_TOKEN; yylval->i = 0; return TOK_INT; }
-       YY_BREAK
-
-case 14:
-YY_RULE_SETUP
-#line 142 "scanner.l"
-{ ADD_TOKEN; return GROUP; }
-       YY_BREAK
-case 15:
-YY_RULE_SETUP
-#line 143 "scanner.l"
-{ ADD_TOKEN; return TO; }
-       YY_BREAK
-case 16:
-YY_RULE_SETUP
-#line 144 "scanner.l"
-{ ADD_TOKEN; BEGIN(0); return OF; }
-       YY_BREAK
-case 17:
-YY_RULE_SETUP
-#line 145 "scanner.l"
-{ ADD_TOKEN; return AND; }
-       YY_BREAK
-case 18:
-YY_RULE_SETUP
-#line 146 "scanner.l"
-{ ADD_TOKEN; return OR; }
-       YY_BREAK
-case 19:
-YY_RULE_SETUP
-#line 147 "scanner.l"
-{ ADD_TOKEN; return XOR; }
-       YY_BREAK
-case 20:
-YY_RULE_SETUP
-#line 148 "scanner.l"
-{ ADD_TOKEN; return NOT; }
-       YY_BREAK
-case 21:
-YY_RULE_SETUP
-#line 149 "scanner.l"
-{ yylval->str = gmx_strndup(yytext, yyleng); ADD_TOKEN; return CMP_OP; }
-       YY_BREAK
-case 22:
-YY_RULE_SETUP
-#line 151 "scanner.l"
-{ return _gmx_sel_lexer_process_identifier(yylval, yytext, yyleng, state); }
-       YY_BREAK
-case 23:
-YY_RULE_SETUP
-#line 153 "scanner.l"
-{ _gmx_sel_lexer_add_token(" ", 1, state); }
-       YY_BREAK
-case 24:
-YY_RULE_SETUP
-#line 154 "scanner.l"
-{ yylval->str = gmx_strndup(yytext, yyleng); ADD_TOKEN; return STR; }
-       YY_BREAK
-case 25:
-YY_RULE_SETUP
-#line 155 "scanner.l"
-{ ADD_TOKEN; return yytext[0]; }
-       YY_BREAK
-case 26:
-YY_RULE_SETUP
-#line 156 "scanner.l"
-YY_FATAL_ERROR( "flex scanner jammed" );
-       YY_BREAK
-#line 1060 "scanner.c"
-case YY_STATE_EOF(INITIAL):
-case YY_STATE_EOF(matchof):
-case YY_STATE_EOF(matchbool):
-case YY_STATE_EOF(cmdstart):
-case YY_STATE_EOF(help):
-       yyterminate();
-
-       case YY_END_OF_BUFFER:
-               {
-               /* Amount of text matched not including the EOB char. */
-               int yy_amount_of_matched_text = (int) (yy_cp - yyg->yytext_ptr) - 1;
-
-               /* Undo the effects of YY_DO_BEFORE_ACTION. */
-               *yy_cp = yyg->yy_hold_char;
-               YY_RESTORE_YY_MORE_OFFSET
-
-               if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
-                       {
-                       /* We're scanning a new file or input source.  It's
-                        * possible that this happened because the user
-                        * just pointed yyin at a new source and called
-                        * _gmx_sel_yylex().  If so, then we have to assure
-                        * consistency between YY_CURRENT_BUFFER and our
-                        * globals.  Here is the right place to do so, because
-                        * this is the first action (other than possibly a
-                        * back-up) that will match for the new input source.
-                        */
-                       yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
-                       YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin;
-                       YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
-                       }
-
-               /* Note that here we test for yy_c_buf_p "<=" to the position
-                * of the first EOB in the buffer, since yy_c_buf_p will
-                * already have been incremented past the NUL character
-                * (since all states make transitions on EOB to the
-                * end-of-buffer state).  Contrast this with the test
-                * in input().
-                */
-               if ( yyg->yy_c_buf_p <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] )
-                       { /* This was really a NUL. */
-                       yy_state_type yy_next_state;
-
-                       yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text;
-
-                       yy_current_state = yy_get_previous_state( yyscanner );
-
-                       /* Okay, we're now positioned to make the NUL
-                        * transition.  We couldn't have
-                        * yy_get_previous_state() go ahead and do it
-                        * for us because it doesn't know how to deal
-                        * with the possibility of jamming (and we don't
-                        * want to build jamming into it because then it
-                        * will run more slowly).
-                        */
-
-                       yy_next_state = yy_try_NUL_trans( yy_current_state , yyscanner);
-
-                       yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
-
-                       if ( yy_next_state )
-                               {
-                               /* Consume the NUL. */
-                               yy_cp = ++yyg->yy_c_buf_p;
-                               yy_current_state = yy_next_state;
-                               goto yy_match;
-                               }
-
-                       else
-                               {
-                               yy_cp = yyg->yy_last_accepting_cpos;
-                               yy_current_state = yyg->yy_last_accepting_state;
-                               goto yy_find_action;
-                               }
-                       }
-
-               else switch ( yy_get_next_buffer( yyscanner ) )
-                       {
-                       case EOB_ACT_END_OF_FILE:
-                               {
-                               yyg->yy_did_buffer_switch_on_eof = 0;
-
-                               if ( _gmx_sel_yywrap(yyscanner ) )
-                                       {
-                                       /* Note: because we've taken care in
-                                        * yy_get_next_buffer() to have set up
-                                        * yytext, we can now set up
-                                        * yy_c_buf_p so that if some total
-                                        * hoser (like flex itself) wants to
-                                        * call the scanner after we return the
-                                        * YY_NULL, it'll still work - another
-                                        * YY_NULL will get returned.
-                                        */
-                                       yyg->yy_c_buf_p = yyg->yytext_ptr + YY_MORE_ADJ;
-
-                                       yy_act = YY_STATE_EOF(YY_START);
-                                       goto do_action;
-                                       }
-
-                               else
-                                       {
-                                       if ( ! yyg->yy_did_buffer_switch_on_eof )
-                                               YY_NEW_FILE;
-                                       }
-                               break;
-                               }
-
-                       case EOB_ACT_CONTINUE_SCAN:
-                               yyg->yy_c_buf_p =
-                                       yyg->yytext_ptr + yy_amount_of_matched_text;
-
-                               yy_current_state = yy_get_previous_state( yyscanner );
-
-                               yy_cp = yyg->yy_c_buf_p;
-                               yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
-                               goto yy_match;
-
-                       case EOB_ACT_LAST_MATCH:
-                               yyg->yy_c_buf_p =
-                               &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars];
-
-                               yy_current_state = yy_get_previous_state( yyscanner );
-
-                               yy_cp = yyg->yy_c_buf_p;
-                               yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
-                               goto yy_find_action;
-                       }
-               break;
-               }
-
-       default:
-               YY_FATAL_ERROR(
-                       "fatal flex scanner internal error--no action found" );
-       } /* end of action switch */
-               } /* end of scanning one token */
-} /* end of _gmx_sel_yylex */
-
-/* yy_get_next_buffer - try to read in a new buffer
- *
- * Returns a code representing an action:
- *     EOB_ACT_LAST_MATCH -
- *     EOB_ACT_CONTINUE_SCAN - continue scanning from current position
- *     EOB_ACT_END_OF_FILE - end of file
- */
-static int yy_get_next_buffer (yyscan_t yyscanner)
-{
-    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
-       register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
-       register char *source = yyg->yytext_ptr;
-       register int number_to_move, i;
-       int ret_val;
-
-       if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] )
-               YY_FATAL_ERROR(
-               "fatal flex scanner internal error--end of buffer missed" );
-
-       if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
-               { /* Don't try to fill the buffer, so this is an EOF. */
-               if ( yyg->yy_c_buf_p - yyg->yytext_ptr - YY_MORE_ADJ == 1 )
-                       {
-                       /* We matched a single character, the EOB, so
-                        * treat this as a final EOF.
-                        */
-                       return EOB_ACT_END_OF_FILE;
-                       }
-
-               else
-                       {
-                       /* We matched some text prior to the EOB, first
-                        * process it.
-                        */
-                       return EOB_ACT_LAST_MATCH;
-                       }
-               }
-
-       /* Try to read more data. */
-
-       /* First move last chars to start of buffer. */
-       number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr) - 1;
-
-       for ( i = 0; i < number_to_move; ++i )
-               *(dest++) = *(source++);
-
-       if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
-               /* don't do the read, it's not guaranteed to return an EOF,
-                * just force an EOF
-                */
-               YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars = 0;
-
-       else
-               {
-                       int num_to_read =
-                       YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
-
-               while ( num_to_read <= 0 )
-                       { /* Not enough room in the buffer - grow it. */
-
-                       /* just a shorter name for the current buffer */
-                       YY_BUFFER_STATE b = YY_CURRENT_BUFFER;
-
-                       int yy_c_buf_p_offset =
-                               (int) (yyg->yy_c_buf_p - b->yy_ch_buf);
-
-                       if ( b->yy_is_our_buffer )
-                               {
-                               int new_size = b->yy_buf_size * 2;
-
-                               if ( new_size <= 0 )
-                                       b->yy_buf_size += b->yy_buf_size / 8;
-                               else
-                                       b->yy_buf_size *= 2;
-
-                               b->yy_ch_buf = (char *)
-                                       /* Include room in for 2 EOB chars. */
-                                       _gmx_sel_yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ,yyscanner );
-                               }
-                       else
-                               /* Can't grow it, we don't own it. */
-                               b->yy_ch_buf = 0;
-
-                       if ( ! b->yy_ch_buf )
-                               YY_FATAL_ERROR(
-                               "fatal error - scanner input buffer overflow" );
-
-                       yyg->yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset];
-
-                       num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
-                                               number_to_move - 1;
-
-                       }
-
-               if ( num_to_read > YY_READ_BUF_SIZE )
-                       num_to_read = YY_READ_BUF_SIZE;
-
-               /* Read in more data. */
-               YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
-                       yyg->yy_n_chars, (size_t) num_to_read );
-
-               YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
-               }
-
-       if ( yyg->yy_n_chars == 0 )
-               {
-               if ( number_to_move == YY_MORE_ADJ )
-                       {
-                       ret_val = EOB_ACT_END_OF_FILE;
-                       _gmx_sel_yyrestart(yyin  ,yyscanner);
-                       }
-
-               else
-                       {
-                       ret_val = EOB_ACT_LAST_MATCH;
-                       YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
-                               YY_BUFFER_EOF_PENDING;
-                       }
-               }
-
-       else
-               ret_val = EOB_ACT_CONTINUE_SCAN;
-
-       if ((yy_size_t) (yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
-               /* Extend the array by 50%, plus the number we really need. */
-               yy_size_t new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1);
-               YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) _gmx_sel_yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ,yyscanner );
-               if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
-                       YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
-       }
-
-       yyg->yy_n_chars += number_to_move;
-       YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] = YY_END_OF_BUFFER_CHAR;
-       YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR;
-
-       yyg->yytext_ptr = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
-
-       return ret_val;
-}
-
-/* yy_get_previous_state - get the state just before the EOB char was reached */
-
-    static yy_state_type yy_get_previous_state (yyscan_t yyscanner)
-{
-       register yy_state_type yy_current_state;
-       register char *yy_cp;
-    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
-
-       yy_current_state = yyg->yy_start;
-
-       for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp )
-               {
-               register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
-               if ( yy_accept[yy_current_state] )
-                       {
-                       yyg->yy_last_accepting_state = yy_current_state;
-                       yyg->yy_last_accepting_cpos = yy_cp;
-                       }
-               while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
-                       {
-                       yy_current_state = (int) yy_def[yy_current_state];
-                       if ( yy_current_state >= 89 )
-                               yy_c = yy_meta[(unsigned int) yy_c];
-                       }
-               yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
-               }
-
-       return yy_current_state;
-}
-
-/* yy_try_NUL_trans - try to make a transition on the NUL character
- *
- * synopsis
- *     next_state = yy_try_NUL_trans( current_state );
- */
-    static yy_state_type yy_try_NUL_trans  (yy_state_type yy_current_state , yyscan_t yyscanner)
-{
-       register int yy_is_jam;
-    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */
-       register char *yy_cp = yyg->yy_c_buf_p;
-
-       register YY_CHAR yy_c = 1;
-       if ( yy_accept[yy_current_state] )
-               {
-               yyg->yy_last_accepting_state = yy_current_state;
-               yyg->yy_last_accepting_cpos = yy_cp;
-               }
-       while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
-               {
-               yy_current_state = (int) yy_def[yy_current_state];
-               if ( yy_current_state >= 89 )
-                       yy_c = yy_meta[(unsigned int) yy_c];
-               }
-       yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
-       yy_is_jam = (yy_current_state == 88);
-
-       return yy_is_jam ? 0 : yy_current_state;
-}
-
-    static void yyunput (int c, register char * yy_bp , yyscan_t yyscanner)
-{
-       register char *yy_cp;
-    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
-
-    yy_cp = yyg->yy_c_buf_p;
-
-       /* undo effects of setting up yytext */
-       *yy_cp = yyg->yy_hold_char;
-
-       if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
-               { /* need to shift things up to make room */
-               /* +2 for EOB chars. */
-               register int number_to_move = yyg->yy_n_chars + 2;
-               register char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[
-                                       YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2];
-               register char *source =
-                               &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move];
-
-               while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
-                       *--dest = *--source;
-
-               yy_cp += (int) (dest - source);
-               yy_bp += (int) (dest - source);
-               YY_CURRENT_BUFFER_LVALUE->yy_n_chars =
-                       yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_buf_size;
-
-               if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
-                       YY_FATAL_ERROR( "flex scanner push-back overflow" );
-               }
-
-       *--yy_cp = (char) c;
-
-       yyg->yytext_ptr = yy_bp;
-       yyg->yy_hold_char = *yy_cp;
-       yyg->yy_c_buf_p = yy_cp;
-}
-
-#ifndef YY_NO_INPUT
-#ifdef __cplusplus
-    static int yyinput (yyscan_t yyscanner)
-#else
-    static int input  (yyscan_t yyscanner)
-#endif
-
-{
-       int c;
-    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
-
-       *yyg->yy_c_buf_p = yyg->yy_hold_char;
-
-       if ( *yyg->yy_c_buf_p == YY_END_OF_BUFFER_CHAR )
-               {
-               /* yy_c_buf_p now points to the character we want to return.
-                * If this occurs *before* the EOB characters, then it's a
-                * valid NUL; if not, then we've hit the end of the buffer.
-                */
-               if ( yyg->yy_c_buf_p < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] )
-                       /* This was really a NUL. */
-                       *yyg->yy_c_buf_p = '\0';
-
-               else
-                       { /* need more input */
-                       int offset = yyg->yy_c_buf_p - yyg->yytext_ptr;
-                       ++yyg->yy_c_buf_p;
-
-                       switch ( yy_get_next_buffer( yyscanner ) )
-                               {
-                               case EOB_ACT_LAST_MATCH:
-                                       /* This happens because yy_g_n_b()
-                                        * sees that we've accumulated a
-                                        * token and flags that we need to
-                                        * try matching the token before
-                                        * proceeding.  But for input(),
-                                        * there's no matching to consider.
-                                        * So convert the EOB_ACT_LAST_MATCH
-                                        * to EOB_ACT_END_OF_FILE.
-                                        */
-
-                                       /* Reset buffer status. */
-                                       _gmx_sel_yyrestart(yyin ,yyscanner);
-
-                                       /*FALLTHROUGH*/
-
-                               case EOB_ACT_END_OF_FILE:
-                                       {
-                                       if ( _gmx_sel_yywrap(yyscanner ) )
-                                               return EOF;
-
-                                       if ( ! yyg->yy_did_buffer_switch_on_eof )
-                                               YY_NEW_FILE;
-#ifdef __cplusplus
-                                       return yyinput(yyscanner);
-#else
-                                       return input(yyscanner);
-#endif
-                                       }
-
-                               case EOB_ACT_CONTINUE_SCAN:
-                                       yyg->yy_c_buf_p = yyg->yytext_ptr + offset;
-                                       break;
-                               }
-                       }
-               }
-
-       c = *(unsigned char *) yyg->yy_c_buf_p; /* cast for 8-bit char's */
-       *yyg->yy_c_buf_p = '\0';        /* preserve yytext */
-       yyg->yy_hold_char = *++yyg->yy_c_buf_p;
-
-       return c;
-}
-#endif /* ifndef YY_NO_INPUT */
-
-/** Immediately switch to a different input stream.
- * @param input_file A readable stream.
- * @param yyscanner The scanner object.
- * @note This function does not reset the start condition to @c INITIAL .
- */
-    void _gmx_sel_yyrestart  (FILE * input_file , yyscan_t yyscanner)
-{
-    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
-
-       if ( ! YY_CURRENT_BUFFER ){
-        _gmx_sel_yyensure_buffer_stack (yyscanner);
-               YY_CURRENT_BUFFER_LVALUE =
-            _gmx_sel_yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner);
-       }
-
-       _gmx_sel_yy_init_buffer(YY_CURRENT_BUFFER,input_file ,yyscanner);
-       _gmx_sel_yy_load_buffer_state(yyscanner );
-}
-
-/** Switch to a different input buffer.
- * @param new_buffer The new input buffer.
- * @param yyscanner The scanner object.
- */
-    void _gmx_sel_yy_switch_to_buffer  (YY_BUFFER_STATE  new_buffer , yyscan_t yyscanner)
-{
-    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
-
-       /* TODO. We should be able to replace this entire function body
-        * with
-        *              _gmx_sel_yypop_buffer_state();
-        *              _gmx_sel_yypush_buffer_state(new_buffer);
-     */
-       _gmx_sel_yyensure_buffer_stack (yyscanner);
-       if ( YY_CURRENT_BUFFER == new_buffer )
-               return;
-
-       if ( YY_CURRENT_BUFFER )
-               {
-               /* Flush out information for old buffer. */
-               *yyg->yy_c_buf_p = yyg->yy_hold_char;
-               YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p;
-               YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
-               }
-
-       YY_CURRENT_BUFFER_LVALUE = new_buffer;
-       _gmx_sel_yy_load_buffer_state(yyscanner );
-
-       /* We don't actually know whether we did this switch during
-        * EOF (_gmx_sel_yywrap()) processing, but the only time this flag
-        * is looked at is after _gmx_sel_yywrap() is called, so it's safe
-        * to go ahead and always set it.
-        */
-       yyg->yy_did_buffer_switch_on_eof = 1;
-}
-
-static void _gmx_sel_yy_load_buffer_state  (yyscan_t yyscanner)
-{
-    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
-       yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
-       yyg->yytext_ptr = yyg->yy_c_buf_p = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
-       yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
-       yyg->yy_hold_char = *yyg->yy_c_buf_p;
-}
-
-/** Allocate and initialize an input buffer state.
- * @param file A readable stream.
- * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
- * @param yyscanner The scanner object.
- * @return the allocated buffer state.
- */
-    YY_BUFFER_STATE _gmx_sel_yy_create_buffer  (FILE * file, int  size , yyscan_t yyscanner)
-{
-       YY_BUFFER_STATE b;
-    
-       b = (YY_BUFFER_STATE) _gmx_sel_yyalloc(sizeof( struct yy_buffer_state ) ,yyscanner );
-       if ( ! b )
-               YY_FATAL_ERROR( "out of dynamic memory in _gmx_sel_yy_create_buffer()" );
-
-       b->yy_buf_size = size;
-
-       /* yy_ch_buf has to be 2 characters longer than the size given because
-        * we need to put in 2 end-of-buffer characters.
-        */
-       b->yy_ch_buf = (char *) _gmx_sel_yyalloc(b->yy_buf_size + 2 ,yyscanner );
-       if ( ! b->yy_ch_buf )
-               YY_FATAL_ERROR( "out of dynamic memory in _gmx_sel_yy_create_buffer()" );
-
-       b->yy_is_our_buffer = 1;
-
-       _gmx_sel_yy_init_buffer(b,file ,yyscanner);
-
-       return b;
-}
-
-/** Destroy the buffer.
- * @param b a buffer created with _gmx_sel_yy_create_buffer()
- * @param yyscanner The scanner object.
- */
-    void _gmx_sel_yy_delete_buffer (YY_BUFFER_STATE  b , yyscan_t yyscanner)
-{
-    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
-
-       if ( ! b )
-               return;
-
-       if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
-               YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
-
-       if ( b->yy_is_our_buffer )
-               _gmx_sel_yyfree((void *) b->yy_ch_buf ,yyscanner );
-
-       _gmx_sel_yyfree((void *) b ,yyscanner );
-}
-
-/* Initializes or reinitializes a buffer.
- * This function is sometimes called more than once on the same buffer,
- * such as during a _gmx_sel_yyrestart() or at EOF.
- */
-    static void _gmx_sel_yy_init_buffer  (YY_BUFFER_STATE  b, FILE * file , yyscan_t yyscanner)
-
-{
-       int oerrno = errno;
-    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
-
-       _gmx_sel_yy_flush_buffer(b ,yyscanner);
-
-       b->yy_input_file = file;
-       b->yy_fill_buffer = 1;
-
-    /* If b is the current buffer, then _gmx_sel_yy_init_buffer was _probably_
-     * called from _gmx_sel_yyrestart() or through yy_get_next_buffer.
-     * In that case, we don't want to reset the lineno or column.
-     */
-    if (b != YY_CURRENT_BUFFER){
-        b->yy_bs_lineno = 1;
-        b->yy_bs_column = 0;
-    }
-
-        b->yy_is_interactive = 0;
-    
-       errno = oerrno;
-}
-
-/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
- * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
- * @param yyscanner The scanner object.
- */
-    void _gmx_sel_yy_flush_buffer (YY_BUFFER_STATE  b , yyscan_t yyscanner)
-{
-    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
-       if ( ! b )
-               return;
-
-       b->yy_n_chars = 0;
-
-       /* We always need two end-of-buffer characters.  The first causes
-        * a transition to the end-of-buffer state.  The second causes
-        * a jam in that state.
-        */
-       b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
-       b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
-
-       b->yy_buf_pos = &b->yy_ch_buf[0];
-
-       b->yy_at_bol = 1;
-       b->yy_buffer_status = YY_BUFFER_NEW;
-
-       if ( b == YY_CURRENT_BUFFER )
-               _gmx_sel_yy_load_buffer_state(yyscanner );
-}
-
-/** Pushes the new state onto the stack. The new state becomes
- *  the current state. This function will allocate the stack
- *  if necessary.
- *  @param new_buffer The new state.
- *  @param yyscanner The scanner object.
- */
-void _gmx_sel_yypush_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner)
-{
-    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
-       if (new_buffer == NULL)
-               return;
-
-       _gmx_sel_yyensure_buffer_stack(yyscanner);
-
-       /* This block is copied from _gmx_sel_yy_switch_to_buffer. */
-       if ( YY_CURRENT_BUFFER )
-               {
-               /* Flush out information for old buffer. */
-               *yyg->yy_c_buf_p = yyg->yy_hold_char;
-               YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p;
-               YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
-               }
-
-       /* Only push if top exists. Otherwise, replace top. */
-       if (YY_CURRENT_BUFFER)
-               yyg->yy_buffer_stack_top++;
-       YY_CURRENT_BUFFER_LVALUE = new_buffer;
-
-       /* copied from _gmx_sel_yy_switch_to_buffer. */
-       _gmx_sel_yy_load_buffer_state(yyscanner );
-       yyg->yy_did_buffer_switch_on_eof = 1;
-}
-
-/** Removes and deletes the top of the stack, if present.
- *  The next element becomes the new top.
- *  @param yyscanner The scanner object.
- */
-void _gmx_sel_yypop_buffer_state (yyscan_t yyscanner)
-{
-    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
-       if (!YY_CURRENT_BUFFER)
-               return;
-
-       _gmx_sel_yy_delete_buffer(YY_CURRENT_BUFFER ,yyscanner);
-       YY_CURRENT_BUFFER_LVALUE = NULL;
-       if (yyg->yy_buffer_stack_top > 0)
-               --yyg->yy_buffer_stack_top;
-
-       if (YY_CURRENT_BUFFER) {
-               _gmx_sel_yy_load_buffer_state(yyscanner );
-               yyg->yy_did_buffer_switch_on_eof = 1;
-       }
-}
-
-/* Allocates the stack if it does not exist.
- *  Guarantees space for at least one push.
- */
-static void _gmx_sel_yyensure_buffer_stack (yyscan_t yyscanner)
-{
-       int num_to_alloc;
-    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
-
-       if (!yyg->yy_buffer_stack) {
-
-               /* First allocation is just for 2 elements, since we don't know if this
-                * scanner will even need a stack. We use 2 instead of 1 to avoid an
-                * immediate realloc on the next call.
-         */
-               num_to_alloc = 1;
-               yyg->yy_buffer_stack = (struct yy_buffer_state**)_gmx_sel_yyalloc
-                                                               (num_to_alloc * sizeof(struct yy_buffer_state*)
-                                                               , yyscanner);
-               if ( ! yyg->yy_buffer_stack )
-                       YY_FATAL_ERROR( "out of dynamic memory in _gmx_sel_yyensure_buffer_stack()" );
-                                                                 
-               memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*));
-                               
-               yyg->yy_buffer_stack_max = num_to_alloc;
-               yyg->yy_buffer_stack_top = 0;
-               return;
-       }
-
-       if (yyg->yy_buffer_stack_top >= (yyg->yy_buffer_stack_max) - 1){
-
-               /* Increase the buffer to prepare for a possible push. */
-               int grow_size = 8 /* arbitrary grow size */;
-
-               num_to_alloc = yyg->yy_buffer_stack_max + grow_size;
-               yyg->yy_buffer_stack = (struct yy_buffer_state**)_gmx_sel_yyrealloc
-                                                               (yyg->yy_buffer_stack,
-                                                               num_to_alloc * sizeof(struct yy_buffer_state*)
-                                                               , yyscanner);
-               if ( ! yyg->yy_buffer_stack )
-                       YY_FATAL_ERROR( "out of dynamic memory in _gmx_sel_yyensure_buffer_stack()" );
-
-               /* zero only the new slots.*/
-               memset(yyg->yy_buffer_stack + yyg->yy_buffer_stack_max, 0, grow_size * sizeof(struct yy_buffer_state*));
-               yyg->yy_buffer_stack_max = num_to_alloc;
-       }
-}
-
-/** Setup the input buffer state to scan directly from a user-specified character buffer.
- * @param base the character buffer
- * @param size the size in bytes of the character buffer
- * @param yyscanner The scanner object.
- * @return the newly allocated buffer state object. 
- */
-YY_BUFFER_STATE _gmx_sel_yy_scan_buffer  (char * base, yy_size_t  size , yyscan_t yyscanner)
-{
-       YY_BUFFER_STATE b;
-    
-       if ( size < 2 ||
-            base[size-2] != YY_END_OF_BUFFER_CHAR ||
-            base[size-1] != YY_END_OF_BUFFER_CHAR )
-               /* They forgot to leave room for the EOB's. */
-               return 0;
-
-       b = (YY_BUFFER_STATE) _gmx_sel_yyalloc(sizeof( struct yy_buffer_state ) ,yyscanner );
-       if ( ! b )
-               YY_FATAL_ERROR( "out of dynamic memory in _gmx_sel_yy_scan_buffer()" );
-
-       b->yy_buf_size = size - 2;      /* "- 2" to take care of EOB's */
-       b->yy_buf_pos = b->yy_ch_buf = base;
-       b->yy_is_our_buffer = 0;
-       b->yy_input_file = 0;
-       b->yy_n_chars = b->yy_buf_size;
-       b->yy_is_interactive = 0;
-       b->yy_at_bol = 1;
-       b->yy_fill_buffer = 0;
-       b->yy_buffer_status = YY_BUFFER_NEW;
-
-       _gmx_sel_yy_switch_to_buffer(b ,yyscanner );
-
-       return b;
-}
-
-/** Setup the input buffer state to scan a string. The next call to _gmx_sel_yylex() will
- * scan from a @e copy of @a str.
- * @param yystr a NUL-terminated string to scan
- * @param yyscanner The scanner object.
- * @return the newly allocated buffer state object.
- * @note If you want to scan bytes that may contain NUL values, then use
- *       _gmx_sel_yy_scan_bytes() instead.
- */
-YY_BUFFER_STATE _gmx_sel_yy_scan_string (yyconst char * yystr , yyscan_t yyscanner)
-{
-    
-       return _gmx_sel_yy_scan_bytes(yystr,strlen(yystr) ,yyscanner);
-}
-
-/** Setup the input buffer state to scan the given bytes. The next call to _gmx_sel_yylex() will
- * scan from a @e copy of @a bytes.
- * @param yybytes the byte buffer to scan
- * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes.
- * @param yyscanner The scanner object.
- * @return the newly allocated buffer state object.
- */
-YY_BUFFER_STATE _gmx_sel_yy_scan_bytes  (yyconst char * yybytes, int  _yybytes_len , yyscan_t yyscanner)
-{
-       YY_BUFFER_STATE b;
-       char *buf;
-       yy_size_t n;
-       int i;
-    
-       /* Get memory for full buffer, including space for trailing EOB's. */
-       n = _yybytes_len + 2;
-       buf = (char *) _gmx_sel_yyalloc(n ,yyscanner );
-       if ( ! buf )
-               YY_FATAL_ERROR( "out of dynamic memory in _gmx_sel_yy_scan_bytes()" );
-
-       for ( i = 0; i < _yybytes_len; ++i )
-               buf[i] = yybytes[i];
-
-       buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
-
-       b = _gmx_sel_yy_scan_buffer(buf,n ,yyscanner);
-       if ( ! b )
-               YY_FATAL_ERROR( "bad buffer in _gmx_sel_yy_scan_bytes()" );
-
-       /* It's okay to grow etc. this buffer, and we should throw it
-        * away when we're done.
-        */
-       b->yy_is_our_buffer = 1;
-
-       return b;
-}
-
-#ifndef YY_EXIT_FAILURE
-#define YY_EXIT_FAILURE 2
-#endif
-
-static void yy_fatal_error (yyconst char* msg , yyscan_t yyscanner)
-{
-       (void) fprintf( stderr, "%s\n", msg );
-       exit( YY_EXIT_FAILURE );
-}
-
-/* Redefine yyless() so it works in section 3 code. */
-
-#undef yyless
-#define yyless(n) \
-       do \
-               { \
-               /* Undo effects of setting up yytext. */ \
-        int yyless_macro_arg = (n); \
-        YY_LESS_LINENO(yyless_macro_arg);\
-               yytext[yyleng] = yyg->yy_hold_char; \
-               yyg->yy_c_buf_p = yytext + yyless_macro_arg; \
-               yyg->yy_hold_char = *yyg->yy_c_buf_p; \
-               *yyg->yy_c_buf_p = '\0'; \
-               yyleng = yyless_macro_arg; \
-               } \
-       while ( 0 )
-
-/* Accessor  methods (get/set functions) to struct members. */
-
-/** Get the user-defined data for this scanner.
- * @param yyscanner The scanner object.
- */
-YY_EXTRA_TYPE _gmx_sel_yyget_extra  (yyscan_t yyscanner)
-{
-    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
-    return yyextra;
-}
-
-/** Get the current line number.
- * @param yyscanner The scanner object.
- */
-int _gmx_sel_yyget_lineno  (yyscan_t yyscanner)
-{
-    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
-    
-        if (! YY_CURRENT_BUFFER)
-            return 0;
-    
-    return yylineno;
-}
-
-/** Get the current column number.
- * @param yyscanner The scanner object.
- */
-int _gmx_sel_yyget_column  (yyscan_t yyscanner)
-{
-    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
-    
-        if (! YY_CURRENT_BUFFER)
-            return 0;
-    
-    return yycolumn;
-}
-
-/** Get the input stream.
- * @param yyscanner The scanner object.
- */
-FILE *_gmx_sel_yyget_in  (yyscan_t yyscanner)
-{
-    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
-    return yyin;
-}
-
-/** Get the output stream.
- * @param yyscanner The scanner object.
- */
-FILE *_gmx_sel_yyget_out  (yyscan_t yyscanner)
-{
-    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
-    return yyout;
-}
-
-/** Get the length of the current token.
- * @param yyscanner The scanner object.
- */
-int _gmx_sel_yyget_leng  (yyscan_t yyscanner)
-{
-    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
-    return yyleng;
-}
-
-/** Get the current token.
- * @param yyscanner The scanner object.
- */
-
-char *_gmx_sel_yyget_text  (yyscan_t yyscanner)
-{
-    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
-    return yytext;
-}
-
-/** Set the user-defined data. This data is never touched by the scanner.
- * @param user_defined The data to be associated with this scanner.
- * @param yyscanner The scanner object.
- */
-void _gmx_sel_yyset_extra (YY_EXTRA_TYPE  user_defined , yyscan_t yyscanner)
-{
-    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
-    yyextra = user_defined ;
-}
-
-/** Set the current line number.
- * @param line_number
- * @param yyscanner The scanner object.
- */
-void _gmx_sel_yyset_lineno (int  line_number , yyscan_t yyscanner)
-{
-    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
-
-        /* lineno is only valid if an input buffer exists. */
-        if (! YY_CURRENT_BUFFER )
-           yy_fatal_error( "_gmx_sel_yyset_lineno called with no buffer" , yyscanner); 
-    
-    yylineno = line_number;
-}
-
-/** Set the current column.
- * @param line_number
- * @param yyscanner The scanner object.
- */
-void _gmx_sel_yyset_column (int  column_no , yyscan_t yyscanner)
-{
-    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
-
-        /* column is only valid if an input buffer exists. */
-        if (! YY_CURRENT_BUFFER )
-           yy_fatal_error( "_gmx_sel_yyset_column called with no buffer" , yyscanner); 
-    
-    yycolumn = column_no;
-}
-
-/** Set the input stream. This does not discard the current
- * input buffer.
- * @param in_str A readable stream.
- * @param yyscanner The scanner object.
- * @see _gmx_sel_yy_switch_to_buffer
- */
-void _gmx_sel_yyset_in (FILE *  in_str , yyscan_t yyscanner)
-{
-    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
-    yyin = in_str ;
-}
-
-void _gmx_sel_yyset_out (FILE *  out_str , yyscan_t yyscanner)
-{
-    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
-    yyout = out_str ;
-}
-
-int _gmx_sel_yyget_debug  (yyscan_t yyscanner)
-{
-    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
-    return yy_flex_debug;
-}
-
-void _gmx_sel_yyset_debug (int  bdebug , yyscan_t yyscanner)
-{
-    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
-    yy_flex_debug = bdebug ;
-}
-
-/* Accessor methods for yylval and yylloc */
-
-/* User-visible API */
-
-/* _gmx_sel_yylex_init is special because it creates the scanner itself, so it is
- * the ONLY reentrant function that doesn't take the scanner as the last argument.
- * That's why we explicitly handle the declaration, instead of using our macros.
- */
-
-int _gmx_sel_yylex_init(yyscan_t* ptr_yy_globals)
-
-{
-    if (ptr_yy_globals == NULL){
-        errno = EINVAL;
-        return 1;
-    }
-
-    *ptr_yy_globals = (yyscan_t) _gmx_sel_yyalloc ( sizeof( struct yyguts_t ), NULL );
-
-    if (*ptr_yy_globals == NULL){
-        errno = ENOMEM;
-        return 1;
-    }
-
-    /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */
-    memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t));
-
-    return yy_init_globals ( *ptr_yy_globals );
-}
-
-/* _gmx_sel_yylex_init_extra has the same functionality as _gmx_sel_yylex_init, but follows the
- * convention of taking the scanner as the last argument. Note however, that
- * this is a *pointer* to a scanner, as it will be allocated by this call (and
- * is the reason, too, why this function also must handle its own declaration).
- * The user defined value in the first argument will be available to _gmx_sel_yyalloc in
- * the yyextra field.
- */
-
-int _gmx_sel_yylex_init_extra(YY_EXTRA_TYPE yy_user_defined,yyscan_t* ptr_yy_globals )
-
-{
-    struct yyguts_t dummy_yyguts;
-
-    _gmx_sel_yyset_extra (yy_user_defined, &dummy_yyguts);
-
-    if (ptr_yy_globals == NULL){
-        errno = EINVAL;
-        return 1;
-    }
-       
-    *ptr_yy_globals = (yyscan_t) _gmx_sel_yyalloc ( sizeof( struct yyguts_t ), &dummy_yyguts );
-       
-    if (*ptr_yy_globals == NULL){
-        errno = ENOMEM;
-        return 1;
-    }
-    
-    /* By setting to 0xAA, we expose bugs in
-    yy_init_globals. Leave at 0x00 for releases. */
-    memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t));
-    
-    _gmx_sel_yyset_extra (yy_user_defined, *ptr_yy_globals);
-    
-    return yy_init_globals ( *ptr_yy_globals );
-}
-
-static int yy_init_globals (yyscan_t yyscanner)
-{
-    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
-    /* Initialization is the same as for the non-reentrant scanner.
-     * This function is called from _gmx_sel_yylex_destroy(), so don't allocate here.
-     */
-
-    yyg->yy_buffer_stack = 0;
-    yyg->yy_buffer_stack_top = 0;
-    yyg->yy_buffer_stack_max = 0;
-    yyg->yy_c_buf_p = (char *) 0;
-    yyg->yy_init = 0;
-    yyg->yy_start = 0;
-
-    yyg->yy_start_stack_ptr = 0;
-    yyg->yy_start_stack_depth = 0;
-    yyg->yy_start_stack =  NULL;
-
-/* Defined in main.c */
-#ifdef YY_STDINIT
-    yyin = stdin;
-    yyout = stdout;
-#else
-    yyin = (FILE *) 0;
-    yyout = (FILE *) 0;
-#endif
-
-    /* For future reference: Set errno on error, since we are called by
-     * _gmx_sel_yylex_init()
-     */
-    return 0;
-}
-
-/* _gmx_sel_yylex_destroy is for both reentrant and non-reentrant scanners. */
-int _gmx_sel_yylex_destroy  (yyscan_t yyscanner)
-{
-    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
-
-    /* Pop the buffer stack, destroying each element. */
-       while(YY_CURRENT_BUFFER){
-               _gmx_sel_yy_delete_buffer(YY_CURRENT_BUFFER ,yyscanner );
-               YY_CURRENT_BUFFER_LVALUE = NULL;
-               _gmx_sel_yypop_buffer_state(yyscanner);
-       }
-
-       /* Destroy the stack itself. */
-       _gmx_sel_yyfree(yyg->yy_buffer_stack ,yyscanner);
-       yyg->yy_buffer_stack = NULL;
-
-    /* Destroy the start condition stack. */
-        _gmx_sel_yyfree(yyg->yy_start_stack ,yyscanner );
-        yyg->yy_start_stack = NULL;
-
-    /* Reset the globals. This is important in a non-reentrant scanner so the next time
-     * _gmx_sel_yylex() is called, initialization will occur. */
-    yy_init_globals( yyscanner);
-
-    /* Destroy the main struct (reentrant only). */
-    _gmx_sel_yyfree ( yyscanner , yyscanner );
-    yyscanner = NULL;
-    return 0;
-}
-
-/*
- * Internal utility routines.
- */
-
-#ifndef yytext_ptr
-static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yyscanner)
-{
-       register int i;
-       for ( i = 0; i < n; ++i )
-               s1[i] = s2[i];
-}
-#endif
-
-#ifdef YY_NEED_STRLEN
-static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner)
-{
-       register int n;
-       for ( n = 0; s[n]; ++n )
-               ;
-
-       return n;
-}
-#endif
-
-void *_gmx_sel_yyalloc (yy_size_t  size , yyscan_t yyscanner)
-{
-       return (void *) malloc( size );
-}
-
-void *_gmx_sel_yyrealloc  (void * ptr, yy_size_t  size , yyscan_t yyscanner)
-{
-       /* The cast to (char *) in the following accommodates both
-        * implementations that use char* generic pointers, and those
-        * that use void* generic pointers.  It works with the latter
-        * because both ANSI C and C++ allow castless assignment from
-        * any pointer type to void*, and deal with argument conversions
-        * as though doing an assignment.
-        */
-       return (void *) realloc( (char *) ptr, size );
-}
-
-void _gmx_sel_yyfree (void * ptr , yyscan_t yyscanner)
-{
-       free( (char *) ptr );   /* see _gmx_sel_yyrealloc() for (char *) cast */
-}
-
-#define YYTABLES_NAME "yytables"
-
-#line 156 "scanner.l"
diff --git a/src/gmxlib/selection/scanner.h b/src/gmxlib/selection/scanner.h
deleted file mode 100644 (file)
index 4486038..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- *
- *                This source code is part of
- *
- *                 G   R   O   M   A   C   S
- *
- *          GROningen MAchine for Chemical Simulations
- *
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
- * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
- * Copyright (c) 2001-2009, The GROMACS development team,
- * check out http://www.gromacs.org for more information.
-
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * If you want to redistribute modifications, please consider that
- * scientific software is very special. Version control is crucial -
- * bugs must be traceable. We will be happy to consider code for
- * inclusion in the official distribution, but derived work must not
- * be called official GROMACS. Details are found in the README & COPYING
- * files - if they are missing, get the official version at www.gromacs.org.
- *
- * To help us fund GROMACS development, we humbly ask that you cite
- * the papers on the package - you can find them in the top README file.
- *
- * For more info, check our website at http://www.gromacs.org
- */
-/*! \internal \file
- * \brief
- * Parser/scanner interaction functions.
- *
- * This is an implementation header: there should be no need to use it outside
- * this directory.
- */
-#ifndef SELECTION_SCANNER_H
-#define SELECTION_SCANNER_H
-
-#include "parser.h"
-
-struct gmx_ana_indexgrps_t;
-struct gmx_ana_selcollection_t;
-
-#ifndef YY_TYPEDEF_YY_SCANNER_T
-#define YY_TYPEDEF_YY_SCANNER_T
-typedef void *yyscan_t;
-#endif
-
-/** Initializes the selection scanner. */
-int
-_gmx_sel_init_lexer(yyscan_t *scannerp, struct gmx_ana_selcollection_t *sc,
-                    gmx_bool bInteractive, int maxnr,
-                    struct gmx_ana_indexgrps_t *grps);
-/** Frees memory allocated for the selection scanner. */
-void
-_gmx_sel_free_lexer(yyscan_t scanner);
-
-/** Returns TRUE if the scanner is interactive. */
-gmx_bool
-_gmx_sel_is_lexer_interactive(yyscan_t scanner);
-/** Returns the selection collection for the scanner. */
-struct gmx_ana_selcollection_t *
-_gmx_sel_lexer_selcollection(yyscan_t scanner);
-/** Returns the external index groups for the scanner. */
-struct gmx_ana_indexgrps_t *
-_gmx_sel_lexer_indexgrps(yyscan_t scanner);
-/** Returns the number of selections after which the parser should stop. */
-int
-_gmx_sel_lexer_exp_selcount(yyscan_t scanner);
-
-/** Returns a pretty string of the current selection.  */
-const char *
-_gmx_sel_lexer_pselstr(yyscan_t scanner);
-/** Clears the current selection string.  */
-void
-_gmx_sel_lexer_clear_pselstr(yyscan_t scanner);
-/** Clears the method stack in the scanner in error situations. */
-void
-_gmx_sel_lexer_clear_method_stack(yyscan_t scanner);
-/** Notifies the scanner that a complete method expression has been parsed. */
-void
-_gmx_sel_finish_method(yyscan_t scanner);
-/** Initializes the scanner to scan a file. */
-void
-_gmx_sel_set_lex_input_file(yyscan_t scanner, FILE *fp);
-/** Initializes the scanner to scan a string. */
-void
-_gmx_sel_set_lex_input_str(yyscan_t scanner, const char *str);
-
-/** A wrapper for the actual scanner, used by the Bison parser. */
-int
-_gmx_sel_yyblex(YYSTYPE *yylval, yyscan_t yyscanner);
-
-#endif
diff --git a/src/gmxlib/selection/scanner.l b/src/gmxlib/selection/scanner.l
deleted file mode 100644 (file)
index b23b2b3..0000000
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- *
- *                This source code is part of
- *
- *                 G   R   O   M   A   C   S
- *
- *          GROningen MAchine for Chemical Simulations
- *
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
- * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
- * Copyright (c) 2001-2009, The GROMACS development team,
- * check out http://www.gromacs.org for more information.
-
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * If you want to redistribute modifications, please consider that
- * scientific software is very special. Version control is crucial -
- * bugs must be traceable. We will be happy to consider code for
- * inclusion in the official distribution, but derived work must not
- * be called official GROMACS. Details are found in the README & COPYING
- * files - if they are missing, get the official version at www.gromacs.org.
- *
- * To help us fund GROMACS development, we humbly ask that you cite
- * the papers on the package - you can find them in the top README file.
- *
- * For more info, check our website at http://www.gromacs.org
- */
-/*! \cond \internal \file scanner.l
- * \brief
- * Tokenizer for the selection language.
- * \endcond
- */
-/*! \internal \file scanner.c
- * \brief
- * Generated (from scanner.l by Flex) tokenizer for the selection language.
- */
-%{
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <string2.h>
-
-#include "parser.h"
-#include "scanner.h"
-#include "scanner_internal.h"
-
-/* This macro is here to make the actions a bit shorter, since nearly every
- * action needs this call. */
-#define ADD_TOKEN _gmx_sel_lexer_add_token(yytext, yyleng, state)
-
-%}
-
-INTEGER    [[:digit:]]+
-DSEQ       ([[:digit:]]+)
-FRAC       (([[:digit:]]*"."{DSEQ})|{DSEQ}".")
-EXP        ([eE][+-]?{DSEQ})
-REAL       (({FRAC}{EXP}?)|({DSEQ}{EXP}))
-STRING     (\"([^\"\\\n]|(\\\"))*\")
-IDENTIFIER ([[:alpha:]][_[:alnum:]]*)
-CMPOP      (([<>]=?)|([!=]=))
-COMMENT    (#.*)
-
-%option nodefault
-%option noyywrap
-%option reentrant
-%option prefix="_gmx_sel_yy"
-%option header-file="scanner_flex.h"
-%option nounistd
-%option never-interactive
-
-%s matchof
-%s matchbool
-%s cmdstart
-%x help
-
-%%
-
-%{
-    gmx_sel_lexer_t *state = yyget_extra(yyscanner);
-    int              retval;
-    /* Return a token if one is pending */
-    retval = _gmx_sel_lexer_process_pending(yylval, state);
-    if (retval != 0)
-    {
-        return retval;
-    }
-    /* Handle the start conditions for 'of' matching */
-    if (state->bMatchOf)
-    {
-        BEGIN(matchof);
-        state->bMatchOf = FALSE;
-    }
-    else if (state->bMatchBool)
-    {
-        BEGIN(matchbool);
-        state->bMatchBool = FALSE;
-    }
-    else if (state->bCmdStart)
-    {
-        BEGIN(cmdstart);
-    }
-    else if (YYSTATE != help)
-    {
-        BEGIN(0);
-    }
-%}
-
-{COMMENT}
-{INTEGER}       { yylval->i   = strtol(yytext, NULL, 10);    ADD_TOKEN; return TOK_INT; }
-{REAL}          { yylval->r   = strtod(yytext, NULL);        ADD_TOKEN; return TOK_REAL; }
-{STRING}        { yylval->str = gmx_strndup(yytext+1, yyleng-2); ADD_TOKEN; return STR;  }
-
-\\\n            { _gmx_sel_lexer_add_token(" ", 1, state); }
-";"|\n          {
-                    if (yytext[0] == ';' || state->bInteractive)
-                    {
-                        rtrim(state->pselstr);
-                        return CMD_SEP;
-                    }
-                    else
-                    {
-                        _gmx_sel_lexer_add_token(" ", 1, state);
-                    }
-                }
-
-<cmdstart>help  { BEGIN(help); return HELP; }
-<help>{
-[[:blank:]]+
-{IDENTIFIER}    { yylval->str = gmx_strndup(yytext, yyleng); return HELP_TOPIC; }
-";"|\n          { return CMD_SEP; }
-.               { return INVALID; }
-}
-
-<matchbool>{
-yes|on          { ADD_TOKEN; yylval->i = 1; return TOK_INT; }
-no|off          { ADD_TOKEN; yylval->i = 0; return TOK_INT; }
-}
-group           { ADD_TOKEN; return GROUP; }
-to              { ADD_TOKEN; return TO; }
-<matchof>of     { ADD_TOKEN; BEGIN(0); return OF; }
-and|"&&"        { ADD_TOKEN; return AND; }
-or|"||"         { ADD_TOKEN; return OR; }
-xor             { ADD_TOKEN; return XOR; }
-not|"!"         { ADD_TOKEN; return NOT; }
-{CMPOP}         { yylval->str = gmx_strndup(yytext, yyleng); ADD_TOKEN; return CMP_OP; }
-
-{IDENTIFIER}    { return _gmx_sel_lexer_process_identifier(yylval, yytext, yyleng, state); }
-
-[[:blank:]]+    { _gmx_sel_lexer_add_token(" ", 1, state); }
-[_[:alnum:]]+   { yylval->str = gmx_strndup(yytext, yyleng); ADD_TOKEN; return STR; }
-.               { ADD_TOKEN; return yytext[0]; }
diff --git a/src/gmxlib/selection/scanner_flex.h b/src/gmxlib/selection/scanner_flex.h
deleted file mode 100644 (file)
index 0a89dc9..0000000
+++ /dev/null
@@ -1,350 +0,0 @@
-#ifndef _gmx_sel_yyHEADER_H
-#define _gmx_sel_yyHEADER_H 1
-#define _gmx_sel_yyIN_HEADER 1
-
-#line 6 "scanner_flex.h"
-
-#line 8 "scanner_flex.h"
-
-#define  YY_INT_ALIGNED short int
-
-/* A lexical scanner generated by flex */
-
-#define FLEX_SCANNER
-#define YY_FLEX_MAJOR_VERSION 2
-#define YY_FLEX_MINOR_VERSION 5
-#define YY_FLEX_SUBMINOR_VERSION 35
-#if YY_FLEX_SUBMINOR_VERSION > 0
-#define FLEX_BETA
-#endif
-
-/* First, we deal with  platform-specific or compiler-specific issues. */
-
-/* begin standard C headers. */
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-#include <stdlib.h>
-
-/* end standard C headers. */
-
-/* flex integer type definitions */
-
-#ifndef FLEXINT_H
-#define FLEXINT_H
-
-/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
-
-#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
-
-/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
- * if you want the limit (max/min) macros for int types. 
- */
-#ifndef __STDC_LIMIT_MACROS
-#define __STDC_LIMIT_MACROS 1
-#endif
-
-#include <inttypes.h>
-typedef int8_t flex_int8_t;
-typedef uint8_t flex_uint8_t;
-typedef int16_t flex_int16_t;
-typedef uint16_t flex_uint16_t;
-typedef int32_t flex_int32_t;
-typedef uint32_t flex_uint32_t;
-#else
-typedef signed char flex_int8_t;
-typedef short int flex_int16_t;
-typedef int flex_int32_t;
-typedef unsigned char flex_uint8_t; 
-typedef unsigned short int flex_uint16_t;
-typedef unsigned int flex_uint32_t;
-
-/* Limits of integral types. */
-#ifndef INT8_MIN
-#define INT8_MIN               (-128)
-#endif
-#ifndef INT16_MIN
-#define INT16_MIN              (-32767-1)
-#endif
-#ifndef INT32_MIN
-#define INT32_MIN              (-2147483647-1)
-#endif
-#ifndef INT8_MAX
-#define INT8_MAX               (127)
-#endif
-#ifndef INT16_MAX
-#define INT16_MAX              (32767)
-#endif
-#ifndef INT32_MAX
-#define INT32_MAX              (2147483647)
-#endif
-#ifndef UINT8_MAX
-#define UINT8_MAX              (255U)
-#endif
-#ifndef UINT16_MAX
-#define UINT16_MAX             (65535U)
-#endif
-#ifndef UINT32_MAX
-#define UINT32_MAX             (4294967295U)
-#endif
-
-#endif /* ! C99 */
-
-#endif /* ! FLEXINT_H */
-
-#ifdef __cplusplus
-
-/* The "const" storage-class-modifier is valid. */
-#define YY_USE_CONST
-
-#else  /* ! __cplusplus */
-
-/* C99 requires __STDC__ to be defined as 1. */
-#if defined (__STDC__)
-
-#define YY_USE_CONST
-
-#endif /* defined (__STDC__) */
-#endif /* ! __cplusplus */
-
-#ifdef YY_USE_CONST
-#define yyconst const
-#else
-#define yyconst
-#endif
-
-/* An opaque pointer. */
-#ifndef YY_TYPEDEF_YY_SCANNER_T
-#define YY_TYPEDEF_YY_SCANNER_T
-typedef void* yyscan_t;
-#endif
-
-/* For convenience, these vars (plus the bison vars far below)
-   are macros in the reentrant scanner. */
-#define yyin yyg->yyin_r
-#define yyout yyg->yyout_r
-#define yyextra yyg->yyextra_r
-#define yyleng yyg->yyleng_r
-#define yytext yyg->yytext_r
-#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno)
-#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column)
-#define yy_flex_debug yyg->yy_flex_debug_r
-
-/* Size of default input buffer. */
-#ifndef YY_BUF_SIZE
-#ifdef __ia64__
-/* On IA-64, the buffer size is 16k, not 8k.
- * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case.
- * Ditto for the __ia64__ case accordingly.
- */
-#define YY_BUF_SIZE 32768
-#else
-#define YY_BUF_SIZE 16384
-#endif /* __ia64__ */
-#endif
-
-#ifndef YY_TYPEDEF_YY_BUFFER_STATE
-#define YY_TYPEDEF_YY_BUFFER_STATE
-typedef struct yy_buffer_state *YY_BUFFER_STATE;
-#endif
-
-#ifndef YY_TYPEDEF_YY_SIZE_T
-#define YY_TYPEDEF_YY_SIZE_T
-typedef size_t yy_size_t;
-#endif
-
-#ifndef YY_STRUCT_YY_BUFFER_STATE
-#define YY_STRUCT_YY_BUFFER_STATE
-struct yy_buffer_state
-       {
-       FILE *yy_input_file;
-
-       char *yy_ch_buf;                /* input buffer */
-       char *yy_buf_pos;               /* current position in input buffer */
-
-       /* Size of input buffer in bytes, not including room for EOB
-        * characters.
-        */
-       yy_size_t yy_buf_size;
-
-       /* Number of characters read into yy_ch_buf, not including EOB
-        * characters.
-        */
-       int yy_n_chars;
-
-       /* Whether we "own" the buffer - i.e., we know we created it,
-        * and can realloc() it to grow it, and should free() it to
-        * delete it.
-        */
-       int yy_is_our_buffer;
-
-       /* Whether this is an "interactive" input source; if so, and
-        * if we're using stdio for input, then we want to use getc()
-        * instead of fread(), to make sure we stop fetching input after
-        * each newline.
-        */
-       int yy_is_interactive;
-
-       /* Whether we're considered to be at the beginning of a line.
-        * If so, '^' rules will be active on the next match, otherwise
-        * not.
-        */
-       int yy_at_bol;
-
-    int yy_bs_lineno; /**< The line count. */
-    int yy_bs_column; /**< The column count. */
-    
-       /* Whether to try to fill the input buffer when we reach the
-        * end of it.
-        */
-       int yy_fill_buffer;
-
-       int yy_buffer_status;
-
-       };
-#endif /* !YY_STRUCT_YY_BUFFER_STATE */
-
-void _gmx_sel_yyrestart (FILE *input_file ,yyscan_t yyscanner );
-void _gmx_sel_yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner );
-YY_BUFFER_STATE _gmx_sel_yy_create_buffer (FILE *file,int size ,yyscan_t yyscanner );
-void _gmx_sel_yy_delete_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
-void _gmx_sel_yy_flush_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
-void _gmx_sel_yypush_buffer_state (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner );
-void _gmx_sel_yypop_buffer_state (yyscan_t yyscanner );
-
-YY_BUFFER_STATE _gmx_sel_yy_scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner );
-YY_BUFFER_STATE _gmx_sel_yy_scan_string (yyconst char *yy_str ,yyscan_t yyscanner );
-YY_BUFFER_STATE _gmx_sel_yy_scan_bytes (yyconst char *bytes,int len ,yyscan_t yyscanner );
-
-void *_gmx_sel_yyalloc (yy_size_t ,yyscan_t yyscanner );
-void *_gmx_sel_yyrealloc (void *,yy_size_t ,yyscan_t yyscanner );
-void _gmx_sel_yyfree (void * ,yyscan_t yyscanner );
-
-#define _gmx_sel_yywrap(n) 1
-#define YY_SKIP_YYWRAP
-
-#define yytext_ptr yytext_r
-
-#ifdef YY_HEADER_EXPORT_START_CONDITIONS
-#define INITIAL 0
-#define matchof 1
-#define matchbool 2
-#define cmdstart 3
-#define help 4
-
-#endif
-
-#ifndef YY_NO_UNISTD_H
-/* Special case for "unistd.h", since it is non-ANSI. We include it way
- * down here because we want the user's section 1 to have been scanned first.
- * The user has a chance to override it with an option.
- */
-#include <unistd.h>
-#endif
-
-#ifndef YY_EXTRA_TYPE
-#define YY_EXTRA_TYPE void *
-#endif
-
-int _gmx_sel_yylex_init (yyscan_t* scanner);
-
-int _gmx_sel_yylex_init_extra (YY_EXTRA_TYPE user_defined,yyscan_t* scanner);
-
-/* Accessor methods to globals.
-   These are made visible to non-reentrant scanners for convenience. */
-
-int _gmx_sel_yylex_destroy (yyscan_t yyscanner );
-
-int _gmx_sel_yyget_debug (yyscan_t yyscanner );
-
-void _gmx_sel_yyset_debug (int debug_flag ,yyscan_t yyscanner );
-
-YY_EXTRA_TYPE _gmx_sel_yyget_extra (yyscan_t yyscanner );
-
-void _gmx_sel_yyset_extra (YY_EXTRA_TYPE user_defined ,yyscan_t yyscanner );
-
-FILE *_gmx_sel_yyget_in (yyscan_t yyscanner );
-
-void _gmx_sel_yyset_in  (FILE * in_str ,yyscan_t yyscanner );
-
-FILE *_gmx_sel_yyget_out (yyscan_t yyscanner );
-
-void _gmx_sel_yyset_out  (FILE * out_str ,yyscan_t yyscanner );
-
-int _gmx_sel_yyget_leng (yyscan_t yyscanner );
-
-char *_gmx_sel_yyget_text (yyscan_t yyscanner );
-
-int _gmx_sel_yyget_lineno (yyscan_t yyscanner );
-
-void _gmx_sel_yyset_lineno (int line_number ,yyscan_t yyscanner );
-
-/* Macros after this point can all be overridden by user definitions in
- * section 1.
- */
-
-#ifndef YY_SKIP_YYWRAP
-#ifdef __cplusplus
-extern "C" int _gmx_sel_yywrap (yyscan_t yyscanner );
-#else
-extern int _gmx_sel_yywrap (yyscan_t yyscanner );
-#endif
-#endif
-
-#ifndef yytext_ptr
-static void yy_flex_strncpy (char *,yyconst char *,int ,yyscan_t yyscanner);
-#endif
-
-#ifdef YY_NEED_STRLEN
-static int yy_flex_strlen (yyconst char * ,yyscan_t yyscanner);
-#endif
-
-#ifndef YY_NO_INPUT
-
-#endif
-
-/* Amount of stuff to slurp up with each read. */
-#ifndef YY_READ_BUF_SIZE
-#ifdef __ia64__
-/* On IA-64, the buffer size is 16k, not 8k */
-#define YY_READ_BUF_SIZE 16384
-#else
-#define YY_READ_BUF_SIZE 8192
-#endif /* __ia64__ */
-#endif
-
-/* Number of entries by which start-condition stack grows. */
-#ifndef YY_START_STACK_INCR
-#define YY_START_STACK_INCR 25
-#endif
-
-/* Default declaration of generated scanner - a define so the user can
- * easily add parameters.
- */
-#ifndef YY_DECL
-#define YY_DECL_IS_OURS 1
-
-extern int _gmx_sel_yylex (yyscan_t yyscanner);
-
-#define YY_DECL int _gmx_sel_yylex (yyscan_t yyscanner)
-#endif /* !YY_DECL */
-
-/* yy_get_previous_state - get the state just before the EOB char was reached */
-
-#undef YY_NEW_FILE
-#undef YY_FLUSH_BUFFER
-#undef yy_set_bol
-#undef yy_new_buffer
-#undef yy_set_interactive
-#undef YY_DO_BEFORE_ACTION
-
-#ifdef YY_DECL_IS_OURS
-#undef YY_DECL_IS_OURS
-#undef YY_DECL
-#endif
-
-#line 156 "scanner.l"
-
-#line 349 "scanner_flex.h"
-#undef _gmx_sel_yyIN_HEADER
-#endif /* _gmx_sel_yyHEADER_H */
diff --git a/src/gmxlib/selection/scanner_internal.c b/src/gmxlib/selection/scanner_internal.c
deleted file mode 100644 (file)
index 1e7e4f7..0000000
+++ /dev/null
@@ -1,586 +0,0 @@
-/*
- *
- *                This source code is part of
- *
- *                 G   R   O   M   A   C   S
- *
- *          GROningen MAchine for Chemical Simulations
- *
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
- * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
- * Copyright (c) 2001-2009, The GROMACS development team,
- * check out http://www.gromacs.org for more information.
-
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * If you want to redistribute modifications, please consider that
- * scientific software is very special. Version control is crucial -
- * bugs must be traceable. We will be happy to consider code for
- * inclusion in the official distribution, but derived work must not
- * be called official GROMACS. Details are found in the README & COPYING
- * files - if they are missing, get the official version at www.gromacs.org.
- *
- * To help us fund GROMACS development, we humbly ask that you cite
- * the papers on the package - you can find them in the top README file.
- *
- * For more info, check our website at http://www.gromacs.org
- */
-/*! \internal \file
- * \brief Helper functions for the selection tokenizer.
- *
- * This file implements the functions in the headers scanner.h and
- * scanner_internal.h.
- */
-/*! \internal file scanner_flex.h
- * \brief Generated (from scanner.l) header file by Flex.
- *
- * This file contains definitions of functions that are needed in
- * scanner_internal.c.
- */
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdlib.h>
-#include <typedefs.h>
-#include <smalloc.h>
-#include <string.h>
-
-#include "string2.h"
-#include "gmx_fatal.h"
-
-#include <selmethod.h>
-
-#include "parsetree.h"
-#include "selcollection.h"
-#include "selelem.h"
-#include "symrec.h"
-
-#include "parser.h"
-#include "scanner.h"
-#include "scanner_internal.h"
-
-#define STRSTORE_ALLOCSTEP 1000
-
-/* These are defined as macros in the generated scanner_flex.h.
- * We undefine them here to have them as variable names in the subroutines.
- * There are other ways of doing this, but this is probably the easiest. */
-#undef yylval
-#undef yytext
-#undef yyleng
-
-static gmx_bool
-read_stdin_line(gmx_sel_lexer_t *state)
-{
-    char *ptr     = state->inputstr;
-    int   max_len = state->nalloc_input;
-    int   totlen = 0;
-
-    if (feof(stdin))
-    {
-        return FALSE;
-    }
-    if (state->bInteractive)
-    {
-        fprintf(stderr, "> ");
-    }
-    /* For some reason (at least on my Linux), fgets() doesn't return until
-     * the user presses Ctrl-D _twice_ at the end of a non-empty line.
-     * This can be a bit confusing for users, but there's not much we can
-     * do, and the chances of a normal user noticing this are not very big. */
-    while (fgets(ptr, max_len, stdin))
-    {
-        int len = strlen(ptr);
-
-        totlen += len;
-        if (len >= 2 && ptr[len - 1] == '\n' && ptr[len - 2] == '\\')
-        {
-            if (state->bInteractive)
-            {
-                fprintf(stderr, "... ");
-            }
-        }
-        else if (len >= 1 && ptr[len - 1] == '\n')
-        {
-            break;
-        }
-        else if (len < max_len - 1)
-        {
-            if (state->bInteractive)
-            {
-                fprintf(stderr, "\n");
-            }
-            break;
-        }
-        ptr     += len;
-        max_len -= len;
-        if (max_len <= 2)
-        {
-            max_len += state->nalloc_input;
-            state->nalloc_input *= 2;
-            len = ptr - state->inputstr;
-            srenew(state->inputstr, state->nalloc_input);
-            ptr = state->inputstr + len;
-        }
-    }
-    if (ferror(stdin))
-    {
-        gmx_input("selection reading failed");
-    }
-    return totlen > 0;
-}
-
-int
-_gmx_sel_yyblex(YYSTYPE *yylval, yyscan_t yyscanner)
-{
-    gmx_sel_lexer_t *state = _gmx_sel_yyget_extra(yyscanner);
-    gmx_bool bCmdStart;
-    int token;
-
-    if (!state->bBuffer && !state->inputstr)
-    {
-        state->nalloc_input = 1024;
-        snew(state->inputstr, state->nalloc_input);
-        read_stdin_line(state);
-        _gmx_sel_set_lex_input_str(yyscanner, state->inputstr);
-    }
-    bCmdStart = state->bCmdStart;
-    token = _gmx_sel_yylex(yylval, yyscanner);
-    while (state->inputstr && token == 0 && read_stdin_line(state))
-    {
-        _gmx_sel_set_lex_input_str(yyscanner, state->inputstr);
-        token = _gmx_sel_yylex(yylval, yyscanner);
-    }
-    if (token == 0 && !bCmdStart)
-    {
-        token = CMD_SEP;
-        rtrim(state->pselstr);
-    }
-    state->bCmdStart = (token == CMD_SEP);
-    return token;
-}
-
-static int
-init_param_token(YYSTYPE *yylval, gmx_ana_selparam_t *param, gmx_bool bBoolNo)
-{
-    if (bBoolNo)
-    {
-        snew(yylval->str, strlen(param->name) + 3);
-        yylval->str[0] = 'n';
-        yylval->str[1] = 'o';
-        strcpy(yylval->str+2, param->name);
-    }
-    else
-    {
-        yylval->str = param->name ? strdup(param->name) : NULL;
-    }
-    return PARAM;
-}
-
-static int
-init_method_token(YYSTYPE *yylval, gmx_ana_selmethod_t *method, gmx_bool bPosMod,
-                  gmx_sel_lexer_t *state)
-{
-    /* If the previous token was not KEYWORD_POS, return EMPTY_POSMOD
-     * before the actual method to work around a limitation in Bison. */
-    if (!bPosMod && method->type != POS_VALUE)
-    {
-        state->nextmethod = method;
-        return EMPTY_POSMOD;
-    }
-    yylval->meth = method;
-    if (!(method->flags & SMETH_MODIFIER) && method->nparams == 0)
-    {
-        /* Keyword */
-        switch (method->type)
-        {
-            case INT_VALUE:   return KEYWORD_NUMERIC;
-            case REAL_VALUE:  return KEYWORD_NUMERIC;
-            case STR_VALUE:   return KEYWORD_STR;
-            case GROUP_VALUE: return KEYWORD_GROUP;
-            default:          return INVALID;
-        }
-    } else {
-        /* Method with parameters or a modifier */
-        if (method->flags & SMETH_MODIFIER)
-        {
-            /* Remove all methods from the stack */
-            state->msp = -1;
-            if (method->param[1].name == NULL)
-            {
-                state->nextparam = &method->param[1];
-            }
-        }
-        else
-        {
-            if (method->param[0].name == NULL)
-            {
-                state->nextparam = &method->param[0];
-            }
-        }
-        ++state->msp;
-        if (state->msp >= state->mstack_alloc)
-        {
-            state->mstack_alloc += 10;
-            srenew(state->mstack, state->mstack_alloc);
-        }
-        state->mstack[state->msp] = method;
-        if (method->flags & SMETH_MODIFIER)
-        {
-            return MODIFIER;
-        }
-        switch (method->type)
-        {
-            case INT_VALUE:   return METHOD_NUMERIC;
-            case REAL_VALUE:  return METHOD_NUMERIC;
-            case POS_VALUE:   return METHOD_POS;
-            case GROUP_VALUE: return METHOD_GROUP;
-            default:
-                --state->msp;
-                return INVALID;
-        }
-    }
-    return INVALID; /* Should not be reached */
-}
-
-int
-_gmx_sel_lexer_process_pending(YYSTYPE *yylval, gmx_sel_lexer_t *state)
-{
-    if (state->nextparam)
-    {
-        gmx_ana_selparam_t *param = state->nextparam;
-        gmx_bool                bBoolNo = state->bBoolNo;
-
-        if (state->neom > 0)
-        {
-            --state->neom;
-            return END_OF_METHOD;
-        }
-        state->nextparam = NULL;
-        state->bBoolNo   = FALSE;
-        _gmx_sel_lexer_add_token(param->name, -1, state);
-        return init_param_token(yylval, param, bBoolNo);
-    }
-    if (state->prev_pos_kw > 0)
-    {
-        --state->prev_pos_kw;
-    }
-    if (state->nextmethod)
-    {
-        gmx_ana_selmethod_t *method = state->nextmethod;
-
-        state->nextmethod = NULL;
-        return init_method_token(yylval, method, TRUE, state);
-    }
-    return 0;
-}
-
-int
-_gmx_sel_lexer_process_identifier(YYSTYPE *yylval, char *yytext, size_t yyleng,
-                                  gmx_sel_lexer_t *state)
-{
-    gmx_sel_symrec_t *symbol;
-    e_symbol_t        symtype;
-
-    /* Check if the identifier matches with a parameter name */
-    if (state->msp >= 0)
-    {
-        gmx_ana_selparam_t *param = NULL;
-        gmx_bool                bBoolNo = FALSE;
-        int                 sp = state->msp;
-        while (!param && sp >= 0)
-        {
-            int             i;
-            for (i = 0; i < state->mstack[sp]->nparams; ++i)
-            {
-                /* Skip NULL parameters and too long parameters */
-                if (state->mstack[sp]->param[i].name == NULL
-                    || strlen(state->mstack[sp]->param[i].name) > yyleng)
-                {
-                    continue;
-                }
-                if (!strncmp(state->mstack[sp]->param[i].name, yytext, yyleng))
-                {
-                    param = &state->mstack[sp]->param[i];
-                    break;
-                }
-                /* Check separately for a 'no' prefix on gmx_boolean parameters */
-                if (state->mstack[sp]->param[i].val.type == NO_VALUE
-                    && yyleng > 2 && yytext[0] == 'n' && yytext[1] == 'o'
-                    && !strncmp(state->mstack[sp]->param[i].name, yytext+2, yyleng-2))
-                {
-                    param = &state->mstack[sp]->param[i];
-                    bBoolNo = TRUE;
-                    break;
-                }
-            }
-            if (!param)
-            {
-                --sp;
-            }
-        }
-        if (param)
-        {
-            if (param->val.type == NO_VALUE && !bBoolNo)
-            {
-                state->bMatchBool = TRUE;
-            }
-            if (sp < state->msp)
-            {
-                state->neom = state->msp - sp - 1;
-                state->nextparam = param;
-                state->bBoolNo   = bBoolNo;
-                return END_OF_METHOD;
-            }
-            _gmx_sel_lexer_add_token(param->name, -1, state);
-            return init_param_token(yylval, param, bBoolNo);
-        }
-    }
-
-    /* Check if the identifier matches with a symbol */
-    symbol = _gmx_sel_find_symbol_len(state->sc->symtab, yytext, yyleng, FALSE);
-    /* If there is no match, return the token as a string */
-    if (!symbol)
-    {
-        yylval->str = gmx_strndup(yytext, yyleng);
-        _gmx_sel_lexer_add_token(yytext, yyleng, state);
-        return IDENTIFIER;
-    }
-    _gmx_sel_lexer_add_token(_gmx_sel_sym_name(symbol), -1, state);
-    symtype = _gmx_sel_sym_type(symbol);
-    /* Reserved symbols should have been caught earlier */
-    if (symtype == SYMBOL_RESERVED)
-    {
-        return INVALID;
-    }
-    /* For variable symbols, return the type of the variable value */
-    if (symtype == SYMBOL_VARIABLE)
-    {
-        t_selelem *var;
-
-        var = _gmx_sel_sym_value_var(symbol);
-        /* Return simple tokens for constant variables */
-        if (var->type == SEL_CONST)
-        {
-            switch (var->v.type)
-            {
-                case INT_VALUE:
-                    yylval->i = var->v.u.i[0];
-                    return TOK_INT;
-                case REAL_VALUE:
-                    yylval->r = var->v.u.r[0];
-                    return TOK_REAL;
-                case POS_VALUE:
-                    break;
-                default:
-                    return INVALID;
-            }
-        }
-        yylval->sel = var;
-        switch (var->v.type)
-        {
-            case INT_VALUE:   return VARIABLE_NUMERIC;
-            case REAL_VALUE:  return VARIABLE_NUMERIC;
-            case POS_VALUE:   return VARIABLE_POS;
-            case GROUP_VALUE: return VARIABLE_GROUP;
-            default:          return INVALID;
-        }
-        return INVALID;
-    }
-    /* For method symbols, return the correct type */
-    if (symtype == SYMBOL_METHOD)
-    {
-        gmx_ana_selmethod_t *method;
-
-        method = _gmx_sel_sym_value_method(symbol);
-        return init_method_token(yylval, method, state->prev_pos_kw > 0, state);
-    }
-    /* For position symbols, we need to return KEYWORD_POS, but we also need
-     * some additional handling. */
-    if (symtype == SYMBOL_POS)
-    {
-        state->bMatchOf = TRUE;
-        yylval->str = _gmx_sel_sym_name(symbol);
-        state->prev_pos_kw = 2;
-        return KEYWORD_POS;
-    }
-    /* Should not be reached */
-    return INVALID;
-}
-
-void
-_gmx_sel_lexer_add_token(const char *str, int len, gmx_sel_lexer_t *state)
-{
-    /* Do nothing if the string is empty, or if it is a space and there is
-     * no other text yet, or if there already is a space. */
-    if (!str || len == 0 || strlen(str) == 0
-        || (str[0] == ' ' && str[1] == 0
-            && (state->pslen == 0 || state->pselstr[state->pslen - 1] == ' ')))
-    {
-        return;
-    }
-    if (len < 0)
-    {
-        len = strlen(str);
-    }
-    /* Allocate more memory if necessary */
-    if (state->nalloc_psel - state->pslen < len)
-    {
-        int incr = STRSTORE_ALLOCSTEP < len ? len : STRSTORE_ALLOCSTEP;
-        state->nalloc_psel += incr;
-        srenew(state->pselstr, state->nalloc_psel);
-    }
-    /* Append the token to the stored string */
-    strncpy(state->pselstr + state->pslen, str, len);
-    state->pslen += len;
-    state->pselstr[state->pslen] = 0;
-}
-
-int
-_gmx_sel_init_lexer(yyscan_t *scannerp, struct gmx_ana_selcollection_t *sc,
-                    gmx_bool bInteractive, int maxnr,
-                    struct gmx_ana_indexgrps_t *grps)
-{
-    gmx_sel_lexer_t *state;
-    int              rc;
-
-    rc = _gmx_sel_yylex_init(scannerp);
-    if (rc != 0)
-    {
-        return rc;
-    }
-
-    snew(state, 1);
-    state->sc        = sc;
-    state->grps      = grps;
-    state->nexpsel   = (maxnr > 0 ? sc->nr + maxnr : -1);
-
-    state->bInteractive = bInteractive;
-    state->nalloc_input = 0;
-    state->inputstr     = NULL;
-
-    snew(state->pselstr, STRSTORE_ALLOCSTEP);
-    state->pselstr[0]   = 0;
-    state->pslen        = 0;
-    state->nalloc_psel  = STRSTORE_ALLOCSTEP;
-
-    snew(state->mstack, 20);
-    state->mstack_alloc = 20;
-    state->msp          = -1;
-    state->neom         = 0;
-    state->nextparam    = NULL;
-    state->nextmethod   = NULL;
-    state->prev_pos_kw  = 0;
-    state->bBoolNo      = FALSE;
-    state->bMatchOf     = FALSE;
-    state->bMatchBool   = FALSE;
-    state->bCmdStart    = TRUE;
-    state->bBuffer      = FALSE;
-
-    _gmx_sel_yyset_extra(state, *scannerp);
-    return 0;
-}
-
-void
-_gmx_sel_free_lexer(yyscan_t scanner)
-{
-    gmx_sel_lexer_t *state = _gmx_sel_yyget_extra(scanner);
-
-    sfree(state->inputstr);
-    sfree(state->pselstr);
-    sfree(state->mstack);
-    if (state->bBuffer)
-    {
-        _gmx_sel_yy_delete_buffer(state->buffer, scanner);
-    }
-    sfree(state);
-    _gmx_sel_yylex_destroy(scanner);
-}
-
-gmx_bool
-_gmx_sel_is_lexer_interactive(yyscan_t scanner)
-{
-    gmx_sel_lexer_t *state = _gmx_sel_yyget_extra(scanner);
-    return state->bInteractive;
-}
-
-struct gmx_ana_selcollection_t *
-_gmx_sel_lexer_selcollection(yyscan_t scanner)
-{
-    gmx_sel_lexer_t *state = _gmx_sel_yyget_extra(scanner);
-    return state->sc;
-}
-
-struct gmx_ana_indexgrps_t *
-_gmx_sel_lexer_indexgrps(yyscan_t scanner)
-{
-    gmx_sel_lexer_t *state = _gmx_sel_yyget_extra(scanner);
-    return state->grps;
-}
-
-int
-_gmx_sel_lexer_exp_selcount(yyscan_t scanner)
-{
-    gmx_sel_lexer_t *state = _gmx_sel_yyget_extra(scanner);
-    return state->nexpsel;
-}
-
-const char *
-_gmx_sel_lexer_pselstr(yyscan_t scanner)
-{
-    gmx_sel_lexer_t *state = _gmx_sel_yyget_extra(scanner);
-    return state->pselstr;
-}
-
-void
-_gmx_sel_lexer_clear_pselstr(yyscan_t scanner)
-{
-    gmx_sel_lexer_t *state = _gmx_sel_yyget_extra(scanner);
-    state->pselstr[0] = 0;
-    state->pslen      = 0;
-}
-
-void
-_gmx_sel_lexer_clear_method_stack(yyscan_t scanner)
-{
-    gmx_sel_lexer_t *state = _gmx_sel_yyget_extra(scanner);
-
-    state->msp = -1;
-}
-
-void
-_gmx_sel_finish_method(yyscan_t scanner)
-{
-    gmx_sel_lexer_t *state = _gmx_sel_yyget_extra(scanner);
-
-    if (state->msp >= 0)
-    {
-        --state->msp;
-    }
-}
-
-void
-_gmx_sel_set_lex_input_file(yyscan_t scanner, FILE *fp)
-{
-    gmx_sel_lexer_t *state = _gmx_sel_yyget_extra(scanner);
-
-    state->bBuffer = TRUE;
-    state->buffer  = _gmx_sel_yy_create_buffer(fp, YY_BUF_SIZE, scanner);
-    _gmx_sel_yy_switch_to_buffer(state->buffer, scanner);
-}
-
-void
-_gmx_sel_set_lex_input_str(yyscan_t scanner, const char *str)
-{
-    gmx_sel_lexer_t *state = _gmx_sel_yyget_extra(scanner);
-
-    if (state->bBuffer)
-    {
-        _gmx_sel_yy_delete_buffer(state->buffer, scanner);
-    }
-    state->bBuffer = TRUE;
-    state->buffer  = _gmx_sel_yy_scan_string(str, scanner);
-}
diff --git a/src/gmxlib/selection/scanner_internal.h b/src/gmxlib/selection/scanner_internal.h
deleted file mode 100644 (file)
index 802c8f7..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- *
- *                This source code is part of
- *
- *                 G   R   O   M   A   C   S
- *
- *          GROningen MAchine for Chemical Simulations
- *
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
- * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
- * Copyright (c) 2001-2009, The GROMACS development team,
- * check out http://www.gromacs.org for more information.
-
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * If you want to redistribute modifications, please consider that
- * scientific software is very special. Version control is crucial -
- * bugs must be traceable. We will be happy to consider code for
- * inclusion in the official distribution, but derived work must not
- * be called official GROMACS. Details are found in the README & COPYING
- * files - if they are missing, get the official version at www.gromacs.org.
- *
- * To help us fund GROMACS development, we humbly ask that you cite
- * the papers on the package - you can find them in the top README file.
- *
- * For more info, check our website at http://www.gromacs.org
- */
-/*! \internal \file
- * \brief Internal header file used by the selection tokenizer.
- */
-#ifndef SELECTION_SCANNER_INTERNAL_H
-#define SELECTION_SCANNER_INTERNAL_H
-
-#include "parser.h"
-
-/** The scanning function generated by Flex. */
-#define YY_DECL int _gmx_sel_yylex(YYSTYPE *yylval, yyscan_t yyscanner)
-YY_DECL;
-
-/* These need to be defined before including scanner_flex.h, because it
- * uses YY_EXTRA_TYPE. But we also need to include it before defining
- * gmx_sel_lexer_t; hence the forward declaration. */
-struct gmx_sel_lexer_t;
-#define YY_EXTRA_TYPE struct gmx_sel_lexer_t *
-
-/* We cannot include scanner_flex.h from the scanner itself, because it
- * seems to break everything. */
-/* And we need to define YY_NO_UNISTD_H here as well, otherwise unistd.h
- * gets included in other files than scanner.c... */
-#ifndef FLEX_SCANNER
-#define YY_NO_UNISTD_H
-#include "scanner_flex.h"
-#endif
-
-/*! \brief
- * Internal data structure for the selection tokenizer state.
- */
-typedef struct gmx_sel_lexer_t
-{
-    struct gmx_ana_selcollection_t  *sc;
-    struct gmx_ana_indexgrps_t      *grps;
-    int                              nexpsel;
-
-    gmx_bool                             bInteractive;
-    char                            *inputstr;
-    int                              nalloc_input;
-
-    char                            *pselstr;
-    int                              pslen;
-    int                              nalloc_psel;
-
-    struct gmx_ana_selmethod_t     **mstack;
-    int                              msp;
-    int                              mstack_alloc;
-
-    int                              neom;
-    struct gmx_ana_selparam_t       *nextparam;
-    gmx_bool                             bBoolNo;
-    struct gmx_ana_selmethod_t      *nextmethod;
-    int                              prev_pos_kw;
-
-    gmx_bool                             bMatchOf;
-    gmx_bool                             bMatchBool;
-    gmx_bool                             bCmdStart;
-
-    gmx_bool                             bBuffer;
-    YY_BUFFER_STATE                  buffer;
-} gmx_sel_lexer_t;
-
-/* Because Flex defines yylval, yytext, and yyleng as macros,
- * and this file is included from scanner.l,
- * we cannot have them here as parameter names... */
-/** Internal function for cases where several tokens need to be returned. */
-int
-_gmx_sel_lexer_process_pending(YYSTYPE *, gmx_sel_lexer_t *state);
-/** Internal function that processes identifier tokens. */
-int
-_gmx_sel_lexer_process_identifier(YYSTYPE *, char *, size_t,
-                                  gmx_sel_lexer_t *state);
-/** Internal function to add a token to the pretty-printed selection text. */
-void
-_gmx_sel_lexer_add_token(const char *str, int len, gmx_sel_lexer_t *state);
-
-#endif
diff --git a/src/gmxlib/selection/selcollection.h b/src/gmxlib/selection/selcollection.h
deleted file mode 100644 (file)
index 909c878..0000000
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- *
- *                This source code is part of
- *
- *                 G   R   O   M   A   C   S
- *
- *          GROningen MAchine for Chemical Simulations
- *
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
- * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
- * Copyright (c) 2001-2009, The GROMACS development team,
- * check out http://www.gromacs.org for more information.
-
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * If you want to redistribute modifications, please consider that
- * scientific software is very special. Version control is crucial -
- * bugs must be traceable. We will be happy to consider code for
- * inclusion in the official distribution, but derived work must not
- * be called official GROMACS. Details are found in the README & COPYING
- * files - if they are missing, get the official version at www.gromacs.org.
- *
- * To help us fund GROMACS development, we humbly ask that you cite
- * the papers on the package - you can find them in the top README file.
- *
- * For more info, check our website at http://www.gromacs.org
- */
-/*! \internal \file
- * \brief Definition of \c gmx_ana_selcollection_t.
- *
- * This is an implementation header: there should be no need to use it outside
- * this directory.
- */
-#ifndef SELECTION_COLLECTION_H
-#define SELECTION_COLLECTION_H
-
-#include <typedefs.h>
-
-#include <indexutil.h>
-
-/*! \internal
- * \brief
- * Information for a collection of selections.
- *
- * The functions to deal with the structure are defined in selection.h.
- * The structure is allocated with gmx_ana_selcollection_create() and
- * freed with gmx_ana_selcollection_free().
- * Some default values must then be set with
- * gmx_ana_selcollection_set_refpostype() and
- * gmx_ana_selcollection_set_outpostype().
- *
- * After setting the default values, one or more selections can be parsed
- * with gmx_ana_selcollection_parse_*().
- * At latest at this point, the topology must be set with
- * gmx_ana_selcollection_set_topology() unless
- * gmx_ana_selcollection_requires_top() returns FALSE.
- * Once all selections are parsed, they must be compiled all at once using
- * gmx_ana_selcollection_compile().
- * After these calls, gmx_ana_selcollection_get_count() and 
- * gmx_ana_selcollection_get_selections() can be used
- * to get the compiled selections.
- * gmx_ana_selcollection_evaluate() can be used to update the selections for a
- * new frame.
- * gmx_ana_selcollection_evaluate_fin() can be called after all the frames have
- * been processed to restore the selection values back to the ones they were
- * after gmx_ana_selcollection_compile(), i.e., dynamic selections have the
- * maximal index group as their value.
- *
- * At any point, gmx_ana_selcollection_requires_top() can be called to see
- * whether the information provided so far requires loading the topology.
- * gmx_ana_selcollection_print_tree() can be used to print the internal
- * representation of the selections (mostly useful for debugging).
- */
-struct gmx_ana_selcollection_t
-{
-    /** Default reference position type for selections. */
-    const char                 *rpost;
-    /** Default output position type for selections. */
-    const char                 *spost;
-    /** TRUE if \ref POS_MASKONLY should be used for output position evaluation. */
-    gmx_bool                        bMaskOnly;
-    /** TRUE if velocities should be evaluated for output positions. */
-    gmx_bool                        bVelocities;
-    /** TRUE if forces should be evaluated for output positions. */
-    gmx_bool                        bForces;
-    /** TRUE if debugging output should be printed during compilation. */
-    gmx_bool                        bDebugCompile;
-
-    /** Root of the selection element tree. */
-    struct t_selelem           *root;
-    /** Number of selections in \p sel. */
-    int                         nr;
-    /** Array of compiled selections. */
-    struct gmx_ana_selection_t **sel;
-    /** Number of variables defined. */
-    int                            nvars;
-    /** Selection strings for variables. */
-    char                         **varstrs;
-
-    /** Topology for the collection. */
-    t_topology                    *top;
-    /** Index group that contains all the atoms. */
-    struct gmx_ana_index_t         gall;
-    /** Position calculation collection used for selection position evaluation. */
-    struct gmx_ana_poscalc_coll_t *pcc;
-    /** Memory pool used for selection evaluation. */
-    struct gmx_sel_mempool_t      *mempool;
-    /** Parser symbol table. */
-    struct gmx_sel_symtab_t     *symtab;
-};
-
-/** Clears the symbol table in the collection */
-void
-_gmx_selcollection_clear_symtab(struct gmx_ana_selcollection_t *sc);
-
-#endif
diff --git a/src/gmxlib/selection/selection.c b/src/gmxlib/selection/selection.c
deleted file mode 100644 (file)
index 17a9cf7..0000000
+++ /dev/null
@@ -1,438 +0,0 @@
-/*
- *
- *                This source code is part of
- *
- *                 G   R   O   M   A   C   S
- *
- *          GROningen MAchine for Chemical Simulations
- *
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
- * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
- * Copyright (c) 2001-2009, The GROMACS development team,
- * check out http://www.gromacs.org for more information.
-
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * If you want to redistribute modifications, please consider that
- * scientific software is very special. Version control is crucial -
- * bugs must be traceable. We will be happy to consider code for
- * inclusion in the official distribution, but derived work must not
- * be called official GROMACS. Details are found in the README & COPYING
- * files - if they are missing, get the official version at www.gromacs.org.
- *
- * To help us fund GROMACS development, we humbly ask that you cite
- * the papers on the package - you can find them in the top README file.
- *
- * For more info, check our website at http://www.gromacs.org
- */
-/*! \internal \file
- * \brief
- * Implementation of functions in selection.h.
- */
-/*! \internal \dir src/gmxlib/selection
- * \brief
- * Source code for selection-related routines.
- */
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <smalloc.h>
-#include <statutil.h>
-#include <string2.h>
-#include <xvgr.h>
-#include <gmx_fatal.h>
-
-#include <poscalc.h>
-#include <selection.h>
-#include <selmethod.h>
-
-#include "mempool.h"
-#include "selcollection.h"
-#include "selelem.h"
-#include "symrec.h"
-
-/*!
- * \param[out] scp Pointer to a newly allocated empty selection collection.
- * \param[in]  pcc Position calculation data structure to use for selection
- *   position evaluation.
- * \returns    0 on success.
- */
-int
-gmx_ana_selcollection_create(gmx_ana_selcollection_t **scp,
-                             gmx_ana_poscalc_coll_t *pcc)
-{
-    gmx_ana_selcollection_t *sc;
-    
-    snew(sc, 1);
-    sc->rpost     = NULL;
-    sc->spost     = NULL;
-    sc->bMaskOnly = FALSE;
-    sc->bVelocities = FALSE;
-    sc->bForces   = FALSE;
-    sc->bDebugCompile = FALSE;
-    sc->root      = NULL;
-    sc->nr        = 0;
-    sc->sel       = NULL;
-    sc->nvars     = 0;
-    sc->varstrs   = NULL;
-    sc->top       = NULL;
-    gmx_ana_index_clear(&sc->gall);
-    sc->pcc       = pcc;
-    sc->mempool   = NULL;
-    _gmx_sel_symtab_create(&sc->symtab);
-    *scp = sc;
-    return 0;
-}
-
-/*!
- * \param[in,out] sc Selection collection to free.
- *
- * The pointer \p sc is invalid after the call.
- */
-void
-gmx_ana_selcollection_free(gmx_ana_selcollection_t *sc)
-{
-    int  i;
-
-    _gmx_selelem_free_chain(sc->root);
-    if (sc->sel)
-    {
-        for (i = 0; i < sc->nr; ++i)
-        {
-            gmx_ana_selection_free(sc->sel[i]);
-        }
-    }
-    sfree(sc->sel);
-    for (i = 0; i < sc->nvars; ++i)
-    {
-        sfree(sc->varstrs[i]);
-    }
-    sfree(sc->varstrs);
-    gmx_ana_index_deinit(&sc->gall);
-    if (sc->mempool)
-    {
-        _gmx_sel_mempool_destroy(sc->mempool);
-    }
-    _gmx_selcollection_clear_symtab(sc);
-    sfree(sc);
-}
-
-/*!
- * \param[in,out] sc Selection collection.
- */
-void
-_gmx_selcollection_clear_symtab(gmx_ana_selcollection_t *sc)
-{
-    if (sc->symtab)
-    {
-        _gmx_sel_symtab_free(sc->symtab);
-        sc->symtab = NULL;
-    }
-}
-
-/*!
- * \param[in,out] sc        Selection collection to modify.
- * \param[in]     type      Default selection reference position type
- *   (one of the strings acceptable for gmx_ana_poscalc_type_from_enum()).
- *
- * Should be called before calling gmx_ana_selcollection_requires_top() or
- * gmx_ana_selcollection_parse_*().
- */
-void
-gmx_ana_selcollection_set_refpostype(gmx_ana_selcollection_t *sc,
-                                     const char *type)
-{
-    sc->rpost     = type;
-}
-
-/*!
- * \param[in,out] sc        Selection collection to modify.
- * \param[in]     type      Default selection output position type
- *   (one of the strings acceptable for gmx_ana_poslcalc_type_from_enum()).
- * \param[in]     bMaskOnly If TRUE, the output positions are initialized
- *   using \ref POS_MASKONLY.
- *
- * If \p type is NULL, the default type is not modified.
- * Should be called before calling gmx_ana_selcollection_requires_top() or
- * gmx_ana_selcollection_parse_*().
- */
-void
-gmx_ana_selcollection_set_outpostype(gmx_ana_selcollection_t *sc,
-                                     const char *type, gmx_bool bMaskOnly)
-{
-    if (type)
-    {
-        sc->spost     = type;
-    }
-    sc->bMaskOnly = bMaskOnly;
-}
-
-/*!
- * \param[in,out] sc        Selection collection to modify.
- * \param[in]     bVelOut   If TRUE, selections will also evaluate
- *      velocities.
- */
-void
-gmx_ana_selcollection_set_veloutput(gmx_ana_selcollection_t *sc,
-                                    gmx_bool bVelOut)
-{
-    sc->bVelocities = bVelOut;
-}
-
-/*!
- * \param[in,out] sc        Selection collection to modify.
- * \param[in]     bForceOut If TRUE, selections will also evaluate
- *      forces.
- */
-void
-gmx_ana_selcollection_set_forceoutput(gmx_ana_selcollection_t *sc,
-                                      gmx_bool bForceOut)
-{
-    sc->bForces = bForceOut;
-}
-
-/*!
- * \param[in,out] sc        Selection collection to set the topology for.
- * \param[in]     top       Topology data.
- * \param[in]     natoms    Number of atoms. If <=0, the number of atoms in the
- *   topology is used.
- * \returns       0 on success, EINVAL if \p top is NULL and \p natoms <= 0.
- *
- * The topology is also set for the position calculation collection
- * associated with \p sc.
- *
- * \p natoms determines the largest atom index that can be selected by the
- * selection: even if the topology contains more atoms, they will not be
- * selected.
- */
-int
-gmx_ana_selcollection_set_topology(gmx_ana_selcollection_t *sc, t_topology *top,
-                                   int natoms)
-{
-    gmx_ana_poscalc_coll_set_topology(sc->pcc, top);
-    sc->top = top;
-
-    /* Get the number of atoms from the topology if it is not given */
-    if (natoms <= 0)
-    {
-        if (!sc->top)
-        {
-            gmx_incons("selections need either the topology or the number of atoms");
-            return EINVAL;
-        }
-        natoms = sc->top->atoms.nr;
-    }
-    gmx_ana_index_init_simple(&sc->gall, natoms, NULL);
-    return 0;
-}
-
-/*!
- * \param[in]  sc  Selection collection to query.
- * \returns    Number of selections in \p sc.
- *
- * If gmx_ana_selcollection_parse_*() has not been called, returns 0.
- *
- * \see gmx_ana_selcollection_get_selection()
- */
-int
-gmx_ana_selcollection_get_count(gmx_ana_selcollection_t *sc)
-{
-    return sc->nr;
-}
-
-/*!
- * \param[in]  sc  Selection collection to query.
- * \param[in]  i   Number of the selection.
- * \returns    Pointer to the \p i'th selection in \p sc,
- *   or NULL if there is no such selection.
- *
- * \p i should be between 0 and the value returned by
- * gmx_ana_selcollection_get_count().
- * The returned pointer should not be freed.
- * If gmx_ana_selcollection_compile() has not been called, the returned
- * selection is not completely initialized (but the returned pointer will be
- * valid even after compilation, and will point to the initialized selection).
- *
- * \see gmx_ana_selcollection_get_count()
- */
-gmx_ana_selection_t *
-gmx_ana_selcollection_get_selection(gmx_ana_selcollection_t *sc, int i)
-{
-    if (i < 0 || i >= sc->nr || !sc->sel)
-        return NULL;
-    return sc->sel[i];
-}
-
-/*!
- * \param[in]  sc  Selection collection to query.
- * \returns    TRUE if any selection in \p sc requires topology information,
- *   FALSE otherwise.
- *
- * Before gmx_ana_selcollection_parse_*(), the return value is based just on
- * the position types set.
- * After gmx_ana_selcollection_parse_*(), the return value also takes into account the
- * selection keywords used.
- */
-gmx_bool
-gmx_ana_selcollection_requires_top(gmx_ana_selcollection_t *sc)
-{
-    t_selelem   *sel;
-    e_poscalc_t  type;
-    int          flags;
-    int          rc;
-
-    if (sc->rpost)
-    {
-        flags = 0;
-        rc = gmx_ana_poscalc_type_from_enum(sc->rpost, &type, &flags);
-        if (rc == 0 && type != POS_ATOM)
-        {
-            return TRUE;
-        }
-    }
-    if (sc->spost)
-    {
-        flags = 0;
-        rc = gmx_ana_poscalc_type_from_enum(sc->spost, &type, &flags);
-        if (rc == 0 && type != POS_ATOM)
-        {
-            return TRUE;
-        }
-    }
-
-    sel = sc->root;
-    while (sel)
-    {
-        if (_gmx_selelem_requires_top(sel))
-        {
-            return TRUE;
-        }
-        sel = sel->next;
-    }
-    return FALSE;
-}
-
-/*!
- * \param[in] fp      File handle to receive the output.
- * \param[in] sc      Selection collection to print.
- * \param[in] bValues If TRUE, the evaluated values of selection elements
- *   are printed as well.
- */
-void
-gmx_ana_selcollection_print_tree(FILE *fp, gmx_ana_selcollection_t *sc, gmx_bool bValues)
-{
-    t_selelem *sel;
-
-    sel = sc->root;
-    while (sel)
-    {
-        _gmx_selelem_print_tree(fp, sel, bValues, 0);
-        sel = sel->next;
-    }
-}
-
-/*!
- * \param[in] sel  Selection to free.
- *
- * After the call, the pointer \p sel is invalid.
- */
-void
-gmx_ana_selection_free(gmx_ana_selection_t *sel)
-{
-    sfree(sel->name);
-    sfree(sel->selstr);
-    gmx_ana_pos_deinit(&sel->p);
-    if (sel->m != sel->orgm)
-    {
-        sfree(sel->m);
-    }
-    if (sel->q != sel->orgq)
-    {
-        sfree(sel->q);
-    }
-    sfree(sel->orgm);
-    sfree(sel->orgq);
-    sfree(sel);
-}
-
-/*!
- * \param[in] sel  Selection whose name is needed.
- * \returns   Pointer to the name of the selection.
- *
- * The return value should not be freed by the caller.
- */
-char *
-gmx_ana_selection_name(gmx_ana_selection_t *sel)
-{
-    return sel->name;
-}
-
-/*!
- * \param[in] sel  Selection for which information should be printed.
- */
-void
-gmx_ana_selection_print_info(gmx_ana_selection_t *sel)
-{
-    fprintf(stderr, "\"%s\" (%d position%s, %d atom%s%s)", sel->name,
-            sel->p.nr,     sel->p.nr     == 1 ? "" : "s",
-            sel->g->isize, sel->g->isize == 1 ? "" : "s",
-            sel->bDynamic ? ", dynamic" : "");
-    fprintf(stderr, "\n");
-}
-
-/*!
- * \param[in] sel  Selection to initialize.
- * \param[in] type Type of covered fraction required.
- * \returns   TRUE if the covered fraction can be calculated for the selection,
- *   FALSE otherwise.    
- */
-gmx_bool
-gmx_ana_selection_init_coverfrac(gmx_ana_selection_t *sel, e_coverfrac_t type)
-{
-    sel->cfractype = type;
-    if (type == CFRAC_NONE || !sel->selelem)
-    {
-        sel->bCFracDyn = FALSE;
-    }
-    else if (!_gmx_selelem_can_estimate_cover(sel->selelem))
-    {
-        sel->cfractype = CFRAC_NONE;
-        sel->bCFracDyn = FALSE;
-    }
-    else
-    {
-        sel->bCFracDyn = TRUE;
-    }
-    sel->cfrac     = sel->bCFracDyn ? 0.0 : 1.0;
-    sel->avecfrac  = sel->cfrac;
-    return type == CFRAC_NONE || sel->cfractype != CFRAC_NONE;
-}
-
-/*!
- * \param[in] out  Output file.
- * \param[in] sc   Selection collection which should be written.
- * \param[in] oenv Output options structure.
- */
-void xvgr_selcollection(FILE *out, gmx_ana_selcollection_t *sc,
-                        const output_env_t oenv)
-{
-    int  i;
-
-    if (output_env_get_xvg_format(oenv) != exvgNONE && sc)
-    {
-        fprintf(out, "# Selections:\n");
-        for (i = 0; i < sc->nvars; ++i)
-        {
-            fprintf(out, "#   %s\n", sc->varstrs[i]);
-        }
-        for (i = 0; i < sc->nr; ++i)
-        {
-            fprintf(out, "#   %s\n", sc->sel[i]->selstr);
-        }
-        fprintf(out, "#\n");
-    }
-}
diff --git a/src/gmxlib/selection/selelem.c b/src/gmxlib/selection/selelem.c
deleted file mode 100644 (file)
index 09971c0..0000000
+++ /dev/null
@@ -1,685 +0,0 @@
-/*
- *
- *                This source code is part of
- *
- *                 G   R   O   M   A   C   S
- *
- *          GROningen MAchine for Chemical Simulations
- *
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
- * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
- * Copyright (c) 2001-2009, The GROMACS development team,
- * check out http://www.gromacs.org for more information.
-
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * If you want to redistribute modifications, please consider that
- * scientific software is very special. Version control is crucial -
- * bugs must be traceable. We will be happy to consider code for
- * inclusion in the official distribution, but derived work must not
- * be called official GROMACS. Details are found in the README & COPYING
- * files - if they are missing, get the official version at www.gromacs.org.
- *
- * To help us fund GROMACS development, we humbly ask that you cite
- * the papers on the package - you can find them in the top README file.
- *
- * For more info, check our website at http://www.gromacs.org
- */
-/*! \internal \file
- * \brief Implementation of functions in selelem.h.
- */
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <smalloc.h>
-#include <gmx_fatal.h>
-
-#include <indexutil.h>
-#include <poscalc.h>
-#include <position.h>
-#include <selmethod.h>
-
-#include "keywords.h"
-#include "mempool.h"
-#include "selelem.h"
-
-/*!
- * \param[in] sel Selection for which the string is requested
- * \returns   Pointer to a string that corresponds to \p sel->type.
- *
- * The return value points to a string constant and should not be \p free'd.
- * 
- * The function returns NULL if \p sel->type is not one of the valid values.
- */
-const char *
-_gmx_selelem_type_str(t_selelem *sel)
-{
-    switch (sel->type)
-    {
-        case SEL_CONST:      return "CONST";
-        case SEL_EXPRESSION: return "EXPR";
-        case SEL_BOOLEAN:    return "BOOL";
-        case SEL_ARITHMETIC: return "ARITH";
-        case SEL_ROOT:       return "ROOT";
-        case SEL_SUBEXPR:    return "SUBEXPR";
-        case SEL_SUBEXPRREF: return "REF";
-        case SEL_MODIFIER:   return "MODIFIER";
-    }
-    return NULL;
-}
-
-/*!
- * \param[in] val Value structore for which the string is requested.
- * \returns   Pointer to a string that corresponds to \p val->type,
- *   NULL if the type value is invalid.
- *
- * The return value points to a string constant and should not be \p free'd.
- */
-const char *
-_gmx_sel_value_type_str(gmx_ana_selvalue_t *val)
-{
-    switch (val->type)
-    {
-        case NO_VALUE:       return "NONE";
-        case INT_VALUE:      return "INT";
-        case REAL_VALUE:     return "REAL";
-        case STR_VALUE:      return "STR";
-        case POS_VALUE:      return "VEC";
-        case GROUP_VALUE:    return "GROUP";
-    }
-    return NULL;
-}
-
-/*! \copydoc _gmx_selelem_type_str() */
-const char *
-_gmx_selelem_gmx_boolean_type_str(t_selelem *sel)
-{
-    switch (sel->u.boolt)
-    {
-        case BOOL_NOT:  return "NOT"; break;
-        case BOOL_AND:  return "AND"; break;
-        case BOOL_OR:   return "OR";  break;
-        case BOOL_XOR:  return "XOR"; break;
-    }
-    return NULL;
-}
-
-/*!
- * \param[in] type Type of selection element to allocate.
- * \returns   Pointer to the newly allocated and initialized element.
- *
- * \c t_selelem::type is set to \p type,
- * \c t_selelem::v::type is set to \ref GROUP_VALUE for gmx_boolean and comparison
- * expressions and \ref NO_VALUE for others,
- * \ref SEL_ALLOCVAL is set for non-root elements (\ref SEL_ALLOCDATA is also
- * set for \ref SEL_BOOLEAN elements),
- * and \c t_selelem::refcount is set to one.
- * All the pointers are set to NULL.
- */
-t_selelem *
-_gmx_selelem_create(e_selelem_t type)
-{
-    t_selelem *sel;
-
-    snew(sel, 1);
-    sel->name       = NULL;
-    sel->type       = type;
-    sel->flags      = (type != SEL_ROOT) ? SEL_ALLOCVAL : 0;
-    if (type == SEL_BOOLEAN)
-    {
-        sel->v.type = GROUP_VALUE;
-        sel->flags |= SEL_ALLOCDATA;
-    }
-    else
-    {
-        sel->v.type = NO_VALUE;
-    }
-    _gmx_selvalue_clear(&sel->v);
-    sel->evaluate   = NULL;
-    sel->mempool    = NULL;
-    sel->child      = NULL;
-    sel->next       = NULL;
-    sel->refcount   = 1;
-
-    return sel;
-}
-
-/*!
- * \param[in,out] sel   Selection element to set the type for.
- * \param[in]     vtype Value type for the selection element.
- * \returns       0 on success, EINVAL if the value type is invalid.
- *
- * If the new type is \ref GROUP_VALUE or \ref POS_VALUE, the
- * \ref SEL_ALLOCDATA flag is also set.
- *
- * This function should only be called at most once for each element,
- * preferably right after calling _gmx_selelem_create().
- */
-int
-_gmx_selelem_set_vtype(t_selelem *sel, e_selvalue_t vtype)
-{
-    if (sel->type == SEL_BOOLEAN && vtype != GROUP_VALUE)
-    {
-        gmx_bug("internal error");
-        return EINVAL;
-    }
-    if (sel->v.type != NO_VALUE && vtype != sel->v.type)
-    {
-        gmx_call("_gmx_selelem_set_vtype() called more than once");
-        return EINVAL;
-    }
-    sel->v.type = vtype;
-    if (vtype == GROUP_VALUE || vtype == POS_VALUE)
-    {
-        sel->flags |= SEL_ALLOCDATA;
-    }
-    return 0;
-}
-
-/*!
- * \param[in,out] sel   Selection element to reserve.
- * \param[in]     count Number of values to reserve memory for.
- * \returns       0 on success or if no memory pool, non-zero on error.
- *
- * Reserves memory for the values of \p sel from the \p sel->mempool
- * memory pool. If no memory pool is set, nothing is done.
- */
-int
-_gmx_selelem_mempool_reserve(t_selelem *sel, int count)
-{
-    int rc = 0;
-
-    if (!sel->mempool)
-    {
-        return 0;
-    }
-    switch (sel->v.type)
-    {
-        case INT_VALUE:
-            rc = _gmx_sel_mempool_alloc(sel->mempool, (void **)&sel->v.u.i,
-                                        sizeof(*sel->v.u.i)*count);
-            break;
-
-        case REAL_VALUE:
-            rc = _gmx_sel_mempool_alloc(sel->mempool, (void **)&sel->v.u.r,
-                                        sizeof(*sel->v.u.r)*count);
-            break;
-
-        case GROUP_VALUE:
-            rc = _gmx_sel_mempool_alloc_group(sel->mempool, sel->v.u.g, count);
-            break;
-
-        default:
-            gmx_incons("mem pooling not implemented for requested type");
-            return -1;
-    }
-    return rc;
-}
-
-/*!
- * \param[in,out] sel   Selection element to release.
- *
- * Releases the memory allocated for the values of \p sel from the
- * \p sel->mempool memory pool. If no memory pool is set, nothing is done.
- */
-void
-_gmx_selelem_mempool_release(t_selelem *sel)
-{
-    if (!sel->mempool)
-    {
-        return;
-    }
-    switch (sel->v.type)
-    {
-        case INT_VALUE:
-        case REAL_VALUE:
-            _gmx_sel_mempool_free(sel->mempool, sel->v.u.ptr);
-            _gmx_selvalue_setstore(&sel->v, NULL);
-            break;
-
-        case GROUP_VALUE:
-            if (sel->v.u.g)
-            {
-                _gmx_sel_mempool_free_group(sel->mempool, sel->v.u.g);
-            }
-            break;
-
-        default:
-            gmx_incons("mem pooling not implemented for requested type");
-            break;
-    }
-}
-
-/*!
- * \param[in] sel Selection to free.
- */
-void
-_gmx_selelem_free_values(t_selelem *sel)
-{
-    int   i, n;
-
-    _gmx_selelem_mempool_release(sel);
-    if ((sel->flags & SEL_ALLOCDATA) && sel->v.u.ptr)
-    {
-        /* The number of position/group structures is constant, so the
-         * backup of using sel->v.nr should work for them.
-         * For strings, we report an error if we don't know the allocation
-         * size here. */
-        n = (sel->v.nalloc > 0) ? sel->v.nalloc : sel->v.nr;
-        switch (sel->v.type)
-        {
-            case STR_VALUE:
-                if (sel->v.nalloc == 0)
-                {
-                    gmx_bug("SEL_ALLOCDATA should only be set for allocated STR_VALUE values");
-                    break;
-                }
-                for (i = 0; i < n; ++i)
-                {
-                    sfree(sel->v.u.s[i]);
-                }
-                break;
-            case POS_VALUE:
-                for (i = 0; i < n; ++i)
-                {
-                    gmx_ana_pos_deinit(&sel->v.u.p[i]);
-                }
-                break;
-            case GROUP_VALUE:
-                for (i = 0; i < n; ++i)
-                {
-                    gmx_ana_index_deinit(&sel->v.u.g[i]);
-                }
-                break;
-            default: /* No special handling for other types */
-                break;
-        }
-    }
-    if (sel->flags & SEL_ALLOCVAL)
-    {
-        sfree(sel->v.u.ptr);
-    }
-    _gmx_selvalue_setstore(&sel->v, NULL);
-    if (sel->type == SEL_SUBEXPRREF && sel->u.param)
-    {
-        sel->u.param->val.u.ptr = NULL;
-    }
-}
-
-/*!
- * \param[in] method Method to free.
- * \param[in] mdata  Method data to free.
- */
-void
-_gmx_selelem_free_method(gmx_ana_selmethod_t *method, void *mdata)
-{
-    sel_freefunc free_func = NULL;
-
-    /* Save the pointer to the free function. */
-    if (method && method->free)
-    {
-        free_func = method->free;
-    }
-
-    /* Free the method itself.
-     * Has to be done before freeing the method data, because parameter
-     * values are typically stored in the method data, and here we may
-     * access them. */
-    if (method)
-    {
-        int  i, j;
-
-        /* Free the memory allocated for the parameters that are not managed
-         * by the selection method itself. */
-        for (i = 0; i < method->nparams; ++i)
-        {
-            gmx_ana_selparam_t *param = &method->param[i];
-
-            if (param->val.u.ptr)
-            {
-                if (param->val.type == GROUP_VALUE)
-                {
-                    for (j = 0; j < param->val.nr; ++j)
-                    {
-                        gmx_ana_index_deinit(&param->val.u.g[j]);
-                    }
-                }
-                else if (param->val.type == POS_VALUE)
-                {
-                    for (j = 0; j < param->val.nr; ++j)
-                    {
-                        gmx_ana_pos_deinit(&param->val.u.p[j]);
-                    }
-                }
-
-                if (param->val.nalloc > 0)
-                {
-                    sfree(param->val.u.ptr);
-                }
-            }
-        }
-        sfree(method->param);
-        sfree(method);
-    }
-    /* Free method data. */
-    if (mdata)
-    {
-        if (free_func)
-        {
-            free_func(mdata);
-        }
-        sfree(mdata);
-    }
-}
-
-/*!
- * \param[in] sel Selection to free.
- */
-void
-_gmx_selelem_free_exprdata(t_selelem *sel)
-{
-    if (sel->type == SEL_EXPRESSION || sel->type == SEL_MODIFIER)
-    {
-        _gmx_selelem_free_method(sel->u.expr.method, sel->u.expr.mdata);
-        sel->u.expr.mdata = NULL;
-        sel->u.expr.method = NULL;
-        /* Free position data */
-        if (sel->u.expr.pos)
-        {
-            gmx_ana_pos_free(sel->u.expr.pos);
-            sel->u.expr.pos = NULL;
-        }
-        /* Free position calculation data */
-        if (sel->u.expr.pc)
-        {
-            gmx_ana_poscalc_free(sel->u.expr.pc);
-            sel->u.expr.pc = NULL;
-        }
-    }
-    if (sel->type == SEL_ARITHMETIC)
-    {
-        sfree(sel->u.arith.opstr);
-        sel->u.arith.opstr = NULL;
-    }
-    if (sel->type == SEL_SUBEXPR || sel->type == SEL_ROOT
-        || (sel->type == SEL_CONST && sel->v.type == GROUP_VALUE))
-    {
-        gmx_ana_index_deinit(&sel->u.cgrp);
-    }
-}
-
-/*!
- * \param[in] sel Selection to free.
- *
- * Decrements \ref t_selelem::refcount "sel->refcount" and frees the
- * memory allocated for \p sel and all its children if the reference count
- * reaches zero.
- */
-void
-_gmx_selelem_free(t_selelem *sel)
-{
-    /* Decrement the reference counter and do nothing if references remain */
-    sel->refcount--;
-    if (sel->refcount > 0)
-    {
-        return;
-    }
-
-    /* Free the children.
-     * Must be done before freeing other data, because the children may hold
-     * references to data in this element. */
-    _gmx_selelem_free_chain(sel->child);
-
-    /* Free value storage */
-    _gmx_selelem_free_values(sel);
-
-    /* Free other storage */
-    _gmx_selelem_free_exprdata(sel);
-
-    /* Free temporary compiler data if present */
-    _gmx_selelem_free_compiler_data(sel);
-
-    sfree(sel);
-}
-
-/*!
- * \param[in] first First selection to free.
- *
- * Frees \p first and all selections accessible through the
- * \ref t_selelem::next "first->next" pointer.
- */
-void
-_gmx_selelem_free_chain(t_selelem *first)
-{
-    t_selelem *child, *prev;
-
-    child = first;
-    while (child)
-    {
-        prev = child;
-        child = child->next;
-        _gmx_selelem_free(prev);
-    }
-}
-
-/*!
- * \param[in] fp      File handle to receive the output.
- * \param[in] sel     Root of the selection subtree to print.
- * \param[in] bValues If TRUE, the evaluated values of selection elements
- *   are printed as well.
- * \param[in] level   Indentation level, starting from zero.
- */
-void
-_gmx_selelem_print_tree(FILE *fp, t_selelem *sel, gmx_bool bValues, int level)
-{
-    t_selelem *child;
-    int          i;
-
-    fprintf(fp, "%*c %s %s", level*2+1, '*',
-            _gmx_selelem_type_str(sel), _gmx_sel_value_type_str(&sel->v));
-    if (sel->name)
-    {
-        fprintf(fp, " \"%s\"", sel->name);
-    }
-    fprintf(fp, " flg=");
-    if (sel->flags & SEL_FLAGSSET)
-    {
-        fprintf(fp, "s");
-    }
-    if (sel->flags & SEL_SINGLEVAL)
-    {
-        fprintf(fp, "S");
-    }
-    if (sel->flags & SEL_ATOMVAL)
-    {
-        fprintf(fp, "A");
-    }
-    if (sel->flags & SEL_VARNUMVAL)
-    {
-        fprintf(fp, "V");
-    }
-    if (sel->flags & SEL_DYNAMIC)
-    {
-        fprintf(fp, "D");
-    }
-    if (!(sel->flags & SEL_VALFLAGMASK))
-    {
-        fprintf(fp, "0");
-    }
-    if (sel->mempool)
-    {
-        fprintf(fp, "P");
-    }
-    if (sel->type == SEL_CONST)
-    {
-        if (sel->v.type == INT_VALUE)
-        {
-            fprintf(fp, " %d", sel->v.u.i[0]);
-        }
-        else if (sel->v.type == REAL_VALUE)
-        {
-            fprintf(fp, " %f", sel->v.u.r[0]);
-        }
-        else if (sel->v.type == GROUP_VALUE)
-        {
-            gmx_ana_index_t *g = sel->v.u.g;
-            if (!g || g->isize == 0)
-                g = &sel->u.cgrp;
-            fprintf(fp, " (%d atoms)", g->isize);
-        }
-    }
-    else if (sel->type == SEL_BOOLEAN)
-    {
-        fprintf(fp, " %s", _gmx_selelem_gmx_boolean_type_str(sel));
-    }
-    else if (sel->type == SEL_EXPRESSION
-             && sel->u.expr.method->name == sm_compare.name)
-    {
-        _gmx_selelem_print_compare_info(fp, sel->u.expr.mdata);
-    }
-    if (sel->evaluate)
-    {
-        fprintf(fp, " eval=");
-        _gmx_sel_print_evalfunc_name(fp, sel->evaluate);
-    }
-    if (sel->refcount > 1)
-    {
-        fprintf(fp, " refc=%d", sel->refcount);
-    }
-    if (!(sel->flags & SEL_ALLOCVAL))
-    {
-        fprintf(fp, " (ext. output)");
-    }
-    fprintf(fp, "\n");
-
-    if ((sel->type == SEL_CONST && sel->v.type == GROUP_VALUE) || sel->type == SEL_ROOT)
-    {
-        gmx_ana_index_t *g = sel->v.u.g;
-        if (!g || g->isize == 0 || sel->evaluate != NULL)
-        {
-            g = &sel->u.cgrp;
-        }
-        if (g->isize < 0)
-        {
-            fprintf(fp, "%*c group: (null)\n", level*2+1, ' ');
-        }
-        else if (g->isize > 0)
-        {
-            fprintf(fp, "%*c group:", level*2+1, ' ');
-            if (g->isize <= 20)
-            {
-                for (i = 0; i < g->isize; ++i)
-                {
-                    fprintf(fp, " %d", g->index[i] + 1);
-                }
-            }
-            else
-            {
-                fprintf(fp, " %d atoms", g->isize);
-            }
-            fprintf(fp, "\n");
-        }
-    }
-    else if (sel->type == SEL_EXPRESSION)
-    {
-        if (sel->u.expr.pc)
-        {
-            fprintf(fp, "%*c COM", level*2+3, '*');
-            fprintf(fp, "\n");
-        }
-    }
-
-    if (sel->cdata)
-    {
-        _gmx_selelem_print_compiler_info(fp, sel, level);
-    }
-
-    if (bValues && sel->type != SEL_CONST && sel->type != SEL_ROOT && sel->v.u.ptr)
-    {
-        fprintf(fp, "%*c value: ", level*2+1, ' ');
-        switch (sel->v.type)
-        {
-            case POS_VALUE:
-                /* In normal use, the pointer should never be NULL, but it's
-                 * useful to have the check for debugging to avoid accidental
-                 * segfaults when printing the selection tree. */
-                if (sel->v.u.p->x)
-                {
-                    fprintf(fp, "(%f, %f, %f)",
-                            sel->v.u.p->x[0][XX], sel->v.u.p->x[0][YY],
-                            sel->v.u.p->x[0][ZZ]);
-                }
-                else
-                {
-                    fprintf(fp, "(null)");
-                }
-                break;
-            case GROUP_VALUE:
-                fprintf(fp, "%d atoms", sel->v.u.g->isize);
-                if (sel->v.u.g->isize < 20)
-                {
-                    if (sel->v.u.g->isize > 0)
-                    {
-                        fprintf(fp, ":");
-                    }
-                    for (i = 0; i < sel->v.u.g->isize; ++i)
-                    {
-                        fprintf(fp, " %d", sel->v.u.g->index[i] + 1);
-                    }
-                }
-                break;
-            default:
-                fprintf(fp, "???");
-                break;
-        }
-        fprintf(fp, "\n");
-    }
-
-    /* Print the subexpressions with one more level of indentation */
-    child = sel->child;
-    while (child)
-    {
-        if (!(sel->type == SEL_SUBEXPRREF && child->type == SEL_SUBEXPR))
-        {
-            _gmx_selelem_print_tree(fp, child, bValues, level+1);
-        }
-        child = child->next;
-    }
-}
-
-/*!
- * \param[in] root Root of the subtree to query.
- * \returns TRUE if \p root or any any of its elements require topology
- *   information, FALSE otherwise.
- */
-gmx_bool
-_gmx_selelem_requires_top(t_selelem *root)
-{
-    t_selelem *child;
-
-    if (root->type == SEL_EXPRESSION || root->type == SEL_MODIFIER)
-    {
-        if (root->u.expr.method && (root->u.expr.method->flags & SMETH_REQTOP))
-        {
-            return TRUE;
-        }
-        if (root->u.expr.pc && gmx_ana_poscalc_requires_top(root->u.expr.pc))
-        {
-            return TRUE;
-        }
-    }
-    child = root->child;
-    while (child)
-    {
-        if (_gmx_selelem_requires_top(child))
-        {
-            return TRUE;
-        }
-        child = child->next;
-    }
-    return FALSE;
-}
diff --git a/src/gmxlib/selection/selelem.h b/src/gmxlib/selection/selelem.h
deleted file mode 100644 (file)
index 571d8a1..0000000
+++ /dev/null
@@ -1,371 +0,0 @@
-/*
- *
- *                This source code is part of
- *
- *                 G   R   O   M   A   C   S
- *
- *          GROningen MAchine for Chemical Simulations
- *
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
- * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
- * Copyright (c) 2001-2009, The GROMACS development team,
- * check out http://www.gromacs.org for more information.
-
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * If you want to redistribute modifications, please consider that
- * scientific software is very special. Version control is crucial -
- * bugs must be traceable. We will be happy to consider code for
- * inclusion in the official distribution, but derived work must not
- * be called official GROMACS. Details are found in the README & COPYING
- * files - if they are missing, get the official version at www.gromacs.org.
- *
- * To help us fund GROMACS development, we humbly ask that you cite
- * the papers on the package - you can find them in the top README file.
- *
- * For more info, check our website at http://www.gromacs.org
- */
-/*! \internal \file
- * \brief Definition of \c t_selelem and related things.
- *
- * The selection element trees constructed by the parser and the compiler
- * are described on the respective pages:
- * \ref selparser and \ref selcompiler.
- *
- * This is an implementation header: there should be no need to use it outside
- * this directory.
- */
-#ifndef SELECTION_ELEMENT_H
-#define SELECTION_ELEMENT_H
-
-#include <types/simple.h>
-
-#include <indexutil.h>
-#include <selvalue.h>
-
-struct gmx_ana_poscalc_t;
-struct gmx_ana_selparam_t;
-struct gmx_ana_selmethod_t;
-
-struct gmx_sel_evaluate_t;
-struct gmx_sel_mempool_t;
-struct t_selelem;
-
-/********************************************************************/
-/*! \name Enumerations for expression types
- ********************************************************************/
-/*@{*/
-
-/** Defines the type of a \c t_selelem object. */
-typedef enum
-{
-    /** Constant-valued expression. */
-    SEL_CONST,
-    /** Method expression that requires evaluation. */
-    SEL_EXPRESSION,
-    /** Boolean expression. */
-    SEL_BOOLEAN,
-    /** Arithmetic expression. */
-    SEL_ARITHMETIC,
-    /** Root node of the evaluation tree. */
-    SEL_ROOT,
-    /** Subexpression that may be referenced several times. */
-    SEL_SUBEXPR,
-    /** Reference to a subexpression. */
-    SEL_SUBEXPRREF,
-    /** Post-processing of selection value. */
-    SEL_MODIFIER
-} e_selelem_t;
-
-/** Defines the gmx_boolean operation of \c t_selelem objects with type \ref SEL_BOOLEAN. */
-typedef enum
-{
-    BOOL_NOT,           /**< Not */
-    BOOL_AND,           /**< And */
-    BOOL_OR,            /**< Or */
-    BOOL_XOR            /**< Xor (not implemented). */
-} e_boolean_t;
-
-/** Defines the arithmetic operation of \c t_selelem objects with type \ref SEL_ARITHMETIC. */
-typedef enum
-{
-    ARITH_PLUS,         /**< + */
-    ARITH_MINUS,        /**< - */
-    ARITH_NEG,          /**< Unary - */
-    ARITH_MULT,         /**< * */
-    ARITH_DIV,          /**< / */
-    ARITH_EXP           /**< ^ (to power) */
-} e_arithmetic_t;
-
-/** Returns a string representation of the type of a \c t_selelem. */
-extern const char *
-_gmx_selelem_type_str(struct t_selelem *sel);
-/** Returns a string representation of the gmx_boolean type of a \ref SEL_BOOLEAN \c t_selelem. */
-extern const char *
-_gmx_selelem_gmx_boolean_type_str(struct t_selelem *sel);
-/** Returns a string representation of the type of a \c gmx_ana_selvalue_t. */
-extern const char *
-_gmx_sel_value_type_str(gmx_ana_selvalue_t *val);
-
-/*@}*/
-
-
-/********************************************************************/
-/*! \name Selection expression flags
- * \anchor selelem_flags
- ********************************************************************/
-/*@{*/
-/*! \brief
- * Selection value flags are set.
- *
- * If this flag is set, the flags covered by \ref SEL_VALFLAGMASK
- * have been set properly for the element.
- */
-#define SEL_FLAGSSET    1
-/*! \brief
- * The element evaluates to a single value.
- *
- * This flag is always set for \ref GROUP_VALUE elements.
- */
-#define SEL_SINGLEVAL   2
-/*! \brief
- * The element evaluates to one value for each input atom.
- */
-#define SEL_ATOMVAL     4
-/*! \brief
- * The element evaluates to an arbitrary number of values.
- */
-#define SEL_VARNUMVAL   8
-/*! \brief
- * The element (or one of its children) is dynamic.
- */
-#define SEL_DYNAMIC     16
-/*! \brief
- * Mask that covers the flags that describe the number of values.
- */
-#define SEL_VALTYPEMASK (SEL_SINGLEVAL | SEL_ATOMVAL | SEL_VARNUMVAL)
-/*! \brief
- * Mask that covers the flags that describe the value type.
- */
-#define SEL_VALFLAGMASK (SEL_FLAGSSET | SEL_VALTYPEMASK | SEL_DYNAMIC)
-/*! \brief
- * Data has been allocated for the \p v.u union.
- *
- * If not set, the \p v.u.ptr points to data allocated externally.
- * This is the case if the value of the element is used as a parameter
- * for a selection method or if the element evaluates the final value of
- * a selection.
- *
- * Even if the flag is set, \p v.u.ptr can be NULL during initialization.
- *
- * \todo
- * This flag overlaps with the function of \p v.nalloc field, and could
- * probably be removed, making memory management simpler. Currently, the
- * \p v.nalloc field is not kept up-to-date in all cases when this flag
- * is changed and is used in places where this flag is not, so this would
- * require a careful investigation of the selection code.
- */
-#define SEL_ALLOCVAL    (1<<8)
-/*! \brief
- * Data has been allocated for the group/position structure.
- *
- * If not set, the memory allocated for fields in \p v.u.g or \p v.u.p is
- * managed externally.
- *
- * This field has no effect if the value type is not \ref GROUP_VALUE or
- * \ref POS_VALUE, but should not be set.
- */
-#define SEL_ALLOCDATA   (1<<9)
-/*! \brief
- * \p method->init_frame should be called for the frame.
- */
-#define SEL_INITFRAME   (1<<10)
-/*! \brief
- * Parameter has been evaluated for the current frame.
- *
- * This flag is set for children of \ref SEL_EXPRESSION elements (which
- * describe method parameters) after the element has been evaluated for the
- * current frame.
- * It is not set for \ref SEL_ATOMVAL elements, because they may need to
- * be evaluated multiple times.
- */
-#define SEL_EVALFRAME   (1<<11)
-/*! \brief
- * \p method->init has been called.
- */
-#define SEL_METHODINIT  (1<<12)
-/*! \brief
- * \p method->outinit has been called.
- *
- * This flag is also used for \ref SEL_SUBEXPRREF elements.
- */
-#define SEL_OUTINIT     (1<<13)
-/*@}*/
-
-
-/********************************************************************/
-/*! \name Selection expression data structures and functions
- ********************************************************************/
-/*@{*/
-
-struct t_selelem;
-
-/*! \brief
- * Function pointer for evaluating a \c t_selelem.
- */
-typedef int (*sel_evalfunc)(struct gmx_sel_evaluate_t *data,
-                            struct t_selelem *sel, gmx_ana_index_t *g);
-
-/*! \internal \brief
- * Represents an element of a selection expression.
- */
-typedef struct t_selelem
-{
-    /*! \brief Name of the element.
-     *
-     * This field is only used for informative purposes.
-     * It is always either NULL or a pointer to a string.
-     * Memory is never allocated for it directly.
-     */
-    const char                         *name;
-    /** Type of the element. */
-    e_selelem_t                         type;
-    /*! \brief
-     * Value storage of the element.
-     *
-     * This field contains the evaluated value of the element, as well as
-     * the output value type.
-     */
-    gmx_ana_selvalue_t                  v;
-    /*! \brief
-     * Evaluation function for the element.
-     *
-     * Can be either NULL (if the expression is a constant and does not require
-     * evaluation) or point to one of the functions defined in evaluate.h.
-     */
-    sel_evalfunc                        evaluate;
-    /*! \brief
-     * Information flags about the element.
-     *
-     * Allowed flags are listed here:
-     * \ref selelem_flags "flags for \c t_selelem".
-     */
-    int                                 flags;
-    /** Data required by the evaluation function. */
-    union {
-        /*! \brief Index group data for several element types.
-         *
-         *  - \ref SEL_CONST : if the value type is \ref GROUP_VALUE,
-         *    this field holds the unprocessed group value.
-         *  - \ref SEL_ROOT : holds the group value for which the
-         *    selection subtree should be evaluated.
-         *  - \ref SEL_SUBEXPR : holds the group for which the subexpression
-         *    has been evaluated.
-         */
-        gmx_ana_index_t                 cgrp;
-        /** Data for \ref SEL_EXPRESSION and \ref SEL_MODIFIER elements. */
-        struct {
-            /** Pointer the the method used in this expression. */
-            struct gmx_ana_selmethod_t *method;
-            /** Pointer to the data allocated by the method's \p init_data (see sel_datafunc()). */
-            void                       *mdata;
-            /** Pointer to the position data passed to the method. */
-            struct gmx_ana_pos_t       *pos;
-            /** Pointer to the evaluation data for \p pos. */
-            struct gmx_ana_poscalc_t   *pc;
-        }                               expr;
-        /** Operation type for \ref SEL_BOOLEAN elements. */
-        e_boolean_t                     boolt;
-        /** Operation type for \ref SEL_ARITHMETIC elements. */
-        struct {
-            /** Operation type. */
-            e_arithmetic_t              type;
-            /** String representation. */
-            char                       *opstr;
-        }                               arith;
-        /** Associated selection parameter for \ref SEL_SUBEXPRREF elements. */
-        struct gmx_ana_selparam_t      *param;
-    }                                   u;
-    /** Memory pool to use for values, or NULL if standard memory handling. */
-    struct gmx_sel_mempool_t           *mempool;
-    /** Internal data for the selection compiler. */
-    struct t_compiler_data             *cdata;
-    
-    /*! \brief The first child element.
-     *
-     * Other children can be accessed through the \p next field of \p child.
-     */
-    struct t_selelem                    *child;
-    /** The next sibling element. */
-    struct t_selelem                    *next;
-    /*! \brief Number of references to this element.
-     *
-     * Should be larger than one only for \ref SEL_SUBEXPR elements.
-     */
-    int                                  refcount;
-} t_selelem;
-
-/* In evaluate.c */
-/** Writes out a human-readable name for an evaluation function. */
-extern void
-_gmx_sel_print_evalfunc_name(FILE *fp, sel_evalfunc evalfunc);
-
-/** Allocates memory and performs some common initialization for a \c t_selelem. */
-extern t_selelem *
-_gmx_selelem_create(e_selelem_t type);
-/** Sets the value type of a \c t_selelem. */
-extern int
-_gmx_selelem_set_vtype(t_selelem *sel, e_selvalue_t vtype);
-/** Reserves memory for value of a \c t_selelem from a memory pool. */
-extern int
-_gmx_selelem_mempool_reserve(t_selelem *sel, int count);
-/** Releases memory pool used for value of a \c t_selelem. */
-extern void
-_gmx_selelem_mempool_release(t_selelem *sel);
-/** Frees the memory allocated for a \c t_selelem structure and all its children. */
-extern void
-_gmx_selelem_free(t_selelem *sel);
-/** Frees the memory allocated for a \c t_selelem structure, all its children, and also all structures referenced through t_selelem::next fields. */
-extern void
-_gmx_selelem_free_chain(t_selelem *first);
-
-/** Frees the memory allocated for the \c t_selelem::d union. */
-extern void
-_gmx_selelem_free_values(t_selelem *sel);
-/** Frees the memory allocated for a selection method. */
-extern void
-_gmx_selelem_free_method(struct gmx_ana_selmethod_t *method, void *mdata);
-/** Frees the memory allocated for the \c t_selelem::u field. */
-extern void
-_gmx_selelem_free_exprdata(t_selelem *sel);
-/* In compiler.c */
-/** Frees the memory allocated for the selection compiler. */
-extern void
-_gmx_selelem_free_compiler_data(t_selelem *sel);
-
-/** Prints a human-readable version of a selection element subtree. */
-extern void
-_gmx_selelem_print_tree(FILE *fp, t_selelem *root, gmx_bool bValues, int level);
-/* In compile.c */
-/** Prints a human-readable version of the internal compiler data structure. */
-extern void
-_gmx_selelem_print_compiler_info(FILE *fp, t_selelem *sel, int level);
-
-/** Returns TRUE if the selection element subtree requires topology information for evaluation. */
-extern gmx_bool
-_gmx_selelem_requires_top(t_selelem *root);
-
-/* In sm_insolidangle.c */
-/** Returns TRUE if the covered fraction of the selection can be calculated. */
-extern gmx_bool
-_gmx_selelem_can_estimate_cover(t_selelem *sel);
-/** Returns the covered fraction of the selection for the current frame. */
-extern real
-_gmx_selelem_estimate_coverfrac(t_selelem *sel);
-
-/*@}*/
-
-#endif
diff --git a/src/gmxlib/selection/selhelp.c b/src/gmxlib/selection/selhelp.c
deleted file mode 100644 (file)
index 0bbe59f..0000000
+++ /dev/null
@@ -1,477 +0,0 @@
-/*
- *
- *                This source code is part of
- *
- *                 G   R   O   M   A   C   S
- *
- *          GROningen MAchine for Chemical Simulations
- *
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
- * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
- * Copyright (c) 2001-2009, The GROMACS development team,
- * check out http://www.gromacs.org for more information.
-
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * If you want to redistribute modifications, please consider that
- * scientific software is very special. Version control is crucial -
- * bugs must be traceable. We will be happy to consider code for
- * inclusion in the official distribution, but derived work must not
- * be called official GROMACS. Details are found in the README & COPYING
- * files - if they are missing, get the official version at www.gromacs.org.
- *
- * To help us fund GROMACS development, we humbly ask that you cite
- * the papers on the package - you can find them in the top README file.
- *
- * For more info, check our website at http://www.gromacs.org
- */
-/*! \internal \file
- * \brief Implementation of functions in selhelp.c.
- */
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <macros.h>
-#include <string2.h>
-#include <wman.h>
-
-#include "selcollection.h"
-#include "selmethod.h"
-#include "selhelp.h"
-#include "symrec.h"
-
-typedef struct {
-    const char  *topic;
-    int          nl;
-    const char **text;
-} t_selection_help_item;
-
-static const char *help_common[] = {
-    "SELECTION HELP[PAR]",
-
-    "This program supports selections in addition to traditional index files.",
-    "Please read the subtopic pages (available through \"help topic\") for",
-    "more information.",
-    "Explanation of command-line arguments for specifying selections can be",
-    "found under the \"cmdline\" subtopic, and general selection syntax is",
-    "described under \"syntax\". Available keywords can be found under",
-    "\"keywords\", and concrete examples under \"examples\".",
-    "Other subtopics give more details on certain aspects.",
-    "\"help all\" prints the help for all subtopics.",
-};
-
-static const char *help_arithmetic[] = {
-    "ARITHMETIC EXPRESSIONS IN SELECTIONS[PAR]",
-
-    "Basic arithmetic evaluation is supported for numeric expressions.",
-    "Supported operations are addition, subtraction, negation, multiplication,",
-    "division, and exponentiation (using ^).",
-    "Result of a division by zero or other illegal operations is undefined.",
-};
-
-static const char *help_cmdline[] = {
-    "SELECTION COMMAND-LINE ARGUMENTS[PAR]",
-
-    "There are two alternative command-line arguments for specifying",
-    "selections:[BR]",
-    "1. [TT]-select[tt] can be used to specify the complete selection as a",
-    "string on the command line.[BR]",
-    "2. [TT]-sf[tt] can be used to specify a file name from which the",
-    "selection is read.[BR]",
-    "If both options are specified, [TT]-select[tt] takes precedence.",
-    "If neither of the above is present, the user is prompted to type the",
-    "selection on the standard input (a pipe can also be used to provide",
-    "the selections in this case).",
-    "This is also done if an empty string is passed to [TT]-select[tt].[PAR]",
-
-    "Option [TT]-n[tt] can be used to provide an index file.",
-    "If no index file is provided, default groups are generated.",
-    "In both cases, the user can also select an index group instead of",
-    "writing a full selection.",
-    "The default groups are generated by reading selections from a file",
-    "[TT]defselection.dat[tt]. If such a file is found in the current",
-    "directory, it is used instead of the one provided by default.[PAR]",
-
-    "Depending on the tool, two additional command-line arguments may be",
-    "available to control the behavior:[BR]",
-    "1. [TT]-seltype[tt] can be used to specify the default type of",
-    "positions to calculate for each selection.[BR]",
-    "2. [TT]-selrpos[tt] can be used to specify the default type of",
-    "positions used in selecting atoms by coordinates.[BR]",
-    "See \"help positions\" for more information on these options.",
-};
-
-static const char *help_eval[] = {
-    "SELECTION EVALUATION AND OPTIMIZATION[PAR]",
-
-    "Boolean evaluation proceeds from left to right and is short-circuiting",
-    "i.e., as soon as it is known whether an atom will be selected, the",
-    "remaining expressions are not evaluated at all.",
-    "This can be used to optimize the selections: you should write the",
-    "most restrictive and/or the most inexpensive expressions first in",
-    "boolean expressions.",
-    "The relative ordering between dynamic and static expressions does not",
-    "matter: all static expressions are evaluated only once, before the first",
-    "frame, and the result becomes the leftmost expression.[PAR]",
-
-    "Another point for optimization is in common subexpressions: they are not",
-    "automatically recognized, but can be manually optimized by the use of",
-    "variables. This can have a big impact on the performance of complex",
-    "selections, in particular if you define several index groups like this:",
-    "  [TT]rdist = distance from com of resnr 1 to 5;[tt][BR]",
-    "  [TT]resname RES and rdist < 2;[tt][BR]",
-    "  [TT]resname RES and rdist < 4;[tt][BR]",
-    "  [TT]resname RES and rdist < 6;[tt][BR]",
-    "Without the variable assignment, the distances would be evaluated three",
-    "times, although they are exactly the same within each selection.",
-    "Anything assigned into a variable becomes a common subexpression that",
-    "is evaluated only once during a frame.",
-    "Currently, in some cases the use of variables can actually lead to a small",
-    "performance loss because of the checks necessary to determine for which",
-    "atoms the expression has already been evaluated, but this should not be",
-    "a major problem.",
-};
-
-static const char *help_examples[] = {
-    "SELECTION EXAMPLES[PAR]",
-
-    "Below, examples of increasingly complex selections are given.[PAR]",
-
-    "Selection of all water oxygens:[BR]",
-    "  resname SOL and name OW",
-    "[PAR]",
-
-    "Centers of mass of residues 1 to 5 and 10:[BR]",
-    "  res_com of resnr 1 to 5 10",
-    "[PAR]",
-
-    "All atoms farther than 1 nm of a fixed position:[BR]",
-    "  not within 1 of (1.2, 3.1, 2.4)",
-    "[PAR]",
-
-    "All atoms of a residue LIG within 0.5 nm of a protein (with a custom name):[BR]",
-    "  \"Close to protein\" resname LIG and within 0.5 of group \"Protein\"",
-    "[PAR]",
-
-    "All protein residues that have at least one atom within 0.5 nm of a residue LIG:[BR]",
-    "  group \"Protein\" and same residue as within 0.5 of resname LIG",
-    "[PAR]",
-
-    "All RES residues whose COM is between 2 and 4 nm from the COM of all of them:[BR]",
-    "  rdist = res_com distance from com of resname RES[BR]",
-    "  resname RES and rdist >= 2 and rdist <= 4",
-    "[PAR]",
-
-    "Selection like C1 C2 C2 C3 C3 C4 ... C8 C9 (e.g., for g_bond):[BR]",
-    "  name \"C[1-8]\" merge name \"C[2-9]\"",
-};
-
-static const char *help_keywords[] = {
-    "SELECTION KEYWORDS[PAR]",
-
-    "The following selection keywords are currently available.",
-    "For keywords marked with a star, additional help is available through",
-    "\"help KEYWORD\", where KEYWORD is the name of the keyword.",
-};
-
-static const char *help_limits[] = {
-    "SELECTION LIMITATIONS[PAR]",
-
-    "Some analysis programs may require a special structure for the input",
-    "selections (e.g., [TT]g_angle[tt] requires the index group to be made",
-    "of groups of three or four atoms).",
-    "For such programs, it is up to the user to provide a proper selection",
-    "expression that always returns such positions.",
-    "[PAR]",
-
-    "Due to technical reasons, having a negative value as the first value in",
-    "expressions like[BR]",
-    "[TT]charge -1 to -0.7[tt][BR]",
-    "result in a syntax error. A workaround is to write[BR]",
-    "[TT]charge {-1 to -0.7}[tt][BR]",
-    "instead.",
-};
-
-static const char *help_positions[] = {
-    "SPECIFYING POSITIONS[PAR]",
-
-    "Possible ways of specifying positions in selections are:[PAR]",
-
-    "1. A constant position can be defined as [TT][XX, YY, ZZ][tt], where",
-    "[TT]XX[tt], [TT]YY[tt] and [TT]ZZ[tt] are real numbers.[PAR]",
-
-    "2. [TT]com of ATOM_EXPR [pbc][tt] or [TT]cog of ATOM_EXPR [pbc][tt]",
-    "calculate the center of mass/geometry of [TT]ATOM_EXPR[tt]. If",
-    "[TT]pbc[tt] is specified, the center is calculated iteratively to try",
-    "to deal with cases where [TT]ATOM_EXPR[tt] wraps around periodic",
-    "boundary conditions.[PAR]",
-
-    "3. [TT]POSTYPE of ATOM_EXPR[tt] calculates the specified positions for",
-    "the atoms in [TT]ATOM_EXPR[tt].",
-    "[TT]POSTYPE[tt] can be [TT]atom[tt], [TT]res_com[tt], [TT]res_cog[tt],",
-    "[TT]mol_com[tt] or [TT]mol_cog[tt], with an optional prefix [TT]whole_[tt]",
-    "[TT]part_[tt] or [TT]dyn_[tt].",
-    "[TT]whole_[tt] calculates the centers for the whole residue/molecule,",
-    "even if only part of it is selected.",
-    "[TT]part_[tt] prefix calculates the centers for the selected atoms, but",
-    "uses always the same atoms for the same residue/molecule. The used atoms",
-    "are determined from the the largest group allowed by the selection.",
-    "[TT]dyn_[tt] calculates the centers strictly only for the selected atoms.",
-    "If no prefix is specified, whole selections default to [TT]part_[tt] and",
-    "other places default to [TT]whole_[tt].",
-    "The latter is often desirable to select the same molecules in different",
-    "tools, while the first is a compromise between speed ([TT]dyn_[tt]",
-    "positions can be slower to evaluate than [TT]part_[tt]) and intuitive",
-    "behavior.[PAR]",
-
-    "4. [TT]ATOM_EXPR[tt], when given for whole selections, is handled as 3.",
-    "above, using the position type from the command-line argument",
-    "[TT]-seltype[tt].[PAR]",
-
-    "Selection keywords that select atoms based on their positions, such as",
-    "[TT]dist from[tt], use by default the positions defined by the",
-    "[TT]-selrpos[tt] command-line option.",
-    "This can be overridden by prepending a [TT]POSTYPE[tt] specifier to the",
-    "keyword. For example, [TT]res_com dist from POS[tt] evaluates the",
-    "residue center of mass distances. In the example, all atoms of a residue",
-    "are either selected or not, based on the single distance calculated.",
-};
-
-static const char *help_syntax[] = {
-    "SELECTION SYNTAX[PAR]",
-
-    "A set of selections consists of one or more selections, separated by",
-    "semicolons. Each selection defines a set of positions for the analysis.",
-    "Each selection can also be preceded by a string that gives a name for",
-    "the selection for use in, e.g., graph legends.",
-    "If no name is provided, the string used for the selection is used",
-    "automatically as the name.[PAR]",
-
-    "For interactive input, the syntax is slightly altered: line breaks can",
-    "also be used to separate selections. \\ followed by a line break can",
-    "be used to continue a line if necessary.",
-    "Notice that the above only applies to real interactive input,",
-    "not if you provide the selections, e.g., from a pipe.[PAR]",
-
-    "It is possible to use variables to store selection expressions.",
-    "A variable is defined with the following syntax:[BR]",
-    "[TT]VARNAME = EXPR ;[tt][BR]",
-    "where [TT]EXPR[tt] is any valid selection expression.",
-    "After this, [TT]VARNAME[tt] can be used anywhere where [TT]EXPR[tt]",
-    "would be valid.[PAR]",
-
-    "Selections are composed of three main types of expressions, those that",
-    "define atoms ([TT]ATOM_EXPR[tt]s), those that define positions",
-    "([TT]POS_EXPR[tt]s), and those that evaluate to numeric values",
-    "([TT]NUM_EXPR[tt]s). Each selection should be a [TT]POS_EXPR[tt]",
-    "or a [TT]ATOM_EXPR[tt] (the latter is automatically converted to",
-    "positions). The basic rules are as follows:[BR]",
-    "1. An expression like [TT]NUM_EXPR1 < NUM_EXPR2[tt] evaluates to an",
-    "[TT]ATOM_EXPR[tt] that selects all the atoms for which the comparison",
-    "is true.[BR]",
-    "2. Atom expressions can be combined with gmx_boolean operations such as",
-    "[TT]not ATOM_EXPR[tt], [TT]ATOM_EXPR and ATOM_EXPR[tt], or",
-    "[TT]ATOM_EXPR or ATOM_EXPR[tt]. Parentheses can be used to alter the",
-    "evaluation order.[BR]",
-    "3. [TT]ATOM_EXPR[tt] expressions can be converted into [TT]POS_EXPR[tt]",
-    "expressions in various ways, see \"help positions\" for more details.[PAR]",
-
-    "Some keywords select atoms based on string values such as the atom name.",
-    "For these keywords, it is possible to use wildcards ([TT]name \"C*\"[tt])",
-    "or regular expressions (e.g., [TT]resname \"R[AB]\"[tt]).",
-    "The match type is automatically guessed from the string: if it contains",
-    "other characters than letters, numbers, '*', or '?', it is interpreted",
-    "as a regular expression.",
-    "Strings that contain non-alphanumeric characters should be enclosed in",
-    "double quotes as in the examples. For other strings, the quotes are",
-    "optional, but if the value conflicts with a reserved keyword, a syntax",
-    "error will occur. If your strings contain uppercase letters, this should",
-    "not happen.[PAR]",
-
-    "Index groups provided with the [TT]-n[tt] command-line option or",
-    "generated by default can be accessed with [TT]group NR[tt] or",
-    "[TT]group NAME[tt], where [TT]NR[tt] is a zero-based index of the group",
-    "and [TT]NAME[tt] is part of the name of the desired group.",
-    "The keyword [TT]group[tt] is optional if the whole selection is",
-    "provided from an index group.",
-    "To see a list of available groups in the interactive mode, press enter",
-    "in the beginning of a line.",
-};
-
-static const t_selection_help_item helpitems[] = {
-    {NULL,          asize(help_common),     help_common},
-    {"cmdline",     asize(help_cmdline),    help_cmdline},
-    {"syntax",      asize(help_syntax),     help_syntax},
-    {"positions",   asize(help_positions),  help_positions},
-    {"arithmetic",  asize(help_arithmetic), help_arithmetic},
-    {"keywords",    asize(help_keywords),   help_keywords},
-    {"evaluation",  asize(help_eval),       help_eval},
-    {"limitations", asize(help_limits),     help_limits},
-    {"examples",    asize(help_examples),   help_examples},
-};
-
-/*! \brief
- * Prints a brief list of keywords (selection methods) available.
- *
- * \param[in] sc    Selection collection for which the list should be printed.
- * \param[in] type  Only methods that return this type are printed.
- * \param[in] bMod  If FALSE, \ref SMETH_MODIFIER methods are excluded, otherwise
- *     only them are printed.
- */
-static void
-print_keyword_list(struct gmx_ana_selcollection_t *sc, e_selvalue_t type,
-                   gmx_bool bMod)
-{
-    gmx_sel_symrec_t *symbol;
-
-    symbol = _gmx_sel_first_symbol(sc->symtab, SYMBOL_METHOD);
-    while (symbol)
-    {
-        gmx_ana_selmethod_t *method = _gmx_sel_sym_value_method(symbol);
-        gmx_bool                 bShow;
-        bShow = (method->type == type)
-            && ((bMod && (method->flags & SMETH_MODIFIER))
-                || (!bMod && !(method->flags & SMETH_MODIFIER)));
-        if (bShow)
-        {
-            fprintf(stderr, " %c ",
-                    (method->help.nlhelp > 0 && method->help.help) ? '*' : ' ');
-            if (method->help.syntax)
-            {
-                fprintf(stderr, "%s\n", method->help.syntax);
-            }
-            else
-            {
-                const char *symname = _gmx_sel_sym_name(symbol);
-
-                fprintf(stderr, "%s", symname);
-                if (strcmp(symname, method->name) != 0)
-                {
-                    fprintf(stderr, " (synonym for %s)", method->name);
-                }
-                fprintf(stderr, "\n");
-            }
-        }
-        symbol = _gmx_sel_next_symbol(symbol, SYMBOL_METHOD);
-    }
-}
-
-/*!
- * \param[in]  sc    Selection collection for which help should be printed.
- * \param[in]  topic Topic to print help on, or NULL for general help.
- *
- * \p sc is used to get information on which keywords are available in the
- * present context.
- */
-void
-_gmx_sel_print_help(struct gmx_ana_selcollection_t *sc, const char *topic)
-{
-    const t_selection_help_item *item = NULL;
-    size_t i;
-
-    /* Find the item for the topic */
-    if (!topic)
-    {
-        item = &helpitems[0];
-    }
-    else if (strcmp(topic, "all") == 0)
-    {
-        for (i = 0; i < asize(helpitems); ++i)
-        {
-            item = &helpitems[i];
-            _gmx_sel_print_help(sc, item->topic);
-            if (i != asize(helpitems) - 1)
-            {
-                fprintf(stderr, "\n\n");
-            }
-        }
-        return;
-    }
-    else
-    {
-        for (i = 1; i < asize(helpitems); ++i)
-        {
-            if (strncmp(helpitems[i].topic, topic, strlen(topic)) == 0)
-            {
-                item = &helpitems[i];
-                break;
-            }
-        }
-    }
-    /* If the topic is not found, check the available methods.
-     * If they don't provide any help either, tell the user and exit. */
-    if (!item)
-    {
-        gmx_sel_symrec_t *symbol;
-
-        symbol = _gmx_sel_first_symbol(sc->symtab, SYMBOL_METHOD);
-        while (symbol)
-        {
-            gmx_ana_selmethod_t *method = _gmx_sel_sym_value_method(symbol);
-            if (method->help.nlhelp > 0 && method->help.help
-                && strncmp(method->name, topic, strlen(topic)) == 0)
-            {
-                print_tty_formatted(stderr, method->help.nlhelp,
-                        method->help.help, 0, NULL, NULL, FALSE);
-                return;
-            }
-            symbol = _gmx_sel_next_symbol(symbol, SYMBOL_METHOD);
-        }
-
-        fprintf(stderr, "No help available for '%s'.\n", topic);
-        return;
-    }
-    /* Print the help */
-    print_tty_formatted(stderr, item->nl, item->text, 0, NULL, NULL, FALSE);
-    /* Special handling of certain pages */
-    if (!topic)
-    {
-        int len = 0;
-
-        /* Print the subtopics on the main page */
-        fprintf(stderr, "\nAvailable subtopics:\n");
-        for (i = 1; i < asize(helpitems); ++i)
-        {
-            int len1 = strlen(helpitems[i].topic) + 2;
-
-            len += len1;
-            if (len > 79)
-            {
-                fprintf(stderr, "\n");
-                len = len1;
-            }
-            fprintf(stderr, "  %s", helpitems[i].topic);
-        }
-        fprintf(stderr, "\n");
-    }
-    else if (strcmp(item->topic, "keywords") == 0)
-    {
-        /* Print the list of keywords */
-        fprintf(stderr, "\nKeywords that select atoms by an integer property:\n");
-        fprintf(stderr, "(use in expressions or like \"atomnr 1 to 5 7 9\")\n");
-        print_keyword_list(sc, INT_VALUE, FALSE);
-
-        fprintf(stderr, "\nKeywords that select atoms by a numeric property:\n");
-        fprintf(stderr, "(use in expressions or like \"occupancy 0.5 to 1\")\n");
-        print_keyword_list(sc, REAL_VALUE, FALSE);
-
-        fprintf(stderr, "\nKeywords that select atoms by a string property:\n");
-        fprintf(stderr, "(use like \"name PATTERN [PATTERN] ...\")\n");
-        print_keyword_list(sc, STR_VALUE, FALSE);
-
-        fprintf(stderr, "\nAdditional keywords that directly select atoms:\n");
-        print_keyword_list(sc, GROUP_VALUE, FALSE);
-
-        fprintf(stderr, "\nKeywords that directly evaluate to positions:\n");
-        fprintf(stderr, "(see also \"help positions\")\n");
-        print_keyword_list(sc, POS_VALUE, FALSE);
-
-        fprintf(stderr, "\nAdditional keywords:\n");
-        print_keyword_list(sc, POS_VALUE, TRUE);
-        print_keyword_list(sc, NO_VALUE, TRUE);
-    }
-}
diff --git a/src/gmxlib/selection/selhelp.h b/src/gmxlib/selection/selhelp.h
deleted file mode 100644 (file)
index 54acb1b..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- *
- *                This source code is part of
- *
- *                 G   R   O   M   A   C   S
- *
- *          GROningen MAchine for Chemical Simulations
- *
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
- * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
- * Copyright (c) 2001-2009, The GROMACS development team,
- * check out http://www.gromacs.org for more information.
-
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * If you want to redistribute modifications, please consider that
- * scientific software is very special. Version control is crucial -
- * bugs must be traceable. We will be happy to consider code for
- * inclusion in the official distribution, but derived work must not
- * be called official GROMACS. Details are found in the README & COPYING
- * files - if they are missing, get the official version at www.gromacs.org.
- *
- * To help us fund GROMACS development, we humbly ask that you cite
- * the papers on the package - you can find them in the top README file.
- *
- * For more info, check our website at http://www.gromacs.org
- */
-/*! \internal \file
- * \brief Functions for printing help for selections.
- *
- * This is an implementation header: there should be no need to use it outside
- * this directory.
- */
-#ifndef SELECTION_HELP_H
-#define SELECTION_HELP_H
-
-struct gmx_ana_selcollection_t;
-
-/** Prints help for writing selections. */
-void
-_gmx_sel_print_help(struct gmx_ana_selcollection_t *sc, const char *topic);
-
-#endif
diff --git a/src/gmxlib/selection/selmethod.c b/src/gmxlib/selection/selmethod.c
deleted file mode 100644 (file)
index 982eaed..0000000
+++ /dev/null
@@ -1,693 +0,0 @@
-/*
- *
- *                This source code is part of
- *
- *                 G   R   O   M   A   C   S
- *
- *          GROningen MAchine for Chemical Simulations
- *
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
- * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
- * Copyright (c) 2001-2009, The GROMACS development team,
- * check out http://www.gromacs.org for more information.
-
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * If you want to redistribute modifications, please consider that
- * scientific software is very special. Version control is crucial -
- * bugs must be traceable. We will be happy to consider code for
- * inclusion in the official distribution, but derived work must not
- * be called official GROMACS. Details are found in the README & COPYING
- * files - if they are missing, get the official version at www.gromacs.org.
- *
- * To help us fund GROMACS development, we humbly ask that you cite
- * the papers on the package - you can find them in the top README file.
- *
- * For more info, check our website at http://www.gromacs.org
- */
-/*! \internal \file
- * \brief Implementation of functions in selmethod.h.
- */
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <ctype.h>
-#include <stdarg.h>
-
-#include <macros.h>
-#include <string2.h>
-
-#include <selmethod.h>
-
-#include "selcollection.h"
-#include "symrec.h"
-
-/*
- * These global variables cannot be const because gmx_ana_selmethod_register()
- * modifies them to set some defaults. This is a small price to pay for the
- * convenience of not having to remember exactly how the selection compiler
- * expects the structures to be filled, and even more so if the expectations
- * change. Also, even if the gmx_ana_selmethod_t structures were made const,
- * the parameters could not be without typecasts somewhere, because the param
- * field in gmx_ana_selmethod_t cannot be declared const.
- *
- * Even though the variables may be modified, this should be thread-safe as
- * modifications are done only in gmx_ana_selmethod_register(), and it should
- * work even if called more than once for the same structure, and even if
- * called concurrently from multiple threads (as long as the selection
- * collection is not the same).
- *
- * All of these problems should go away if/when the selection methods are
- * implemented as C++ classes.
- */
-
-/* From sm_com.c */
-extern gmx_ana_selmethod_t sm_cog;
-extern gmx_ana_selmethod_t sm_com;
-/* From sm_simple.c */
-extern gmx_ana_selmethod_t sm_all;
-extern gmx_ana_selmethod_t sm_none;
-extern gmx_ana_selmethod_t sm_atomnr;
-extern gmx_ana_selmethod_t sm_resnr;
-extern gmx_ana_selmethod_t sm_resindex;
-extern gmx_ana_selmethod_t sm_molindex;
-extern gmx_ana_selmethod_t sm_atomname;
-extern gmx_ana_selmethod_t sm_atomtype;
-extern gmx_ana_selmethod_t sm_resname;
-extern gmx_ana_selmethod_t sm_insertcode;
-extern gmx_ana_selmethod_t sm_chain;
-extern gmx_ana_selmethod_t sm_mass;
-extern gmx_ana_selmethod_t sm_charge;
-extern gmx_ana_selmethod_t sm_altloc;
-extern gmx_ana_selmethod_t sm_occupancy;
-extern gmx_ana_selmethod_t sm_betafactor;
-extern gmx_ana_selmethod_t sm_x;
-extern gmx_ana_selmethod_t sm_y;
-extern gmx_ana_selmethod_t sm_z;
-/* From sm_distance.c */
-extern gmx_ana_selmethod_t sm_distance;
-extern gmx_ana_selmethod_t sm_mindistance;
-extern gmx_ana_selmethod_t sm_within;
-/* From sm_insolidangle.c */
-extern gmx_ana_selmethod_t sm_insolidangle;
-/* From sm_same.c */
-extern gmx_ana_selmethod_t sm_same;
-
-/* From sm_merge.c */
-extern gmx_ana_selmethod_t sm_merge;
-extern gmx_ana_selmethod_t sm_plus;
-/* From sm_permute.c */
-extern gmx_ana_selmethod_t sm_permute;
-
-/*! \brief
- * Helper structure for defining selection methods.
- */
-typedef struct {
-    /*! \brief
-     * Name to register the method under.
-     *
-     * If NULL, use the actual name of the method.
-     * This field is used for defining synonyms.
-     */
-    const char            *name;
-    /** Method data structure to register. */
-    gmx_ana_selmethod_t   *method;
-} t_register_method;
-
-/** Array of selection methods defined in the library. */
-static const t_register_method smtable_def[] = {
-    {NULL,         &sm_cog},
-    {NULL,         &sm_com},
-
-    {NULL,         &sm_all},
-    {NULL,         &sm_none},
-    {NULL,         &sm_atomnr},
-    {NULL,         &sm_resnr},
-    {"resid",      &sm_resnr},
-    {NULL,         &sm_resindex},
-    {"residue",    &sm_resindex},
-    {NULL,         &sm_molindex},
-    {"mol",        &sm_molindex},
-    {"molecule",   &sm_molindex},
-    {NULL,         &sm_atomname},
-    {NULL,         &sm_atomtype},
-    {NULL,         &sm_resname},
-    {NULL,         &sm_insertcode},
-    {NULL,         &sm_chain},
-    {NULL,         &sm_mass},
-    {NULL,         &sm_charge},
-    {NULL,         &sm_altloc},
-    {NULL,         &sm_occupancy},
-    {NULL,         &sm_betafactor},
-    {NULL,         &sm_x},
-    {NULL,         &sm_y},
-    {NULL,         &sm_z},
-
-    {NULL,         &sm_distance},
-    {NULL,         &sm_mindistance},
-    {NULL,         &sm_within},
-    {NULL,         &sm_insolidangle},
-    {NULL,         &sm_same},
-
-    {NULL,         &sm_merge},
-    {NULL,         &sm_plus},
-    {NULL,         &sm_permute},
-};
-
-/*! \brief
- * Convenience function for reporting errors found in selection methods.
- */
-static void
-report_error(FILE *fp, const char *name, const char *fmt, ...)
-{
-    va_list ap;
-    va_start(ap, fmt);
-    if (fp)
-    {
-        fprintf(fp, "selection method '%s': ", name);
-        vfprintf(fp, fmt, ap);
-        fprintf(fp, "\n");
-    }
-    va_end(ap);
-}
-
-/*! \brief
- * Convenience function for reporting errors found in selection method parameters.
- */
-static void
-report_param_error(FILE *fp, const char *mname, const char *pname,
-                   const char *fmt, ...)
-{
-    va_list ap;
-    va_start(ap, fmt);
-    if (fp)
-    {
-        fprintf(fp, "selection method '%s': parameter '%s': ", mname, pname);
-        vfprintf(fp, fmt, ap);
-        fprintf(fp, "\n");
-    }
-    va_end(ap);
-}
-
-/*! \brief
- * Checks the validity of parameters.
- *
- * \param[in]     fp      File handle to use for diagnostic messages
- *   (can be NULL).
- * \param[in]     name    Name of the method (used for error messages).
- * \param[in]     nparams Number of parameters in \p param.
- * \param[in,out] param   Parameter array
- *   (only the \c flags field of gmx_boolean parameters may be modified).
- * \param[in]     symtab  Symbol table (used for checking overlaps).
- * \returns       TRUE if there are no problems with the parameters,
- *   FALSE otherwise.
- *
- * This function performs some checks common to both check_method() and
- * check_modifier().
- * The purpose of these checks is to ensure that the selection parser does not
- * need to check for the validity of the parameters at each turn, and to
- * report programming errors as early as possible.
- * If you remove a check, make sure that the parameter parser can handle the
- * resulting parameters.
- */
-static gmx_bool
-check_params(FILE *fp, const char *name, int nparams, gmx_ana_selparam_t param[],
-             gmx_sel_symtab_t *symtab)
-{
-    gmx_bool              bOk = TRUE;
-    gmx_sel_symrec_t *sym;
-    int               i, j;
-
-    if (nparams > 0 && !param)
-    {
-        report_error(fp, name, "error: missing parameter data");
-        bOk = FALSE;
-        return FALSE;
-    }
-    if (nparams == 0 && param)
-    {
-        report_error(fp, name, "warning: parameter data unused because nparams=0");
-    }
-    /* Check each parameter */
-    for (i = 0; i < nparams; ++i)
-    {
-        /* Check that there is at most one NULL name, in the beginning */
-        if (param[i].name == NULL && i > 0)
-        {
-            report_error(fp, name, "error: NULL parameter should be the first one");
-            bOk = FALSE;
-            continue;
-        }
-        /* Check for duplicates */
-        for (j = 0; j < i; ++j)
-        {
-            if (param[j].name == NULL)
-            {
-                continue;
-            }
-            if (!gmx_strcasecmp(param[i].name, param[j].name))
-            {
-                report_error(fp, name, "error: duplicate parameter name '%s'", param[i].name);
-                bOk = FALSE;
-                break;
-            }
-        }
-        /* Check flags */
-        if (param[i].flags & SPAR_SET)
-        {
-            report_param_error(fp, name, param[i].name, "warning: flag SPAR_SET is set");
-            param[i].flags &= ~SPAR_SET;
-        }
-        if (param[i].flags & SPAR_RANGES)
-        {
-            if (param[i].val.type != INT_VALUE && param[i].val.type != REAL_VALUE)
-            {
-                report_param_error(fp, name, param[i].name, "error: SPAR_RANGES cannot be set for a non-numeric parameter");
-                bOk = FALSE;
-            }
-            if (param[i].flags & SPAR_DYNAMIC)
-            {
-                report_param_error(fp, name, param[i].name, "warning: SPAR_DYNAMIC does not have effect with SPAR_RANGES");
-                param[i].flags &= ~SPAR_DYNAMIC;
-            }
-            if (!(param[i].flags & SPAR_VARNUM) && param[i].val.nr != 1)
-            {
-                report_param_error(fp, name, param[i].name, "error: range should take either one or an arbitrary number of values");
-                bOk = FALSE;
-            }
-            if (param[i].flags & SPAR_ATOMVAL)
-            {
-                report_param_error(fp, name, param[i].name, "error: SPAR_RANGES and SPAR_ATOMVAL both set");
-                bOk = FALSE;
-            }
-        }
-        if ((param[i].flags & SPAR_VARNUM) && (param[i].flags & SPAR_ATOMVAL))
-        {
-            report_param_error(fp, name, param[i].name, "error: SPAR_VARNUM and SPAR_ATOMVAL both set");
-            bOk = FALSE;
-        }
-        if (param[i].flags & SPAR_ENUMVAL)
-        {
-            if (param[i].val.type != STR_VALUE)
-            {
-                report_param_error(fp, name, param[i].name, "error: SPAR_ENUMVAL can only be set for string parameters");
-                bOk = FALSE;
-            }
-            if (param[i].val.nr != 1)
-            {
-                report_param_error(fp, name, param[i].name, "error: SPAR_ENUMVAL parameters should take exactly one value");
-                bOk = FALSE;
-            }
-            if (param[i].flags & (SPAR_DYNAMIC | SPAR_VARNUM | SPAR_ATOMVAL))
-            {
-                report_param_error(fp, name, param[i].name, "error: only SPAR_OPTIONAL supported with SPAR_ENUMVAL");
-                bOk = FALSE;
-            }
-        }
-        /* Check gmx_boolean parameters */
-        if (param[i].val.type == NO_VALUE)
-        {
-            if (param[i].val.nr != 0)
-            {
-                report_param_error(fp, name, param[i].name, "error: number of values should be zero for gmx_boolean parameters");
-                bOk = FALSE;
-            }
-            /* The gmx_boolean parameters should always be optional, so set the
-             * flag for convenience. */
-            param[i].flags |= SPAR_OPTIONAL;
-            /* Any other flags should not be specified */
-            if (param[i].flags & ~SPAR_OPTIONAL)
-            {
-                report_param_error(fp, name, param[i].name, "error: gmx_boolean parameter should not have any flags set");
-                bOk = FALSE;
-            }
-        }
-        /* Check val.nr */
-        if (param[i].flags & (SPAR_VARNUM | SPAR_ATOMVAL))
-        {
-            if (param[i].val.nr != -1)
-            {
-                report_param_error(fp, name, param[i].name, "warning: val.nr is not -1 although SPAR_VARNUM/SPAR_ATOMVAL is set");
-            }
-            param[i].val.nr = -1;
-        }
-        else if (param[i].val.type != NO_VALUE)
-        {
-            if (param[i].val.nr <= 0)
-            {
-                report_param_error(fp, name, param[i].name, "error: val.nr <= 0");
-                bOk = FALSE;
-            }
-        }
-        /* Check that the value pointer is NULL */
-        if (param[i].nvalptr != NULL)
-        {
-            report_param_error(fp, name, param[i].name, "warning: nvalptr is set");
-        }
-        if (param[i].val.u.ptr != NULL && !(param[i].flags & SPAR_ENUMVAL))
-        {
-            report_param_error(fp, name, param[i].name, "warning: value pointer is set");
-        }
-        /* Check that the name contains only valid characters */
-        if (param[i].name == NULL)
-        {
-            continue;
-        }
-        if (!isalpha(param[i].name[0]))
-        {
-            report_param_error(fp, name, param[i].name, "error: name does not begin with a letter");
-            bOk = FALSE;
-            continue;
-        }
-        for (j = 1; param[i].name[j] != 0; ++j)
-        {
-            if (param[i].name[j] != '_' && !isalnum(param[i].name[j]))
-            {
-                report_param_error(fp, name, param[i].name, "error: name contains non-alphanumeric characters");
-                bOk = FALSE;
-                break;
-            }
-        }
-        if (param[i].name[j] != 0)
-        {
-            continue;
-        }
-        /* Check that the name does not conflict with a method */
-        if (_gmx_sel_find_symbol(symtab, param[i].name, TRUE))
-        {
-            report_param_error(fp, name, param[i].name, "error: name conflicts with another method or a keyword");
-            bOk = FALSE;
-        }
-    } /* End of parameter loop */
-    /* Check parameters of existing methods */
-    sym = _gmx_sel_first_symbol(symtab, SYMBOL_METHOD);
-    while (sym)
-    {
-        gmx_ana_selmethod_t *method = _gmx_sel_sym_value_method(sym);
-        gmx_ana_selparam_t  *param =
-            gmx_ana_selmethod_find_param(name, method);
-        if (param)
-        {
-            report_param_error(fp, method->name, param->name, "error: name conflicts with another method or a keyword");
-            bOk = FALSE;
-        }
-        sym = _gmx_sel_next_symbol(sym, SYMBOL_METHOD);
-    }
-    return bOk;
-}
-
-/*! \brief
- * Checks the validity of selection method callback functions.
- *
- * \param[in] fp        File handle to use for diagnostic messages
- *   (can be NULL).
- * \param[in] method    The method to check.
- * \returns   TRUE if there are no problems, FALSE otherwise.
- *
- * This function performs some checks common to both check_method() and
- * check_modifier().
- * This function checks that all the required callbacks are defined, i.e.,
- * not NULL, to find programming errors.
- */
-static gmx_bool
-check_callbacks(FILE *fp, gmx_ana_selmethod_t *method)
-{
-    gmx_bool         bOk = TRUE;
-    gmx_bool         bNeedInit;
-    int          i;
-
-    /* Make some checks on init_data and free */
-    if (method->nparams > 0 && !method->init_data)
-    {
-        report_error(fp, method->name, "error: init_data should be provided because the method has parameters");
-        bOk = FALSE;
-    }
-    if (method->free && !method->init_data)
-    {
-        report_error(fp, method->name, "warning: free is not used because of missing init_data");
-    }
-    /* Check presence of outinit for position-valued methods */
-    if (method->type == POS_VALUE && !method->outinit)
-    {
-        report_error(fp, method->name, "error: outinit should be provided because the method has POS_VALUE");
-        bOk = FALSE;
-    }
-    /* Warn of dynamic callbacks in static methods */
-    if (!(method->flags & SMETH_MODIFIER))
-    {
-        if (method->pupdate && !(method->flags & SMETH_DYNAMIC))
-        {
-            report_error(fp, method->name, "warning: pupdate not used because the method is static");
-            method->pupdate = NULL;
-        }
-    }
-    /* Check that there is an evaluation function */
-    if (method->type != NO_VALUE && !method->update && !method->pupdate)
-    {
-        report_error(fp, method->name, "error: evaluation function missing");
-        bOk = FALSE;
-    }
-    /* Loop through the parameters to determine if initialization callbacks
-     * are needed. */
-    bNeedInit = FALSE;
-    for (i = 0; i < method->nparams; ++i)
-    {
-        if (method->param[i].val.type != POS_VALUE
-            && (method->param[i].flags & (SPAR_VARNUM | SPAR_ATOMVAL)))
-        {
-            bNeedInit = TRUE;
-        }
-    }
-    /* Check that the callbacks required by the parameters are present */
-    if (bNeedInit && !method->init)
-    {
-        report_error(fp, method->name, "error: init should be provided");
-        bOk = FALSE;
-    }
-    return bOk;
-}
-
-/*!
- * Checks the validity of a selection method.
- *
- * \param[in]     fp     File handle to use for diagnostic messages
- *   (can be NULL).
- * \param[in,out] method Method to check.
- * \param[in]     symtab Symbol table (used for checking overlaps).
- *
- * Checks the validity of the given selection method data structure
- * that does not have \ref SMETH_MODIFIER set.
- * If you remove a check, please make sure that the selection parser,
- * compiler, and evaluation functions can deal with the method.
- */
-static gmx_bool
-check_method(FILE *fp, gmx_ana_selmethod_t *method, gmx_sel_symtab_t *symtab)
-{
-    gmx_bool         bOk = TRUE;
-
-    /* Check the type */
-    if (method->type == NO_VALUE)
-    {
-        report_error(fp, method->name, "error: no value type specified");
-        bOk = FALSE;
-    }
-    if (method->type == STR_VALUE && method->nparams > 0)
-    {
-        report_error(fp, method->name, "error: evaluates to a string but is not a keyword");
-        bOk = FALSE;
-    }
-    /* Check flags */
-    if (method->type == GROUP_VALUE)
-    {
-        /* Group methods should always have SMETH_SINGLEVAL,
-         * so set it for convenience. */
-        method->flags |= SMETH_SINGLEVAL;
-        /* Check that conflicting flags are not present. */
-        if (method->flags & SMETH_VARNUMVAL)
-        {
-            report_error(fp, method->name, "error: SMETH_VARNUMVAL cannot be set for group-valued methods");
-            bOk = FALSE;
-        }
-    }
-    else
-    {
-        if ((method->flags & SMETH_SINGLEVAL)
-            && (method->flags & SMETH_VARNUMVAL))
-        {
-            report_error(fp, method->name, "error: SMETH_SINGLEVAL and SMETH_VARNUMVAL both set");
-            bOk = FALSE;
-        }
-    }
-    if ((method->flags & SMETH_CHARVAL) && method->type != STR_VALUE)
-    {
-        report_error(fp, method->name, "error: SMETH_CHARVAL can only be specified for STR_VALUE methods");
-        bOk = FALSE;
-    }
-    /* Check the parameters */
-    if (!check_params(fp, method->name, method->nparams, method->param, symtab))
-    {
-        bOk = FALSE;
-    }
-    /* Check the callback pointers */
-    if (!check_callbacks(fp, method))
-    {
-        bOk = FALSE;
-    }
-
-    return bOk;
-}
-
-/*!
- * Checks the validity of a selection modifier method.
- *
- * \param[in]     fp     File handle to use for diagnostic messages
- *   (can be NULL).
- * \param[in,out] method Method to check.
- * \param[in]     symtab Symbol table (used for checking overlaps).
- *
- * Checks the validity of the given selection method data structure
- * that has \ref SMETH_MODIFIER set.
- * If you remove a check, please make sure that the selection parser,
- * compiler, and evaluation functions can deal with the method.
- */
-static gmx_bool
-check_modifier(FILE *fp, gmx_ana_selmethod_t *method, gmx_sel_symtab_t *symtab)
-{
-    gmx_bool         bOk = TRUE;
-
-    /* Check the type */
-    if (method->type != NO_VALUE && method->type != POS_VALUE)
-    {
-        report_error(fp, method->name, "error: modifier should have type POS_VALUE or NO_VALUE");
-        bOk = FALSE;
-    }
-    /* Check flags */
-    if (method->flags & (SMETH_SINGLEVAL | SMETH_VARNUMVAL))
-    {
-        report_error(fp, method->name, "error: modifier should not have SMETH_SINGLEVAL or SMETH_VARNUMVAL set");
-        bOk = FALSE;
-    }
-    /* Check the parameters */
-    /* The first parameter is skipped */
-    if (!check_params(fp, method->name, method->nparams-1, method->param+1, symtab))
-    {
-        bOk = FALSE;
-    }
-    /* Check the callback pointers */
-    if (!check_callbacks(fp, method))
-    {
-        bOk = FALSE;
-    }
-    if (method->update)
-    {
-        report_error(fp, method->name, "error: modifier should not have update");
-        bOk = FALSE;
-    }
-    if (method->type == POS_VALUE && !method->pupdate)
-    {
-        report_error(fp, method->name, "error: evaluation function missing");
-        bOk = FALSE;
-    }
-
-    return bOk;
-}
-
-/*!
- * \param[in,out] sc     Selection collection to registered the method to.
- * \param[in]     name   Name under which the method should be registered.
- * \param[in]     method Method to register.
- * \returns       0 on success, EINVAL if there was something wrong with the
- *   method.
- *
- * \p name does not need to match the name of the method, and the same
- * method can be registered multiple times under different names.
- * If \p name equals some previously registered name,
- * an error message is printed and the method is not registered.
- *
- * The function also performs some sanity checking on the input method,
- * and refuses to register it if there are problems.
- * Some problems only generate warnings.
- * All problems are described to \p stderr.
- */
-int
-gmx_ana_selmethod_register(struct gmx_ana_selcollection_t *sc,
-                           const char *name, gmx_ana_selmethod_t *method)
-{
-    gmx_bool bOk;
-
-    /* Check the method */
-    if (method->flags & SMETH_MODIFIER)
-    {
-        bOk = check_modifier(stderr, method, sc->symtab);
-    }
-    else
-    {
-        bOk = check_method(stderr, method, sc->symtab);
-    }
-    /* Try to register the method if everything is ok */
-    if (bOk) 
-    {
-        if (!_gmx_sel_add_method_symbol(sc->symtab, name, method))
-        {
-            bOk = FALSE;
-        }
-    }
-    if (!bOk)
-    {
-        report_error(stderr, name, "warning: not registered");
-        return EINVAL;
-    }
-    return 0;
-}
-
-/*!
- * \param[in,out] sc     Selection collection to registered the methods to.
- * \returns       0 on success, -1 if any of the default methods could not be
- *   registered.
- */
-int
-gmx_ana_selmethod_register_defaults(struct gmx_ana_selcollection_t *sc)
-{
-    size_t i;
-    int  rc;
-    gmx_bool bOk;
-
-    bOk = TRUE;
-    for (i = 0; i < asize(smtable_def); ++i)
-    {
-        gmx_ana_selmethod_t *method = smtable_def[i].method;
-
-        if (smtable_def[i].name == NULL)
-        {
-            rc = gmx_ana_selmethod_register(sc, method->name, method);
-        }
-        else
-        {
-            rc = gmx_ana_selmethod_register(sc, smtable_def[i].name, method);
-        }
-        if (rc != 0)
-        {
-            bOk = FALSE;
-        }
-    }
-    return bOk ? 0 : -1;
-}
-
-/*!
- * \param[in] name   Name of the parameter to search.
- * \param[in] method Method to search for the parameter.
- * \returns   Pointer to the parameter in the
- *   \ref gmx_ana_selmethod_t::param "method->param" array,
- *   or NULL if no parameter with name \p name was found.
- *
- * This is a simple wrapper for gmx_ana_selparam_find().
- */
-gmx_ana_selparam_t *
-gmx_ana_selmethod_find_param(const char *name, gmx_ana_selmethod_t *method)
-{
-    return gmx_ana_selparam_find(name, method->nparams, method->param);
-}
diff --git a/src/gmxlib/selection/selvalue.c b/src/gmxlib/selection/selvalue.c
deleted file mode 100644 (file)
index 769bfa5..0000000
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- *
- *                This source code is part of
- *
- *                 G   R   O   M   A   C   S
- *
- *          GROningen MAchine for Chemical Simulations
- *
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
- * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
- * Copyright (c) 2001-2009, The GROMACS development team,
- * check out http://www.gromacs.org for more information.
-
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * If you want to redistribute modifications, please consider that
- * scientific software is very special. Version control is crucial -
- * bugs must be traceable. We will be happy to consider code for
- * inclusion in the official distribution, but derived work must not
- * be called official GROMACS. Details are found in the README & COPYING
- * files - if they are missing, get the official version at www.gromacs.org.
- *
- * To help us fund GROMACS development, we humbly ask that you cite
- * the papers on the package - you can find them in the top README file.
- *
- * For more info, check our website at http://www.gromacs.org
- */
-/*! \internal \file
- * \brief Implementation of functions in selvalue.h.
- */
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <smalloc.h>
-
-#include <indexutil.h>
-#include <position.h>
-#include <selvalue.h>
-
-/*!
- * \param[out] val  Output structure
- *
- * The type of \p val is not touched.
- * Any contents of \p val are discarded without freeing.
- */
-void
-_gmx_selvalue_clear(gmx_ana_selvalue_t *val)
-{
-    val->nr     = 0;
-    val->u.ptr  = NULL;
-    val->nalloc = 0;
-}
-
-/*!
- * \param[in,out] val  Value structure to allocate.
- * \param[in]     n    Maximum number of values needed.
- * \returns       Zero on success.
- *
- * Reserves memory for the values within \p val to store at least \p n values,
- * of the type specified in the \p val structure.
- *
- * If the type is \ref POS_VALUE or \ref GROUP_VALUE, memory is reserved for
- * the data structures, but no memory is reserved inside these newly allocated
- * data structures.
- * Similarly, for \ref STR_VALUE values, the pointers are set to NULL.
- * For other values, the memory is uninitialized.
- */
-int
-_gmx_selvalue_reserve(gmx_ana_selvalue_t *val, int n)
-{
-    int  i;
-
-    if (val->nalloc == -1)
-    {
-        return 0;
-    }
-
-    if (!val->u.ptr || val->nalloc < n)
-    {
-        switch (val->type)
-        {
-            case INT_VALUE:   srenew(val->u.i, n); break;
-            case REAL_VALUE:  srenew(val->u.r, n); break;
-            case STR_VALUE:
-                srenew(val->u.s, n);
-                for (i = val->nalloc; i < n; ++i)
-                {
-                    val->u.s[i] = NULL;
-                }
-                break;
-            case POS_VALUE:
-                srenew(val->u.p, n);
-                for (i = val->nalloc; i < n; ++i)
-                {
-                    gmx_ana_pos_clear(&val->u.p[i]);
-                }
-                break;
-            case GROUP_VALUE:
-                srenew(val->u.g, n);
-                for (i = val->nalloc; i < n; ++i)
-                {
-                    gmx_ana_index_clear(&val->u.g[i]);
-                }
-                break;
-            case NO_VALUE:    break;
-        }
-        val->nalloc = n;
-    }
-    return 0;
-}
-
-/*!
- * \param[in,out] val    Value structure to allocate.
- * \param[in]     ptr    Pointer where the values should be stored.
- * \returns       Zero on success.
- *
- * Automatic memory management is disabled for \p ptr, unless \p ptr is NULL.
- */
-int
-_gmx_selvalue_setstore(gmx_ana_selvalue_t *val, void *ptr)
-{
-    val->u.ptr  = ptr;
-    val->nalloc = (ptr ? -1 : 0);
-    return 0;
-}
-
-/*!
- * \param[in,out] val    Value structure to allocate.
- * \param[in]     ptr    Pointer where the values should be stored.
- * \param[in]     nalloc Number of values allocated for \p ptr.
- * \returns       Zero on success.
- */
-int
-_gmx_selvalue_setstore_alloc(gmx_ana_selvalue_t *val, void *ptr, int nalloc)
-{
-    val->u.ptr  = ptr;
-    val->nalloc = nalloc;
-    return 0;
-}
diff --git a/src/gmxlib/selection/sm_compare.c b/src/gmxlib/selection/sm_compare.c
deleted file mode 100644 (file)
index 103eb9e..0000000
+++ /dev/null
@@ -1,620 +0,0 @@
-/*
- *
- *                This source code is part of
- *
- *                 G   R   O   M   A   C   S
- *
- *          GROningen MAchine for Chemical Simulations
- *
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
- * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
- * Copyright (c) 2001-2009, The GROMACS development team,
- * check out http://www.gromacs.org for more information.
-
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * If you want to redistribute modifications, please consider that
- * scientific software is very special. Version control is crucial -
- * bugs must be traceable. We will be happy to consider code for
- * inclusion in the official distribution, but derived work must not
- * be called official GROMACS. Details are found in the README & COPYING
- * files - if they are missing, get the official version at www.gromacs.org.
- *
- * To help us fund GROMACS development, we humbly ask that you cite
- * the papers on the package - you can find them in the top README file.
- *
- * For more info, check our website at http://www.gromacs.org
- */
-/*! \internal \file
- * \brief
- * Implementation of internal selection method for comparison expressions.
- */
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <maths.h>
-#include <macros.h>
-#include <smalloc.h>
-#include <gmx_fatal.h>
-
-#include <selmethod.h>
-
-/** Defines the comparison operator for comparison expressions. */
-typedef enum
-{
-    CMP_INVALID,        /**< Indicates an error */
-    CMP_LESS,           /**< '<' */
-    CMP_LEQ,            /**< '<=' */
-    CMP_GTR,            /**< '>' */
-    CMP_GEQ,            /**< '>=' */
-    CMP_EQUAL,          /**< '==' */
-    CMP_NEQ             /**< '!=' */
-} e_comparison_t;
-
-/** The operand has a single value. */
-#define CMP_SINGLEVAL  1
-/** The operand value is dynamic. */
-#define CMP_DYNAMICVAL 2
-/** The value is real. */
-#define CMP_REALVAL    4
-/** The integer array is allocated. */
-#define CMP_ALLOCINT   16
-/** The real array is allocated. */
-#define CMP_ALLOCREAL  32
-
-/*! \internal \brief
- * Data structure for comparison expression operand values.
- */
-typedef struct
-{
-    /** Flags that describe the type of the operand. */
-    int             flags;
-    /** (Array of) integer value(s). */
-    int        *i;
-    /** (Array of) real value(s). */
-    real       *r;
-} t_compare_value;
-
-/*! \internal \brief
- * Data structure for comparison expression evaluation.
- */
-typedef struct
-{
-    /** Comparison operator as a string. */
-    char            *cmpop;
-    /** Comparison operator type. */
-    e_comparison_t   cmpt;
-    /** Left value. */
-    t_compare_value  left;
-    /** Right value. */
-    t_compare_value  right;
-} t_methoddata_compare;
-
-/** Allocates data for comparison expression evaluation. */
-static void *
-init_data_compare(int npar, gmx_ana_selparam_t *param);
-/** Initializes data for comparison expression evaluation. */
-static int
-init_compare(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
-/** Frees the memory allocated for comparison expression evaluation. */
-static void
-free_data_compare(void *data);
-/** Evaluates comparison expressions. */
-static int
-evaluate_compare(t_topology *top, t_trxframe *fr, t_pbc *pbc,
-                 gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
-
-/** Parameters for comparison expression evaluation. */
-static gmx_ana_selparam_t smparams_compare[] = {
-    {"int1",  {INT_VALUE,  -1, {NULL}}, NULL,
-     SPAR_OPTIONAL | SPAR_DYNAMIC | SPAR_ATOMVAL},
-    {"real1", {REAL_VALUE, -1, {NULL}}, NULL,
-     SPAR_OPTIONAL | SPAR_DYNAMIC | SPAR_ATOMVAL},
-    {"op",    {STR_VALUE,   1, {NULL}}, NULL, 0},
-    {"int2",  {INT_VALUE,  -1, {NULL}}, NULL,
-     SPAR_OPTIONAL | SPAR_DYNAMIC | SPAR_ATOMVAL},
-    {"real2", {REAL_VALUE, -1, {NULL}}, NULL,
-     SPAR_OPTIONAL | SPAR_DYNAMIC | SPAR_ATOMVAL},
-};
-
-/** \internal Selection method data for comparison expression evaluation. */
-gmx_ana_selmethod_t sm_compare = {
-    "cmp", GROUP_VALUE, SMETH_SINGLEVAL,
-    asize(smparams_compare), smparams_compare,
-    &init_data_compare,
-    NULL,
-    &init_compare,
-    NULL,
-    &free_data_compare,
-    NULL,
-    &evaluate_compare,
-    NULL,
-    {NULL, 0, NULL},
-};
-
-/*! \brief
- * Returns a \c e_comparison_t value corresponding to an operator.
- *
- * \param[in] str  String to process.
- * \returns   The comparison type corresponding to the first one or two
- *   characters of \p str.
- *
- * \p str can contain any number of characters; only the first two
- * are used.
- * If the beginning of \p str does not match any of the recognized types,
- * \ref CMP_INVALID is returned.
- */
-static e_comparison_t
-comparison_type(char *str)
-{
-    switch (str[0])
-    {
-        case '<': return (str[1] == '=') ? CMP_LEQ   : CMP_LESS;
-        case '>': return (str[1] == '=') ? CMP_GEQ   : CMP_GTR;
-        case '=': return (str[1] == '=') ? CMP_EQUAL : CMP_INVALID;
-        case '!': return (str[1] == '=') ? CMP_NEQ   : CMP_INVALID;
-    }
-    return CMP_INVALID;
-}
-
-/*! \brief
- * Returns a string corresponding to a \c e_comparison_t value.
- *
- * \param[in] cmpt  Comparison type to convert.
- * \returns   Pointer to a string that corresponds to \p cmpt.
- *
- * The return value points to a string constant and should not be \p free'd.
- * 
- * The function returns NULL if \p cmpt is not one of the valid values.
- */
-static const char *
-comparison_type_str(e_comparison_t cmpt)
-{
-    switch (cmpt)
-    {
-        case CMP_INVALID: return "INVALID"; break;
-        case CMP_LESS:    return "<";  break;
-        case CMP_LEQ:     return "<="; break;
-        case CMP_GTR:     return ">";  break;
-        case CMP_GEQ:     return ">="; break;
-        case CMP_EQUAL:   return "=="; break;
-        case CMP_NEQ:     return "!="; break;
-    }
-    return NULL;
-}
-
-/*!
- * \param[in] fp    File to receive the output.
- * \param[in] data  Should point to a \c t_methoddata_compare.
- */
-void
-_gmx_selelem_print_compare_info(FILE *fp, void *data)
-{
-    t_methoddata_compare *d = (t_methoddata_compare *)data;
-
-    fprintf(fp, " \"");
-    /* Print the left value */
-    if ((d->left.flags & CMP_SINGLEVAL) && !(d->left.flags & CMP_DYNAMICVAL))
-    {
-        if (d->left.flags & CMP_REALVAL)
-        {
-            fprintf(fp, "%f ", d->left.r[0]);
-        }
-        else
-        {
-            fprintf(fp, "%d ", d->left.i[0]);
-        }
-    }
-    /* Print the operator */
-    if (d->cmpt != CMP_INVALID)
-    {
-        fprintf(fp, "%s", comparison_type_str(d->cmpt));
-    }
-    else
-    {
-        fprintf(fp, "%s", d->cmpop);
-    }
-    /* Print the right value */
-    if ((d->right.flags & CMP_SINGLEVAL) && !(d->right.flags & CMP_DYNAMICVAL))
-    {
-        if (d->right.flags & CMP_REALVAL)
-        {
-            fprintf(fp, " %f", d->right.r[0]);
-        }
-        else
-        {
-            fprintf(fp, " %d", d->right.i[0]);
-        }
-    }
-    fprintf(fp, "\"");
-}
-
-/*!
- * \param[in]     npar  Not used (should be 5).
- * \param[in,out] param Method parameters (should point to a copy of
- *   \ref smparams_compare).
- * \returns       Pointer to the allocated data (\c t_methoddata_compare).
- *
- * Allocates memory for a \c t_methoddata_compare structure.
- */
-static void *
-init_data_compare(int npar, gmx_ana_selparam_t *param)
-{
-    t_methoddata_compare *data;
-
-    snew(data, 1);
-    param[2].val.u.s = &data->cmpop;
-    return data;
-}
-
-/* \brief
- * Reverses a comparison operator.
- *
- * \param[in] type  Comparison operator to reverse.
- * \returns   The correct comparison operator that equals \p type when the
- *   left and right sides are interchanged.
- */
-static e_comparison_t
-reverse_comparison_type(e_comparison_t type)
-{
-    switch (type)
-    {
-        case CMP_LESS: return CMP_GTR;
-        case CMP_LEQ:  return CMP_GEQ;
-        case CMP_GTR:  return CMP_LESS;
-        case CMP_GEQ:  return CMP_LEQ;
-        default:       break;
-    }
-    return type;
-}
-
-/*! \brief
- * Initializes the value storage for comparison expression.
- *
- * \param[out] val   Value structure to initialize.
- * \param[in]  param Parameters to use for initialization.
- * \returns    The number of values provided for the value, 0 on error.
- */
-static int
-init_comparison_value(t_compare_value *val, gmx_ana_selparam_t param[2])
-{
-    int  n;
-
-    val->flags = 0;
-    if (param[0].flags & SPAR_SET)
-    {
-        val->flags |=  (param[0].flags & SPAR_DYNAMIC) ? CMP_DYNAMICVAL : 0;
-        val->flags |= !(param[0].flags & SPAR_ATOMVAL) ? CMP_SINGLEVAL  : 0;
-        n           = param[0].val.nr;
-        val->i      = param[0].val.u.i;
-    }
-    else if (param[1].flags & SPAR_SET)
-    {
-        val->flags |=  (param[1].flags & SPAR_DYNAMIC) ? CMP_DYNAMICVAL : 0;
-        val->flags |= !(param[1].flags & SPAR_ATOMVAL) ? CMP_SINGLEVAL  : 0;
-        val->flags |= CMP_REALVAL;
-        n           = param[1].val.nr;
-        val->r      = param[1].val.u.r;
-    }
-    else
-    {
-        n           = 0;
-        val->i      = NULL;
-        val->r      = NULL;
-    }
-    return n;
-}
-
-/* \brief
- * Converts an integer value to floating point.
- *
- * \param[in]     n   Number of values in the \p val->u array.
- * \param[in,out] val Value to convert.
- */
-static void
-convert_int_real(int n, t_compare_value *val)
-{
-    int   i;
-    real *rv;
-
-    snew(rv, n);
-    for (i = 0; i < n; ++i)
-    {
-        rv[i] = (real)val->i[i];
-    }
-    /* Free the previous value if one is present. */
-    sfree(val->r);
-    val->r      = rv;
-    val->flags |= CMP_REALVAL | CMP_ALLOCREAL;
-}
-
-/* \brief
- * Converts a floating point value to integer.
- *
- * \param[in]     n      Number of values in the \p val->u array.
- * \param[in,out] val    Value to convert.
- * \param[in]     cmpt   Comparison operator type.
- * \param[in]     bRight TRUE if \p val appears on the right hand size of
- *   \p cmpt.
- * \returns       0 on success, EINVAL on error.
- *
- * The values are rounded such that the same comparison operator can be used.
- */
-static int
-convert_real_int(int n, t_compare_value *val, e_comparison_t cmpt, gmx_bool bRight)
-{
-    int   i;
-    int  *iv;
-
-    if (!bRight)
-    {
-        cmpt = reverse_comparison_type(cmpt);
-    }
-    snew(iv, n);
-    /* Round according to the comparison type */
-    for (i = 0; i < n; ++i)
-    {
-        switch (cmpt)
-        {
-            case CMP_LESS:
-            case CMP_GEQ:
-                iv[i] = (int)ceil(val->r[i]);
-                break;
-            case CMP_GTR:
-            case CMP_LEQ:
-                iv[i] = (int)floor(val->r[i]);
-                break;
-            case CMP_EQUAL:
-            case CMP_NEQ:
-                fprintf(stderr, "comparing equality an integer expression and a real value\n");
-                sfree(iv);
-                return EINVAL;
-            case CMP_INVALID: /* Should not be reached */
-                gmx_bug("internal error");
-                sfree(iv);
-                return EINVAL;
-        }
-    }
-    /* Free the previous value if one is present. */
-    sfree(val->i);
-    val->i      = iv;
-    val->flags &= ~CMP_REALVAL;
-    val->flags |= CMP_ALLOCINT;
-    return 0;
-}
-
-/*!
- * \param[in] top   Not used.
- * \param[in] npar  Not used (should be 5).
- * \param[in] param Method parameters (should point to \ref smparams_compare).
- * \param[in] data  Should point to a \c t_methoddata_compare.
- * \returns   0 if the input data is valid, -1 on error.
- */
-static int
-init_compare(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data)
-{
-    t_methoddata_compare *d = (t_methoddata_compare *)data;
-    int                   n1, n2;
-
-    /* Store the values */
-    n1 = init_comparison_value(&d->left, &param[0]);
-    n2 = init_comparison_value(&d->right, &param[3]);
-    if (n1 == 0 || n2 == 0)
-    {
-        gmx_bug("one of the values for comparison missing");
-        return -1;
-    }
-    /* Store the comparison type */
-    d->cmpt = comparison_type(d->cmpop);
-    if (d->cmpt == CMP_INVALID)
-    {
-        gmx_bug("invalid comparison type");
-        return -1;
-    }
-    /* Convert the values to the same type */
-    if ((d->left.flags & CMP_REALVAL) && !(d->right.flags & CMP_REALVAL))
-    {
-        if (d->left.flags & d->right.flags & CMP_DYNAMICVAL)
-        {
-            /* Nothing can be done */
-        }
-        else if (!(d->right.flags & CMP_DYNAMICVAL))
-        {
-            convert_int_real(n2, &d->right);
-        }
-        else /* d->left is static */
-        {
-            if (convert_real_int(n1, &d->left, d->cmpt, FALSE))
-            {
-                return -1;
-            }
-        }
-    }
-    else if (!(d->left.flags & CMP_REALVAL) && (d->right.flags & CMP_REALVAL))
-    {
-        if (d->left.flags & d->right.flags & CMP_DYNAMICVAL)
-        {
-            /* Reverse the sides to place the integer on the right */
-            int    flags;
-            d->left.r  = d->right.r;
-            d->right.r = NULL;
-            d->right.i = d->left.i;
-            d->left.i  = NULL;
-            flags          = d->left.flags;
-            d->left.flags  = d->right.flags;
-            d->right.flags = flags;
-            d->cmpt = reverse_comparison_type(d->cmpt);
-        }
-        else if (!(d->left.flags & CMP_DYNAMICVAL))
-        {
-            convert_int_real(n1, &d->left);
-        }
-        else /* d->right is static */
-        {
-            if (convert_real_int(n2, &d->right, d->cmpt, TRUE))
-            {
-                return -1;
-            }
-        }
-    }
-    return 0;
-}
-
-/*!
- * \param data Data to free (should point to a \c t_methoddata_compare).
- *
- * Frees the memory allocated for \c t_methoddata_compare.
- */
-static void
-free_data_compare(void *data)
-{
-    t_methoddata_compare *d = (t_methoddata_compare *)data;
-
-    sfree(d->cmpop);
-    if (d->left.flags & CMP_ALLOCINT)
-    {
-        sfree(d->left.i);
-    }
-    if (d->left.flags & CMP_ALLOCREAL)
-    {
-        sfree(d->left.r);
-    }
-    if (d->right.flags & CMP_ALLOCINT)
-    {
-        sfree(d->right.i);
-    }
-    if (d->right.flags & CMP_ALLOCREAL)
-    {
-        sfree(d->right.r);
-    }
-}
-
-/*!
- * \param[in]  top   Not used.
- * \param[in]  fr    Not used.
- * \param[in]  pbc   Not used.
- * \param[in]  g     Evaluation index group.
- * \param[out] out   Output data structure (\p out->u.g is used).
- * \param[in]  data  Should point to a \c t_methoddata_compare.
- * \returns    0 for success.
- */
-static int
-evaluate_compare_int(t_topology *top, t_trxframe *fr, t_pbc *pbc,
-                     gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
-{
-    t_methoddata_compare *d = (t_methoddata_compare *)data;
-    int                   i, i1, i2, ig;
-    int                   a, b;
-    gmx_bool                  bAccept;
-
-    for (i = i1 = i2 = ig = 0; i < g->isize; ++i)
-    {
-        a = d->left.i[i1];
-        b = d->right.i[i2];
-        bAccept = FALSE;
-        switch (d->cmpt)
-        {
-            case CMP_INVALID: break;
-            case CMP_LESS:    bAccept = a <  b; break;
-            case CMP_LEQ:     bAccept = a <= b; break;
-            case CMP_GTR:     bAccept = a >  b; break;
-            case CMP_GEQ:     bAccept = a >= b; break;
-            case CMP_EQUAL:   bAccept = a == b; break;
-            case CMP_NEQ:     bAccept = a != b; break;
-        }
-        if (bAccept)
-        {
-            out->u.g->index[ig++] = g->index[i];
-        }
-        if (!(d->left.flags & CMP_SINGLEVAL))
-        {
-            ++i1;
-        }
-        if (!(d->right.flags & CMP_SINGLEVAL))
-        {
-            ++i2;
-        }
-    }
-    out->u.g->isize = ig;
-    return 0;
-}
-
-/*!
- * \param[in]  top   Not used.
- * \param[in]  fr    Not used.
- * \param[in]  pbc   Not used.
- * \param[in]  g     Evaluation index group.
- * \param[out] out   Output data structure (\p out->u.g is used).
- * \param[in]  data  Should point to a \c t_methoddata_compare.
- * \returns    0 for success.
- */
-static int
-evaluate_compare_real(t_topology *top, t_trxframe *fr, t_pbc *pbc,
-                      gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
-{
-    t_methoddata_compare *d = (t_methoddata_compare *)data;
-    int                   i, i1, i2, ig;
-    real                  a, b;
-    gmx_bool                  bAccept;
-
-    for (i = i1 = i2 = ig = 0; i < g->isize; ++i)
-    {
-        a = d->left.r[i1];
-        b = (d->right.flags & CMP_REALVAL) ? d->right.r[i2] : d->right.i[i2];
-        bAccept = FALSE;
-        switch (d->cmpt)
-        {
-            case CMP_INVALID: break;
-            case CMP_LESS:    bAccept = a <  b; break;
-            case CMP_LEQ:     bAccept = a <= b; break;
-            case CMP_GTR:     bAccept = a >  b; break;
-            case CMP_GEQ:     bAccept = a >= b; break;
-            case CMP_EQUAL:   bAccept =  gmx_within_tol(a, b, GMX_REAL_EPS); break;
-            case CMP_NEQ:     bAccept = !gmx_within_tol(a, b, GMX_REAL_EPS); break;
-        }
-        if (bAccept)
-        {
-            out->u.g->index[ig++] = g->index[i];
-        }
-        if (!(d->left.flags & CMP_SINGLEVAL))
-        {
-            ++i1;
-        }
-        if (!(d->right.flags & CMP_SINGLEVAL))
-        {
-            ++i2;
-        }
-    }
-    out->u.g->isize = ig;
-    return 0;
-}
-
-/*!
- * \param[in]  top   Not used.
- * \param[in]  fr    Not used.
- * \param[in]  pbc   Not used.
- * \param[in]  g     Evaluation index group.
- * \param[out] out   Output data structure (\p out->u.g is used).
- * \param[in]  data  Should point to a \c t_methoddata_compare.
- * \returns    0 for success.
- */
-static int
-evaluate_compare(t_topology *top, t_trxframe *fr, t_pbc *pbc,
-                 gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
-{
-    t_methoddata_compare *d = (t_methoddata_compare *)data;
-
-    if (!((d->left.flags | d->right.flags) & CMP_REALVAL))
-    {
-        return evaluate_compare_int(top, fr, pbc, g, out, data);
-    }
-    else
-    {
-        return evaluate_compare_real(top, fr, pbc, g, out, data);
-    }
-    return 0;
-}
diff --git a/src/gmxlib/selection/sm_distance.c b/src/gmxlib/selection/sm_distance.c
deleted file mode 100644 (file)
index 61ee58e..0000000
+++ /dev/null
@@ -1,306 +0,0 @@
-/*
- *
- *                This source code is part of
- *
- *                 G   R   O   M   A   C   S
- *
- *          GROningen MAchine for Chemical Simulations
- *
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
- * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
- * Copyright (c) 2001-2009, The GROMACS development team,
- * check out http://www.gromacs.org for more information.
-
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * If you want to redistribute modifications, please consider that
- * scientific software is very special. Version control is crucial -
- * bugs must be traceable. We will be happy to consider code for
- * inclusion in the official distribution, but derived work must not
- * be called official GROMACS. Details are found in the README & COPYING
- * files - if they are missing, get the official version at www.gromacs.org.
- *
- * To help us fund GROMACS development, we humbly ask that you cite
- * the papers on the package - you can find them in the top README file.
- *
- * For more info, check our website at http://www.gromacs.org
- */
-/*! \internal \file
- * \brief Implementation of distance-based selection methods.
- *
- * This file implements the \p distance, \p mindistance and \p within
- * selection methods.
- */
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <macros.h>
-#include <pbc.h>
-#include <smalloc.h>
-#include <vec.h>
-
-#include <nbsearch.h>
-#include <position.h>
-#include <selmethod.h>
-
-/*! \internal \brief
- * Data structure for distance-based selection method.
- *
- * The same data structure is used by all the distance-based methods.
- */
-typedef struct
-{
-    /** Cutoff distance. */
-    real                cutoff;
-    /** Positions of the reference points. */
-    gmx_ana_pos_t       p;
-    /** Neighborhood search data. */
-    gmx_ana_nbsearch_t *nb;
-} t_methoddata_distance;
-
-/** Allocates data for distance-based selection methods. */
-static void *
-init_data_common(int npar, gmx_ana_selparam_t *param);
-/** Initializes a distance-based selection method. */
-static int
-init_common(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
-/** Frees the data allocated for a distance-based selection method. */
-static void
-free_data_common(void *data);
-/** Initializes the evaluation of a distance-based within selection method for a frame. */
-static int
-init_frame_common(t_topology *top, t_trxframe *fr, t_pbc *pbc, void *data);
-/** Evaluates the \p distance selection method. */
-static int
-evaluate_distance(t_topology *top, t_trxframe *fr, t_pbc *pbc,
-                  gmx_ana_pos_t *pos, gmx_ana_selvalue_t *out, void *data);
-/** Evaluates the \p within selection method. */
-static int
-evaluate_within(t_topology *top, t_trxframe *fr, t_pbc *pbc,
-                gmx_ana_pos_t *pos, gmx_ana_selvalue_t *out, void *data);
-
-/** Parameters for the \p distance selection method. */
-static gmx_ana_selparam_t smparams_distance[] = {
-    {"cutoff", {REAL_VALUE, 1, {NULL}}, NULL, SPAR_OPTIONAL},
-    {"from",   {POS_VALUE,  1, {NULL}}, NULL, SPAR_DYNAMIC},
-};
-
-/** Parameters for the \p mindistance selection method. */
-static gmx_ana_selparam_t smparams_mindistance[] = {
-    {"cutoff", {REAL_VALUE, 1, {NULL}}, NULL, SPAR_OPTIONAL},
-    {"from",   {POS_VALUE, -1, {NULL}}, NULL, SPAR_DYNAMIC | SPAR_VARNUM},
-};
-
-/** Parameters for the \p within selection method. */
-static gmx_ana_selparam_t smparams_within[] = {
-    {NULL, {REAL_VALUE,  1, {NULL}}, NULL, 0},
-    {"of", {POS_VALUE,  -1, {NULL}}, NULL, SPAR_DYNAMIC | SPAR_VARNUM},
-};
-
-/** Help text for the distance selection methods. */
-static const char *help_distance[] = {
-    "DISTANCE-BASED SELECTION KEYWORDS[PAR]",
-
-    "[TT]distance from POS [cutoff REAL][tt][BR]",
-    "[TT]mindistance from POS_EXPR [cutoff REAL][tt][BR]",
-    "[TT]within REAL of POS_EXPR[tt][PAR]",
-
-    "[TT]distance[tt] and [TT]mindistance[tt] calculate the distance from the",
-    "given position(s), the only difference being in that [TT]distance[tt]",
-    "only accepts a single position, while any number of positions can be",
-    "given for [TT]mindistance[tt], which then calculates the distance to the",
-    "closest position.",
-    "[TT]within[tt] directly selects atoms that are within [TT]REAL[tt] of",
-    "[TT]POS_EXPR[tt].[PAR]",
-
-    "For the first two keywords, it is possible to specify a cutoff to speed",
-    "up the evaluation: all distances above the specified cutoff are",
-    "returned as equal to the cutoff.",
-    "Currently, this does nothing, but in the future, it allows the use of",
-    "grid-based neighborhood search techniques.",
-};
-
-/** \internal Selection method data for the \p distance method. */
-gmx_ana_selmethod_t sm_distance = {
-    "distance", REAL_VALUE, SMETH_DYNAMIC,
-    asize(smparams_distance), smparams_distance,
-    &init_data_common,
-    NULL,
-    &init_common,
-    NULL,
-    &free_data_common,
-    &init_frame_common,
-    NULL,
-    &evaluate_distance,
-    {"distance from POS [cutoff REAL]", asize(help_distance), help_distance},
-};
-
-/** \internal Selection method data for the \p distance method. */
-gmx_ana_selmethod_t sm_mindistance = {
-    "mindistance", REAL_VALUE, SMETH_DYNAMIC,
-    asize(smparams_mindistance), smparams_mindistance,
-    &init_data_common,
-    NULL,
-    &init_common,
-    NULL,
-    &free_data_common,
-    &init_frame_common,
-    NULL,
-    &evaluate_distance,
-    {"mindistance from POS_EXPR [cutoff REAL]", asize(help_distance), help_distance},
-};
-
-/** \internal Selection method data for the \p within method. */
-gmx_ana_selmethod_t sm_within = {
-    "within", GROUP_VALUE, SMETH_DYNAMIC,
-    asize(smparams_within), smparams_within,
-    &init_data_common,
-    NULL,
-    &init_common,
-    NULL,
-    &free_data_common,
-    &init_frame_common,
-    NULL,
-    &evaluate_within,
-    {"within REAL of POS_EXPR", asize(help_distance), help_distance},
-};
-
-/*!
- * \param[in]     npar  Not used (should be 2).
- * \param[in,out] param Method parameters (should point to one of the distance
- *   parameter arrays).
- * \returns       Pointer to the allocated data (\c t_methoddata_distance).
- *
- * Allocates memory for a \c t_methoddata_distance structure and
- * initializes the parameter as follows:
- *  - the first parameter defines the value for
- *    \c t_methoddata_distance::cutoff.
- *  - the second parameter defines the reference positions and the value is
- *    stored in \c t_methoddata_distance::p.
- */
-static void *
-init_data_common(int npar, gmx_ana_selparam_t *param)
-{
-    t_methoddata_distance *data;
-
-    snew(data, 1);
-    data->cutoff     = -1;
-    param[0].val.u.r = &data->cutoff;
-    param[1].val.u.p = &data->p;
-    return data;
-}
-
-/*!
- * \param   top   Not used.
- * \param   npar  Not used (should be 2).
- * \param   param Method parameters (should point to one of the distance
- *   parameter arrays).
- * \param   data  Pointer to \c t_methoddata_distance to initialize.
- * \returns 0 on success, a non-zero error code on failure.
- *
- * Initializes the neighborhood search data structure
- * (\c t_methoddata_distance::nb).
- * Also checks that the cutoff is valid.
- */
-static int
-init_common(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data)
-{
-    t_methoddata_distance *d = (t_methoddata_distance *)data;
-
-    if ((param[0].flags & SPAR_SET) && d->cutoff <= 0)
-    {
-        fprintf(stderr, "error: distance cutoff should be > 0");
-        return -1;
-    }
-    return gmx_ana_nbsearch_create(&d->nb, d->cutoff, d->p.nr);
-}
-
-/*!
- * \param data Data to free (should point to a \c t_methoddata_distance).
- *
- * Frees the memory allocated for \c t_methoddata_distance::xref and
- * \c t_methoddata_distance::nb.
- */
-static void
-free_data_common(void *data)
-{
-    t_methoddata_distance *d = (t_methoddata_distance *)data;
-
-    if (d->nb)
-    {
-        gmx_ana_nbsearch_free(d->nb);
-    }
-}
-
-/*!
- * \param[in]  top  Not used.
- * \param[in]  fr   Current frame.
- * \param[in]  pbc  PBC structure.
- * \param      data Should point to a \c t_methoddata_distance.
- * \returns    0 on success, a non-zero error code on error.
- *
- * Initializes the neighborhood search for the current frame.
- */
-static int
-init_frame_common(t_topology *top, t_trxframe *fr, t_pbc *pbc, void *data)
-{
-    t_methoddata_distance *d = (t_methoddata_distance *)data;
-
-    return gmx_ana_nbsearch_pos_init(d->nb, pbc, &d->p);
-}
-
-/*!
- * See sel_updatefunc_pos() for description of the parameters.
- * \p data should point to a \c t_methoddata_distance.
- *
- * Calculates the distance of each position from \c t_methoddata_distance::p
- * and puts them in \p out->u.r.
- */
-static int
-evaluate_distance(t_topology *top, t_trxframe *fr, t_pbc *pbc,
-                  gmx_ana_pos_t *pos, gmx_ana_selvalue_t *out, void *data)
-{
-    t_methoddata_distance *d = (t_methoddata_distance *)data;
-    int  b, i;
-    real n;
-
-    out->nr = pos->g->isize;
-    for (b = 0; b < pos->nr; ++b)
-    {
-        n = gmx_ana_nbsearch_pos_mindist(d->nb, pos, b);
-        for (i = pos->m.mapb.index[b]; i < pos->m.mapb.index[b+1]; ++i)
-        {
-            out->u.r[i] = n;
-        }
-    }
-    return 0;
-}
-
-/*!
- * See sel_updatefunc() for description of the parameters.
- * \p data should point to a \c t_methoddata_distance.
- *
- * Finds the atoms that are closer than the defined cutoff to
- * \c t_methoddata_distance::xref and puts them in \p out.g.
- */
-static int
-evaluate_within(t_topology *top, t_trxframe *fr, t_pbc *pbc,
-                gmx_ana_pos_t *pos, gmx_ana_selvalue_t *out, void *data)
-{
-    t_methoddata_distance *d = (t_methoddata_distance *)data;
-    int                    b;
-
-    out->u.g->isize = 0;
-    for (b = 0; b < pos->nr; ++b)
-    {
-        if (gmx_ana_nbsearch_pos_is_within(d->nb, pos, b))
-        {
-            gmx_ana_pos_append(NULL, out->u.g, pos, b, 0);
-        }
-    }
-    return 0;
-}
diff --git a/src/gmxlib/selection/sm_insolidangle.c b/src/gmxlib/selection/sm_insolidangle.c
deleted file mode 100644 (file)
index 1f72fcf..0000000
+++ /dev/null
@@ -1,963 +0,0 @@
-/*
- *
- *                This source code is part of
- *
- *                 G   R   O   M   A   C   S
- *
- *          GROningen MAchine for Chemical Simulations
- *
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
- * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
- * Copyright (c) 2001-2009, The GROMACS development team,
- * check out http://www.gromacs.org for more information.
-
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * If you want to redistribute modifications, please consider that
- * scientific software is very special. Version control is crucial -
- * bugs must be traceable. We will be happy to consider code for
- * inclusion in the official distribution, but derived work must not
- * be called official GROMACS. Details are found in the README & COPYING
- * files - if they are missing, get the official version at www.gromacs.org.
- *
- * To help us fund GROMACS development, we humbly ask that you cite
- * the papers on the package - you can find them in the top README file.
- *
- * For more info, check our website at http://www.gromacs.org
- */
-/*! \page sm_insolidangle Selection method: insolidangle
- *
- * This method selects a subset of particles that are located in a solid
- * angle defined by a center and a set of points.
- * The solid angle is constructed as a union of small cones whose axis
- * goes through the center and a point.
- * So there's such a cone for each position, and a
- * point is in the solid angle if it lies within any of these cones.
- * The width of the cones can be adjusted.
- *
- * \internal
- *
- * The method is implemented by partitioning the surface of the unit sphere
- * into bins using the polar coordinates \f$(\theta, \phi)\f$.
- * The partitioning is always uniform in the zenith angle \f$\theta\f$,
- * while the partitioning in the azimuthal angle \f$\phi\f$ varies.
- * For each reference point, the unit vector from the center to the point
- * is constructed, and it is stored in all the bins that overlap with the
- * cone defined by the point.
- * Bins that are completely covered by a single cone are marked as such.
- * Checking whether a point is in the solid angle is then straightforward
- * with this data structure: one finds the bin that corresponds to the point,
- * and checks whether the bin is completely covered. If it is not, one
- * additionally needs to check whether it is within the specified cutoff of
- * any of the stored points.
- *
- * The above construction gives quite a lot of flexibility for constructing
- * the bins without modifying the rest of the code.
- * The current (quite inefficient) implementation is discussed below, but
- * it should be optimized to get the most out of the code.
- *
- * The current way of constructing the bins constructs the boundaries
- * statically: the bin size in the zenith direction is set to approximately
- * half the angle cutoff, and the bins in the azimuthal direction have
- * sizes such that the shortest edge of the bin is approximately equal to
- * half the angle cutoff (for the regions close to the poles, a single bin
- * is used).
- * Each reference point is then added to the bins as follows:
- *  -# Find the zenith angle range that is spanned by the cone centered at the
- *     point (this is simple addition/subtraction).
- *  -# Calculate the maximal span of the cone in the azimuthal direction using
- *     the formula
- *     \f[\sin \Delta \phi_{max} = \frac{\sin \alpha}{\sin \theta}\f]
- *     (a sine formula in spherical coordinates),
- *     where \f$\alpha\f$ is the width of the cone and \f$\theta\f$ is the
- *     zenith angle of the cone center.
- *     Similarly, the zenith angle at which this extent is achieved is
- *     calculated using
- *     \f[\cos \theta_{max} = \frac{\cos \theta}{\cos \alpha}\f]
- *     (Pythagoras's theorem in spherical coordinates).
- *  -# For each zenith angle bin that is at least partially covered by the
- *     cone, calculate the span of the cone at the edges using
- *     \f[\sin^2 \frac{\Delta \phi}{2} = \frac{\sin^2 \frac{\alpha}{2} - \sin^2 \frac{\theta - \theta'}{2}}{\sin \theta \sin \theta'}\f]
- *     (distance in spherical geometry),
- *     where \f$\theta'\f$ is the zenith angle of the bin edge.
- *  -# Using the values calculated above, loop through the azimuthal bins that
- *     are partially or completely covered by the cone and update them.
- *
- * The total solid angle (for covered fraction calculations) is estimated by
- * taking the total area of completely covered bins plus
- * half the area of partially covered bins.
- * The second one is an approximation, but should give reasonable estimates
- * for the averages as well as in cases where the bin size is small.
- */
-/*! \internal \file
- * \brief Implementation of the \ref sm_insolidangle "insolidangle"
- *   selection method.
- *
- * \todo
- * The implementation could be optimized quite a bit.
- * 
- * \todo Move the covered fraction stuff somewhere else and make it more
- * generic (along the lines it is handled in selection.h and trajana.h).
- */
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <math.h>
-
-#include <macros.h>
-#include <maths.h>
-#include <pbc.h>
-#include <physics.h>
-#include <smalloc.h>
-#include <vec.h>
-
-#include <indexutil.h>
-#include <position.h>
-#include <selection.h>
-#include <selmethod.h>
-
-#include "selelem.h"
-
-/*! \internal \brief
- * Internal data structure for the \p insolidangle selection method.
- *
- * \see \c t_partition
- */
-typedef struct
-{
-    /** Left edge of the partition. */
-    real                left;
-    /** Bin index corresponding to this partition. */
-    int                 bin;
-} t_partition_item;
-
-/*! \internal \brief
- * Internal data structure for the \p insolidangle selection method.
- *
- * Describes the surface partitioning within one slice along the zenith angle.
- * The slice from azimuthal angle \p p[i].left to \p p[i+1].left belongs to
- * bin \p p[i].bin.
- */
-typedef struct
-{
-    /** Number of partition items (\p p contains \p n+1 items). */
-    int                 n;
-    /** Array of partition edges and corresponding bins. */
-    t_partition_item   *p;
-} t_partition;
-
-/*! \internal \brief
- * Internal data structure for the \p insolidangle selection method.
- *
- * Contains the reference points that partially cover a certain region on the
- * surface of the unit sphere.
- * If \p n is -1, the whole region described by the bin is covered.
- */
-typedef struct
-{
-    /** Number of points in the array \p x, -1 if whole bin covered. */
-    int   n;
-    /** Number of elements allocated for \p x. */
-    int   n_alloc;
-    /** Array of points that partially cover the bin. */
-    rvec *x;
-} t_spheresurfacebin;
-
-/*! \internal \brief
- * Data structure for the \p insolidangle selection method.
- *
- * All angle values are in the units of radians.
- */
-typedef struct
-{
-    /** Center of the solid angle. */
-    gmx_ana_pos_t       center;
-    /** Positions that span the solid angle. */
-    gmx_ana_pos_t       span;
-    /** Cutoff angle. */
-    real                angcut;
-    /** Estimate of the covered fraction. */
-    real                cfrac;
-
-    /** Cutoff for the cosine (equals cos(angcut)). */
-    real                distccut;
-    /** Bin size to be used as the target bin size when constructing the bins. */
-    real                targetbinsize;
-
-    /** Number of bins in the \p tbin array. */
-    int                 ntbins;
-    /** Size of one bin in the zenith angle direction. */
-    real                tbinsize;
-    /** Array of zenith angle slices. */
-    t_partition        *tbin;
-    /** Number of elements allocated for the \p bin array. */
-    int                 maxbins;
-    /** Number of elements used in the \p bin array. */
-    int                 nbins;
-    /** Array of individual bins. */
-    t_spheresurfacebin *bin;
-} t_methoddata_insolidangle;
-
-/** Allocates data for the \p insolidangle selection method. */
-static void *
-init_data_insolidangle(int npar, gmx_ana_selparam_t *param);
-/** Initializes the \p insolidangle selection method. */
-static int
-init_insolidangle(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
-/** Sets the COM/COG data for the \p insolidangle selection method. */
-static void
-set_comg_insolidangle(gmx_ana_pos_t *pos, void *data);
-/** Frees the data allocated for the \p insolidangle selection method. */
-static void
-free_data_insolidangle(void *data);
-/** Initializes the evaluation of the \p insolidangle selection method for a frame. */
-static int
-init_frame_insolidangle(t_topology *top, t_trxframe *fr, t_pbc *pbc, void *data);
-/** Internal helper function for evaluate_insolidangle(). */
-static gmx_bool
-accept_insolidangle(rvec x, t_pbc *pbc, void *data);
-/** Evaluates the \p insolidangle selection method. */
-static int
-evaluate_insolidangle(t_topology *top, t_trxframe *fr, t_pbc *pbc,
-                      gmx_ana_pos_t *pos, gmx_ana_selvalue_t *out, void *data);
-
-/** Calculates the distance between unit vectors. */
-static real
-sph_distc(rvec x1, rvec x2);
-/** Does a binary search on a \p t_partition to find a bin for a value. */
-static int
-find_partition_bin(t_partition *p, real value);
-/** Finds a bin that corresponds to a location on the unit sphere surface. */
-static int
-find_surface_bin(t_methoddata_insolidangle *surf, rvec x);
-/** Clears/initializes the bins on the unit sphere surface. */
-static void
-clear_surface_points(t_methoddata_insolidangle *surf);
-/** Frees memory allocated for storing the reference points in the surface bins. */
-static void
-free_surface_points(t_methoddata_insolidangle *surf);
-/** Adds a reference point to a given bin. */
-static void
-add_surface_point(t_methoddata_insolidangle *surf, int tbin, int pbin, rvec x);
-/** Marks a bin as completely covered. */
-static void
-mark_surface_covered(t_methoddata_insolidangle *surf, int tbin, int pbin);
-/** Helper function for store_surface_point() to update a single zenith angle bin. */
-static void
-update_surface_bin(t_methoddata_insolidangle *surf, int tbin,
-                   real phi, real pdelta1, real pdelta2, real pdeltamax,
-                   rvec x);
-/** Adds a single reference point and updates the surface bins. */
-static void
-store_surface_point(t_methoddata_insolidangle *surf, rvec x);
-/** Optimizes the surface bins for faster searching. */
-static void
-optimize_surface_points(t_methoddata_insolidangle *surf);
-/** Estimates the area covered by the reference cones. */
-static real
-estimate_covered_fraction(t_methoddata_insolidangle *surf);
-/** Checks whether a point lies within a solid angle. */
-static gmx_bool
-is_surface_covered(t_methoddata_insolidangle *surf, rvec x);
-
-/** Parameters for the \p insolidangle selection method. */
-static gmx_ana_selparam_t smparams_insolidangle[] = {
-    {"center", {POS_VALUE,   1, {NULL}}, NULL, SPAR_DYNAMIC},
-    {"span",   {POS_VALUE,  -1, {NULL}}, NULL, SPAR_DYNAMIC | SPAR_VARNUM},
-    {"cutoff", {REAL_VALUE,  1, {NULL}}, NULL, SPAR_OPTIONAL},
-};
-
-/** Help text for the \p insolidangle selection method. */
-static const char *help_insolidangle[] = {
-    "SELECTING ATOMS IN A SOLID ANGLE[PAR]",
-
-    "[TT]insolidangle center POS span POS_EXPR [cutoff REAL][tt][PAR]",
-
-    "This keyword selects atoms that are within [TT]REAL[tt] degrees",
-    "(default=5) of any position in [TT]POS_EXPR[tt] as seen from [TT]POS[tt]",
-    "a position expression that evaluates to a single position), i.e., atoms",
-    "in the solid angle spanned by the positions in [TT]POS_EXPR[tt] and",
-    "centered at [TT]POS[tt].[PAR]"
-
-    "Technically, the solid angle is constructed as a union of small cones",
-    "whose tip is at [TT]POS[tt] and the axis goes through a point in",
-    "[TT]POS_EXPR[tt]. There is such a cone for each position in",
-    "[TT]POS_EXPR[tt], and point is in the solid angle if it lies within any",
-    "of these cones. The cutoff determines the width of the cones.",
-};
-
-/** \internal Selection method data for the \p insolidangle method. */
-gmx_ana_selmethod_t sm_insolidangle = {
-    "insolidangle", GROUP_VALUE, SMETH_DYNAMIC,
-    asize(smparams_insolidangle), smparams_insolidangle,
-    &init_data_insolidangle,
-    NULL,
-    &init_insolidangle,
-    NULL,
-    &free_data_insolidangle,
-    &init_frame_insolidangle,
-    NULL,
-    &evaluate_insolidangle,
-    {"insolidangle center POS span POS_EXPR [cutoff REAL]",
-     asize(help_insolidangle), help_insolidangle},
-};
-
-/*!
- * \param[in]     npar  Not used (should be 3).
- * \param[in,out] param Method parameters (should point to 
- *   \ref smparams_insolidangle).
- * \returns Pointer to the allocated data (\ref t_methoddata_insolidangle).
- *
- * Allocates memory for a \ref t_methoddata_insolidangle structure and
- * initializes the parameter as follows:
- *  - \p center defines the value for t_methoddata_insolidangle::center.
- *  - \p span   defines the value for t_methoddata_insolidangle::span.
- *  - \p cutoff defines the value for t_methoddata_insolidangle::angcut.
- */
-static void *
-init_data_insolidangle(int npar, gmx_ana_selparam_t *param)
-{
-    t_methoddata_insolidangle *data;
-
-    snew(data, 1);
-    data->angcut = 5.0;
-    param[0].val.u.p = &data->center;
-    param[1].val.u.p = &data->span;
-    param[2].val.u.r = &data->angcut;
-    return data;
-}
-
-/*!
- * \param   top  Not used.
- * \param   npar Not used.
- * \param   param Not used.
- * \param   data Pointer to \ref t_methoddata_insolidangle to initialize.
- * \returns 0 on success, -1 on failure.
- *
- * Converts t_methoddata_insolidangle::angcut to radians and allocates
- * and allocates memory for the bins used during the evaluation.
- */
-static int
-init_insolidangle(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data)
-{
-    t_methoddata_insolidangle *surf = (t_methoddata_insolidangle *)data;
-    int                        i, c;
-
-    if (surf->angcut <= 0)
-    {
-        fprintf(stderr, "error: angle cutoff should be > 0");
-        return -1;
-    }
-
-    surf->angcut *= DEG2RAD;
-
-    surf->distccut = -cos(surf->angcut);
-    surf->targetbinsize = surf->angcut / 2;
-    surf->ntbins = (int) (M_PI / surf->targetbinsize);
-    surf->tbinsize = (180.0 / surf->ntbins)*DEG2RAD;
-
-    snew(surf->tbin, (int)(M_PI/surf->tbinsize) + 1);
-    surf->maxbins = 0;
-    for (i = 0; i < surf->ntbins; ++i)
-    {
-        c = max(sin(surf->tbinsize*i), sin(surf->tbinsize*(i+1)))
-              * M_2PI / surf->targetbinsize + 1;
-        snew(surf->tbin[i].p, c+1);
-        surf->maxbins += c;
-    }
-    surf->nbins = 0;
-    snew(surf->bin, surf->maxbins);
-
-    return 0;
-}
-
-/*!
- * \param data Data to free (should point to a \ref t_methoddata_insolidangle).
- *
- * Frees the memory allocated for \c t_methoddata_insolidangle::center and
- * \c t_methoddata_insolidangle::span, as well as the memory for the internal
- * bin structure.
- */
-static void
-free_data_insolidangle(void *data)
-{
-    t_methoddata_insolidangle *d = (t_methoddata_insolidangle *)data;
-    int                        i;
-
-    if (d->tbin)
-    {
-        for (i = 0; i < d->ntbins; ++i)
-        {
-            sfree(d->tbin[i].p);
-        }
-        sfree(d->tbin);
-    }
-    free_surface_points(d);
-    sfree(d->bin);
-}
-
-/*!
- * \param[in]  top  Not used.
- * \param[in]  fr   Current frame.
- * \param[in]  pbc  PBC structure.
- * \param      data Should point to a \ref t_methoddata_insolidangle.
- * \returns    0 on success, a non-zero error code on error.
- *
- * Creates a lookup structure that enables fast queries of whether a point
- * is within the solid angle or not.
- */
-static int
-init_frame_insolidangle(t_topology *top, t_trxframe *fr, t_pbc *pbc, void *data)
-{
-    t_methoddata_insolidangle *d = (t_methoddata_insolidangle *)data;
-    rvec                       dx;
-    int                        i;
-
-    free_surface_points(d);
-    clear_surface_points(d);
-    for (i = 0; i < d->span.nr; ++i)
-    {
-        if (pbc)
-        {
-            pbc_dx(pbc, d->span.x[i], d->center.x[0], dx);
-        }
-        else
-        {
-            rvec_sub(d->span.x[i], d->center.x[0], dx);
-        }
-        unitv(dx, dx);
-        store_surface_point(d, dx);
-    }
-    optimize_surface_points(d);
-    d->cfrac = -1;
-    return 0;
-}
-
-/*!
- * \param[in] x    Test point.
- * \param[in] pbc  PBC data (if NULL, no PBC are used).
- * \param[in] data Pointer to a \c t_methoddata_insolidangle data structure.
- * \returns   TRUE if \p x is within the solid angle, FALSE otherwise.
- */
-static gmx_bool
-accept_insolidangle(rvec x, t_pbc *pbc, void *data)
-{
-    t_methoddata_insolidangle *d = (t_methoddata_insolidangle *)data;
-    rvec                       dx;
-
-    if (pbc)
-    {
-        pbc_dx(pbc, x, d->center.x[0], dx);
-    }
-    else
-    {
-        rvec_sub(x, d->center.x[0], dx);
-    }
-    unitv(dx, dx);
-    return is_surface_covered(d, dx);
-}
-
-/*!
- * See sel_updatefunc() for description of the parameters.
- * \p data should point to a \c t_methoddata_insolidangle.
- *
- * Calculates which atoms in \p g are within the solid angle spanned by
- * \c t_methoddata_insolidangle::span and centered at
- * \c t_methoddata_insolidangle::center, and stores the result in \p out->u.g.
- */
-static int
-evaluate_insolidangle(t_topology *top, t_trxframe *fr, t_pbc *pbc,
-                      gmx_ana_pos_t *pos, gmx_ana_selvalue_t *out, void *data)
-{
-    t_methoddata_insolidangle *d = (t_methoddata_insolidangle *)data;
-    int                        b;
-
-    out->u.g->isize = 0;
-    for (b = 0; b < pos->nr; ++b)
-    {
-        if (accept_insolidangle(pos->x[b], pbc, data))
-        {
-            gmx_ana_pos_append(NULL, out->u.g, pos, b, 0);
-        }
-    }
-    return 0;
-}
-
-/*!
- * \param[in] sel Selection element to query.
- * \returns   TRUE if the covered fraction can be estimated for \p sel with
- *   _gmx_selelem_estimate_coverfrac(), FALSE otherwise.
- */
-gmx_bool
-_gmx_selelem_can_estimate_cover(t_selelem *sel)
-{
-    t_selelem   *child;
-    gmx_bool         bFound;
-    gmx_bool         bDynFound;
-
-    if (sel->type == SEL_BOOLEAN && sel->u.boolt == BOOL_OR)
-    {
-        return FALSE;
-    }
-    bFound    = FALSE;
-    bDynFound = FALSE;
-    child     = sel->child;
-    while (child)
-    {
-        if (child->type == SEL_EXPRESSION)
-        {
-            if (child->u.expr.method->name == sm_insolidangle.name)
-            {
-                if (bFound || bDynFound)
-                {
-                    return FALSE;
-                }
-                bFound = TRUE;
-            }
-            else if (child->u.expr.method
-                     && (child->u.expr.method->flags & SMETH_DYNAMIC))
-            {
-                if (bFound)
-                {
-                    return FALSE;
-                }
-                bDynFound = TRUE;
-            }
-        }
-        else if (!_gmx_selelem_can_estimate_cover(child))
-        {
-            return FALSE;
-        }
-        child = child->next;
-    }
-    return TRUE;
-}
-
-/*!
- * \param[in] sel Selection for which the fraction should be calculated.
- * \returns Fraction of angles covered by the selection (between zero and one).
- *
- * The return value is undefined if _gmx_selelem_can_estimate_cover() returns
- * FALSE.
- * Should be called after gmx_ana_evaluate_selections() has been called for the
- * frame.
- */
-real
-_gmx_selelem_estimate_coverfrac(t_selelem *sel)
-{
-    t_selelem   *child;
-    real         cfrac;
-
-    if (sel->type == SEL_EXPRESSION && sel->u.expr.method->name == sm_insolidangle.name)
-    {
-        t_methoddata_insolidangle *d = (t_methoddata_insolidangle *)sel->u.expr.mdata;
-        if (d->cfrac < 0)
-        {
-            d->cfrac = estimate_covered_fraction(d);        
-        }
-        return d->cfrac;
-    }
-    if (sel->type == SEL_BOOLEAN && sel->u.boolt == BOOL_NOT)
-    {
-        cfrac = _gmx_selelem_estimate_coverfrac(sel->child);
-        if (cfrac < 1.0)
-        {
-            return 1 - cfrac;
-        }
-        return 1;
-    }
-
-    /* Here, we assume that the selection is simple enough */
-    child = sel->child;
-    while (child)
-    {
-        cfrac = _gmx_selelem_estimate_coverfrac(child); 
-        if (cfrac < 1.0)
-        {
-            return cfrac;
-        }
-        child = child->next;
-    }
-    return 1.0;
-}
-
-/*!
- * \param[in] x1  Unit vector 1.
- * \param[in] x2  Unit vector 2.
- * \returns   Minus the dot product of \p x1 and \p x2.
- *
- * This function is used internally to calculate the distance between the
- * unit vectors \p x1 and \p x2 to find out whether \p x2 is within the
- * cone centered at \p x1. Currently, the cosine of the angle is used
- * for efficiency, and the minus is there to make it behave like a normal
- * distance (larger values mean longer distances).
- */
-static real
-sph_distc(rvec x1, rvec x2)
-{
-    return -iprod(x1, x2);
-}
-
-/*!
- * \param[in] p     Partition to search.
- * \param[in] value Value to search for.
- * \returns   The partition index in \p p that contains \p value.
- *
- * If \p value is outside the range of \p p, the first/last index is returned.
- * Otherwise, the return value \c i satisfies \c p->p[i].left<=value and
- * \c p->p[i+1].left>value
- */
-static int
-find_partition_bin(t_partition *p, real value)
-{
-    int pmin, pmax, pbin;
-
-    /* Binary search the partition */
-    pmin = 0; pmax = p->n;
-    while (pmax > pmin + 1)
-    {
-        pbin = pmin + (pmax - pmin) / 2;
-        if (p->p[pbin].left <= value)
-        {
-            pmin = pbin;
-        }
-        else
-        {
-            pmax = pbin;
-        }
-    }
-    pbin = pmin;
-    return pbin;
-}
-
-/*!
- * \param[in] surf  Surface data structure to search.
- * \param[in] x     Unit vector to find.
- * \returns   The bin index that contains \p x.
- *
- * The return value is an index to the \p surf->bin array.
- */
-static int
-find_surface_bin(t_methoddata_insolidangle *surf, rvec x)
-{
-    real theta, phi;
-    int  tbin, pbin;
-    
-    theta = acos(x[ZZ]);
-    phi = atan2(x[YY], x[XX]);
-    tbin = floor(theta / surf->tbinsize);
-    if (tbin >= surf->ntbins)
-    {
-        tbin = surf->ntbins - 1;
-    }
-    pbin = find_partition_bin(&surf->tbin[tbin], phi);
-    return surf->tbin[tbin].p[pbin].bin;
-}
-
-/*!
- * \param[in,out] surf Surface data structure.
- *
- * Clears the reference points from the bins and (re)initializes the edges
- * of the azimuthal bins.
- */
-static void
-clear_surface_points(t_methoddata_insolidangle *surf)
-{
-    int i, j, c;
-
-    surf->nbins = 0;
-    for (i = 0; i < surf->ntbins; ++i)
-    {
-        c = min(sin(surf->tbinsize*i), sin(surf->tbinsize*(i+1)))
-              * M_2PI / surf->targetbinsize + 1;
-        if (c <= 0)
-        {
-            c = 1;
-        }
-        surf->tbin[i].n = c;
-        for (j = 0; j < c; ++j)
-        {
-            surf->tbin[i].p[j].left = -M_PI + j*M_2PI/c - 0.0001;
-            surf->tbin[i].p[j].bin = surf->nbins;
-            surf->bin[surf->nbins].n = 0;
-            surf->nbins++;
-        }
-        surf->tbin[i].p[c].left = M_PI + 0.0001;
-        surf->tbin[i].p[c].bin = -1;
-    }
-}
-
-/*!
- * \param[in,out] surf Surface data structure.
- */
-static void
-free_surface_points(t_methoddata_insolidangle *surf)
-{
-    int i;
-
-    for (i = 0; i < surf->nbins; ++i)
-    {
-        if (surf->bin[i].x)
-        {
-            sfree(surf->bin[i].x);
-        }
-        surf->bin[i].n_alloc = 0;
-        surf->bin[i].x = NULL;
-    }
-}
-
-/*!
- * \param[in,out] surf Surface data structure.
- * \param[in]     tbin Bin number in the zenith angle direction.
- * \param[in]     pbin Bin number in the azimuthal angle direction.
- * \param[in]     x    Point to store.
- */
-static void
-add_surface_point(t_methoddata_insolidangle *surf, int tbin, int pbin, rvec x)
-{
-    int bin;
-
-    bin = surf->tbin[tbin].p[pbin].bin;
-    /* Return if bin is already completely covered */
-    if (surf->bin[bin].n == -1)
-        return;
-    /* Allocate more space if necessary */
-    if (surf->bin[bin].n == surf->bin[bin].n_alloc) {
-        surf->bin[bin].n_alloc += 10;
-        srenew(surf->bin[bin].x, surf->bin[bin].n_alloc);
-    }
-    /* Add the point to the bin */
-    copy_rvec(x, surf->bin[bin].x[surf->bin[bin].n]);
-    ++surf->bin[bin].n;
-}
-
-/*!
- * \param[in,out] surf Surface data structure.
- * \param[in]     tbin Bin number in the zenith angle direction.
- * \param[in]     pbin Bin number in the azimuthal angle direction.
- */
-static void
-mark_surface_covered(t_methoddata_insolidangle *surf, int tbin, int pbin)
-{
-    int bin;
-
-    bin = surf->tbin[tbin].p[pbin].bin;
-    surf->bin[bin].n = -1;
-}
-
-/*!
- * \param[in,out] surf      Surface data structure.
- * \param[in]     tbin      Bin number in the zenith angle direction.
- * \param[in]     phi       Azimuthal angle of \p x.
- * \param[in]     pdelta1   Width of the cone at the lower edge of \p tbin.
- * \param[in]     pdelta2   Width of the cone at the uppper edge of \p tbin.
- * \param[in]     pdeltamax Max. width of the cone inside \p tbin.
- * \param[in]     x         Point to store (should have unit length).
- */
-static void
-update_surface_bin(t_methoddata_insolidangle *surf, int tbin,
-                   real phi, real pdelta1, real pdelta2, real pdeltamax,
-                   rvec x)
-{
-    real pdelta, phi1, phi2;
-    int  pbin1, pbin2, pbin;
-
-    /* Find the edges of the bins affected */
-    pdelta = max(max(pdelta1, pdelta2), pdeltamax);
-    phi1 = phi - pdelta;
-    if (phi1 < -M_PI)
-    {
-        phi1 += M_2PI;
-    }
-    phi2 = phi + pdelta;
-    if (phi2 > M_PI)
-    {
-        phi2 -= M_2PI;
-    }
-    pbin1 = find_partition_bin(&surf->tbin[tbin], phi1);
-    pbin2 = find_partition_bin(&surf->tbin[tbin], phi2);
-    /* Find the edges of completely covered region */
-    pdelta = min(pdelta1, pdelta2);
-    phi1 = phi - pdelta;
-    if (phi1 < -M_PI)
-    {
-        phi1 += M_2PI;
-    }
-    phi2 = phi + pdelta;
-    /* Loop over all affected bins */
-    pbin = pbin1;
-    do
-    {
-        /* Wrap bin around if end reached */
-        if (pbin == surf->tbin[tbin].n)
-        {
-            pbin = 0;
-            phi1 -= M_2PI;
-            phi2 -= M_2PI;
-        }
-        /* Check if bin is completely covered and update */
-        if (surf->tbin[tbin].p[pbin].left >= phi1
-            && surf->tbin[tbin].p[pbin+1].left <= phi2)
-        {
-            mark_surface_covered(surf, tbin, pbin);
-        }
-        else
-        {
-            add_surface_point(surf, tbin, pbin, x);
-        }
-    }
-    while (pbin++ != pbin2); /* Loop including pbin2 */
-}
-
-/*!
- * \param[in,out] surf Surface data structure.
- * \param[in]     x    Point to store (should have unit length).
- *
- * Finds all the bins covered by the cone centered at \p x and calls
- * update_surface_bin() to update them.
- */
-static void
-store_surface_point(t_methoddata_insolidangle *surf, rvec x)
-{
-    real theta, phi;
-    real pdeltamax, tmax;
-    real theta1, theta2, pdelta1, pdelta2;
-    int  tbin, pbin, bin;
-
-    theta = acos(x[ZZ]);
-    phi = atan2(x[YY], x[XX]);
-    /* Find the maximum extent in the phi direction */
-    if (theta <= surf->angcut)
-    {
-        pdeltamax = M_PI;
-        tmax = 0;
-    }
-    else if (theta >= M_PI - surf->angcut)
-    {
-        pdeltamax = M_PI;
-        tmax = M_PI;
-    }
-    else
-    {
-        pdeltamax = asin(sin(surf->angcut) / sin(theta));
-        tmax = acos(cos(theta) / cos(surf->angcut));
-    }
-    /* Find the first affected bin */
-    tbin = max(floor((theta - surf->angcut) / surf->tbinsize), 0);
-    theta1 = tbin * surf->tbinsize;
-    if (theta1 < theta - surf->angcut)
-    {
-        pdelta1 = 0;
-    }
-    else
-    {
-        pdelta1 = M_PI;
-    }
-    /* Loop through all affected bins */
-    while (tbin < ceil((theta + surf->angcut) / surf->tbinsize)
-           && tbin < surf->ntbins)
-    {
-        /* Calculate the next boundaries */
-        theta2 = (tbin+1) * surf->tbinsize;
-        if (theta2 > theta + surf->angcut)
-        {
-            pdelta2 = 0;
-        }
-        else if (tbin == surf->ntbins - 1)
-        {
-            pdelta2 = M_PI;
-        }
-        else
-        {
-            pdelta2 = 2*asin(sqrt(
-                    (sqr(sin(surf->angcut/2)) - sqr(sin((theta2-theta)/2))) /
-                    (sin(theta) * sin(theta2))));
-        }
-        /* Update the bin */
-        if (tmax >= theta1 && tmax <= theta2)
-        {
-            update_surface_bin(surf, tbin, phi, pdelta1, pdelta2, pdeltamax, x);
-        }
-        else
-        {
-            update_surface_bin(surf, tbin, phi, pdelta1, pdelta2, 0, x);
-        }
-        /* Next bin */
-        theta1 = theta2;
-        pdelta1 = pdelta2;
-        ++tbin;
-    }
-}
-
-/*!
- * \param[in,out] surf Surface data structure.
- *
- * Currently, this function does nothing.
- */
-static void
-optimize_surface_points(t_methoddata_insolidangle *surf)
-{
-    /* TODO: Implement */
-}
-
-/*!
- * \param[in] surf Surface data structure.
- * \returns   An estimate for the area covered by the reference points.
- */
-static real
-estimate_covered_fraction(t_methoddata_insolidangle *surf)
-{
-    int  t, p, n;
-    real cfrac, tfrac, pfrac;
-
-    cfrac = 0.0;
-    for (t = 0; t < surf->ntbins; ++t)
-    {
-        tfrac = cos(t * surf->tbinsize) - cos((t+1) * surf->tbinsize);
-        for (p = 0; p < surf->tbin[t].n; ++p)
-        {
-            pfrac = surf->tbin[t].p[p+1].left - surf->tbin[t].p[p].left;
-            n = surf->bin[surf->tbin[t].p[p].bin].n;
-            if (n == -1) /* Bin completely covered */
-            {
-                cfrac += tfrac * pfrac;
-            }
-            else if (n > 0) /* Bin partially covered */
-            {
-                cfrac += tfrac * pfrac / 2; /* A rough estimate */
-            }
-        }
-    }
-    return cfrac / (4*M_PI);
-}
-
-/*!
- * \param[in] surf  Surface data structure to search.
- * \param[in] x     Unit vector to check.
- * \returns   TRUE if \p x is within the solid angle, FALSE otherwise.
- */
-static gmx_bool
-is_surface_covered(t_methoddata_insolidangle *surf, rvec x)
-{
-    int  bin, i;
-
-    bin = find_surface_bin(surf, x);
-    /* Check for completely covered bin */
-    if (surf->bin[bin].n == -1)
-    {
-        return TRUE;
-    }
-    /* Check each point that partially covers the bin */
-    for (i = 0; i < surf->bin[bin].n; ++i)
-    {
-        if (sph_distc(x, surf->bin[bin].x[i]) < surf->distccut)
-        {
-            return TRUE;
-        }
-    }
-    return FALSE;
-}
diff --git a/src/gmxlib/selection/sm_keywords.c b/src/gmxlib/selection/sm_keywords.c
deleted file mode 100644 (file)
index afcb2e3..0000000
+++ /dev/null
@@ -1,747 +0,0 @@
-/*
- *
- *                This source code is part of
- *
- *                 G   R   O   M   A   C   S
- *
- *          GROningen MAchine for Chemical Simulations
- *
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
- * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
- * Copyright (c) 2001-2009, The GROMACS development team,
- * check out http://www.gromacs.org for more information.
-
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * If you want to redistribute modifications, please consider that
- * scientific software is very special. Version control is crucial -
- * bugs must be traceable. We will be happy to consider code for
- * inclusion in the official distribution, but derived work must not
- * be called official GROMACS. Details are found in the README & COPYING
- * files - if they are missing, get the official version at www.gromacs.org.
- *
- * To help us fund GROMACS development, we humbly ask that you cite
- * the papers on the package - you can find them in the top README file.
- *
- * For more info, check our website at http://www.gromacs.org
- */
-/*! \internal \file
- * \brief Implementations of internal selection methods for numeric and
- * string keyword evaluation.
- */
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <ctype.h>
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>  /*old Mac needs types before regex.h*/
-#endif
-#ifdef HAVE_REGEX_H
-#include <regex.h>
-#define USE_REGEX
-#endif
-
-#include <gmx_fatal.h>
-#include <macros.h>
-#include <smalloc.h>
-#include <string2.h>
-
-#include <selmethod.h>
-
-#include "keywords.h"
-#include "parsetree.h"
-#include "selelem.h"
-
-/** Allocates data for integer keyword evaluation. */
-static void *
-init_data_kwint(int npar, gmx_ana_selparam_t *param);
-/** Allocates data for real keyword evaluation. */
-static void *
-init_data_kwreal(int npar, gmx_ana_selparam_t *param);
-/** Allocates data for string keyword evaluation. */
-static void *
-init_data_kwstr(int npar, gmx_ana_selparam_t *param);
-/** Initializes data for integer keyword evaluation. */
-static int
-init_kwint(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
-/** Initializes data for real keyword evaluation. */
-static int
-init_kwreal(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
-/** Initializes data for string keyword evaluation. */
-static int
-init_kwstr(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
-/** Frees the memory allocated for string keyword evaluation. */
-static void
-free_data_kwstr(void *data);
-/** Evaluates integer selection keywords. */
-static int
-evaluate_keyword_int(t_topology *top, t_trxframe *fr, t_pbc *pbc,
-                     gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
-/** Evaluates real selection keywords. */
-static int
-evaluate_keyword_real(t_topology *top, t_trxframe *fr, t_pbc *pbc,
-                      gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
-/** Evaluates string selection keywords. */
-static int
-evaluate_keyword_str(t_topology *top, t_trxframe *fr, t_pbc *pbc,
-                     gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
-
-/*! \internal \brief
- * Data structure for integer keyword expression evaluation.
- */
-typedef struct t_methoddata_kwint
-{
-    /** Array of values for the keyword. */
-    int               *v;
-    /** Number of ranges in the \p r array. */
-    int                n;
-    /*! \brief
-     * Array of sorted integer ranges to match against.
-     *
-     * Each range is made of two integers, giving the endpoints (inclusive).
-     * This field stores the pointer to the ranges allocated by the
-     * parameter parser; see \ref SPAR_RANGES for more information.
-     */
-    int               *r;
-} t_methoddata_kwint;
-
-/*! \internal \brief
- * Data structure for real keyword expression evaluation.
- */
-typedef struct t_methoddata_kwreal
-{
-    /** Array of values for the keyword. */
-    real              *v;
-    /** Number of ranges in the \p r array. */
-    int                n;
-    /*! \brief
-     * Array of sorted ranges to match against.
-     *
-     * Each range is made of two values, giving the endpoints (inclusive).
-     * This field stores the pointer to the ranges allocated by the
-     * parameter parser; see \ref SPAR_RANGES for more information.
-     */
-    real              *r;
-} t_methoddata_kwreal;
-
-/*! \internal \brief
- * Data structure for string keyword expression evaluation.
- */
-typedef struct t_methoddata_kwstr
-{
-    /** Array of values for the keyword. */
-    char             **v;
-    /** Number of elements in the \p val array. */
-    int                n;
-    /*! \internal \brief
-     * Array of strings/regular expressions to match against.
-     */
-    struct t_methoddata_kwstr_match {
-        /** TRUE if the expression is a regular expression, FALSE otherwise. */
-        gmx_bool           bRegExp;
-        /** The value to match against. */
-        union {
-#ifdef USE_REGEX
-            /** Compiled regular expression if \p bRegExp is TRUE. */
-            regex_t    r;
-#endif
-            /** The string if \p bRegExp is FALSE; */
-            char      *s;
-        }              u;
-    }                 *m;
-} t_methoddata_kwstr;
-
-/** Parameters for integer keyword evaluation. */
-static gmx_ana_selparam_t smparams_keyword_int[] = {
-    {NULL, {INT_VALUE, -1, {NULL}}, NULL, SPAR_ATOMVAL},
-    {NULL, {INT_VALUE, -1, {NULL}}, NULL, SPAR_RANGES | SPAR_VARNUM},
-};
-
-/** Parameters for real keyword evaluation. */
-static gmx_ana_selparam_t smparams_keyword_real[] = {
-    {NULL, {REAL_VALUE, -1, {NULL}}, NULL, SPAR_ATOMVAL | SPAR_DYNAMIC},
-    {NULL, {REAL_VALUE, -1, {NULL}}, NULL, SPAR_RANGES | SPAR_VARNUM},
-};
-
-/** Parameters for string keyword evaluation. */
-static gmx_ana_selparam_t smparams_keyword_str[] = {
-    {NULL, {STR_VALUE, -1, {NULL}}, NULL, SPAR_ATOMVAL},
-    {NULL, {STR_VALUE, -1, {NULL}}, NULL, SPAR_VARNUM},
-};
-
-/** \internal Selection method data for integer keyword evaluation. */
-gmx_ana_selmethod_t sm_keyword_int = {
-    "kw_int", GROUP_VALUE, SMETH_SINGLEVAL,
-    asize(smparams_keyword_int), smparams_keyword_int,
-    &init_data_kwint,
-     NULL,
-    &init_kwint,
-     NULL,
-     NULL,
-     NULL,
-    &evaluate_keyword_int,
-     NULL,
-    {NULL, 0, NULL},
-};
-
-/** \internal Selection method data for real keyword evaluation. */
-gmx_ana_selmethod_t sm_keyword_real = {
-    "kw_real", GROUP_VALUE, SMETH_SINGLEVAL,
-    asize(smparams_keyword_real), smparams_keyword_real,
-    &init_data_kwreal,
-     NULL,
-    &init_kwreal,
-     NULL,
-     NULL,
-     NULL,
-    &evaluate_keyword_real,
-     NULL,
-    {NULL, 0, NULL},
-};
-
-/** \internal Selection method data for string keyword evaluation. */
-gmx_ana_selmethod_t sm_keyword_str = {
-    "kw_str", GROUP_VALUE, SMETH_SINGLEVAL,
-    asize(smparams_keyword_str), smparams_keyword_str,
-    &init_data_kwstr,
-     NULL,
-    &init_kwstr,
-     NULL,
-    &free_data_kwstr,
-     NULL,
-    &evaluate_keyword_str,
-     NULL,
-    {NULL, 0, NULL},
-};
-
-/** Initializes keyword evaluation for an arbitrary group. */
-static int
-init_kweval(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
-/** Initializes output for keyword evaluation in an arbitrary group. */
-static int
-init_output_kweval(t_topology *top, gmx_ana_selvalue_t *out, void *data);
-/** Frees the data allocated for keyword evaluation in an arbitrary group. */
-static void
-free_data_kweval(void *data);
-/** Initializes frame evaluation for keyword evaluation in an arbitrary group. */
-static int
-init_frame_kweval(t_topology *top, t_trxframe *fr, t_pbc *pbc, void *data);
-/** Evaluates keywords in an arbitrary group. */
-static int
-evaluate_kweval(t_topology *top, t_trxframe *fr, t_pbc *pbc,
-                gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
-
-/*! \internal \brief
- * Data structure for keyword evaluation in arbitrary groups.
- */
-typedef struct
-{
-    /** Wrapped keyword method for evaluating the values. */
-    gmx_ana_selmethod_t  *kwmethod;
-    /** Method data for \p kwmethod. */
-    void                 *kwmdata;
-    /** Group in which \p kwmethod should be evaluated. */
-    gmx_ana_index_t       g;
-} t_methoddata_kweval;
-
-/** Parameters for keyword evaluation in an arbitrary group. */
-static gmx_ana_selparam_t smparams_kweval[] = {
-    {NULL,   {GROUP_VALUE, 1, {NULL}}, NULL, SPAR_DYNAMIC},
-};
-
-
-/********************************************************************
- * INTEGER KEYWORD EVALUATION
- ********************************************************************/
-
-/*!
- * \param[in] npar  Not used.
- * \param     param Not used.
- * \returns   Pointer to the allocated data (\ref t_methoddata_kwint).
- *
- * Allocates memory for a \ref t_methoddata_kwint structure.
- */
-static void *
-init_data_kwint(int npar, gmx_ana_selparam_t *param)
-{
-    t_methoddata_kwint *data;
-
-    snew(data, 1);
-    return data;
-}
-
-/*!
- * \param[in] top   Not used.
- * \param[in] npar  Not used (should be 2).
- * \param[in] param Method parameters (should point to \ref smparams_keyword_int).
- * \param[in] data  Should point to \ref t_methoddata_kwint.
- * \returns   0 (the initialization always succeeds).
- */
-static int
-init_kwint(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data)
-{
-    t_methoddata_kwint *d = (t_methoddata_kwint *)data;
-
-    d->v = param[0].val.u.i;
-    d->n = param[1].val.nr;
-    d->r = param[1].val.u.i;
-    return 0;
-}
-
-/*!
- * See sel_updatefunc() for description of the parameters.
- * \p data should point to a \c t_methoddata_kwint.
- *
- * Does a binary search to find which atoms match the ranges in the
- * \c t_methoddata_kwint structure for this selection.
- * Matching atoms are stored in \p out->u.g.
- */
-static int
-evaluate_keyword_int(t_topology *top, t_trxframe *fr, t_pbc *pbc,
-                     gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
-{
-    t_methoddata_kwint *d = (t_methoddata_kwint *)data;
-    int                 n, i, j, jmin, jmax;
-    int                 val;
-
-    out->u.g->isize = 0;
-    n    = d->n;
-    for (i = 0; i < g->isize; ++i)
-    {
-        val = d->v[i];
-        if (d->r[0] > val || d->r[2*n-1] < val)
-        {
-            continue;
-        }
-        jmin = 0;
-        jmax = n;
-        while (jmax - jmin > 1)
-        {
-            j = jmin + (jmax - jmin) / 2;
-            if (val < d->r[2*j])
-            {
-                jmax = j;
-            }
-            else
-            {
-                jmin = j;
-                if (val <= d->r[2*j+1])
-                {
-                    break;
-                }
-                /* ++jmin;*/
-            }
-        }
-        if (val <= d->r[2*jmin+1])
-        {
-            out->u.g->index[out->u.g->isize++] = g->index[i];
-        }
-    }
-    return 0;
-}
-
-
-/********************************************************************
- * REAL KEYWORD EVALUATION
- ********************************************************************/
-
-/*!
- * \param[in] npar  Not used.
- * \param     param Not used.
- * \returns   Pointer to the allocated data (\ref t_methoddata_kwreal).
- *
- * Allocates memory for a \ref t_methoddata_kwreal structure.
- */
-static void *
-init_data_kwreal(int npar, gmx_ana_selparam_t *param)
-{
-    t_methoddata_kwreal *data;
-
-    snew(data, 1);
-    return data;
-}
-
-/*!
- * \param[in] top   Not used.
- * \param[in] npar  Not used (should be 2).
- * \param[in] param Method parameters (should point to \ref smparams_keyword_real).
- * \param[in] data  Should point to \ref t_methoddata_kwreal.
- * \returns   0 (the initialization always succeeds).
- */
-static int
-init_kwreal(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data)
-{
-    t_methoddata_kwreal *d = (t_methoddata_kwreal *)data;
-
-    d->v = param[0].val.u.r;
-    d->n = param[1].val.nr;
-    d->r = param[1].val.u.r;
-    return 0;
-}
-
-/*!
- * See sel_updatefunc() for description of the parameters.
- * \p data should point to a \c t_methoddata_kwreal.
- *
- * Does a binary search to find which atoms match the ranges in the
- * \c t_methoddata_kwreal structure for this selection.
- * Matching atoms are stored in \p out->u.g.
- */
-static int
-evaluate_keyword_real(t_topology *top, t_trxframe *fr, t_pbc *pbc,
-                     gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
-{
-    t_methoddata_kwreal *d = (t_methoddata_kwreal *)data;
-    int                  n, i, j, jmin, jmax;
-    real                 val;
-
-    out->u.g->isize = 0;
-    n    = d->n;
-    for (i = 0; i < g->isize; ++i)
-    {
-        val = d->v[i];
-        if (d->r[0] > val || d->r[2*n-1] < val)
-        {
-            continue;
-        }
-        jmin = 0;
-        jmax = n;
-        while (jmax - jmin > 1)
-        {
-            j = jmin + (jmax - jmin) / 2;
-            if (val < d->r[2*j])
-            {
-                jmax = j;
-            }
-            else
-            {
-                jmin = j;
-                if (val <= d->r[2*j+1])
-                {
-                    break;
-                }
-                /* ++jmin;*/
-            }
-        }
-        if (val <= d->r[2*jmin+1])
-        {
-            out->u.g->index[out->u.g->isize++] = g->index[i];
-        }
-    }
-    return 0;
-}
-
-
-/********************************************************************
- * STRING KEYWORD EVALUATION
- ********************************************************************/
-
-/*!
- * \param[in] npar  Not used.
- * \param     param Not used.
- * \returns Pointer to the allocated data (\ref t_methoddata_kwstr).
- *
- * Allocates memory for a \ref t_methoddata_kwstr structure.
- */
-static void *
-init_data_kwstr(int npar, gmx_ana_selparam_t *param)
-{
-    t_methoddata_kwstr *data;
-
-    snew(data, 1);
-    return data;
-}
-
-/*!
- * \param[in] top   Not used.
- * \param[in] npar  Not used (should be 2).
- * \param[in] param Method parameters (should point to \ref smparams_keyword_str).
- * \param[in] data  Should point to \ref t_methoddata_kwstr.
- * \returns   0 (the initialization always succeeds).
- */
-static int
-init_kwstr(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data)
-{
-    t_methoddata_kwstr *d = (t_methoddata_kwstr *)data;
-    char               *buf;
-    char               *s;
-    int                 i;
-    size_t              j;
-    gmx_bool                bRegExp;
-
-    d->v   = param[0].val.u.s;
-    d->n   = param[1].val.nr;
-    /* Return if this is not the first time */
-    if (d->m)
-    {
-        return 0;
-    }
-    snew(d->m, d->n);
-    for (i = 0; i < d->n; ++i)
-    {
-        s = param[1].val.u.s[i];
-        bRegExp = FALSE;
-        for (j = 0; j < strlen(s); ++j)
-        {
-            if (ispunct(s[j]) && s[j] != '?' && s[j] != '*')
-            {
-                bRegExp = TRUE;
-                break;
-            }
-        }
-        if (bRegExp)
-        {
-#ifdef USE_REGEX
-            snew(buf, strlen(s) + 3);
-            sprintf(buf, "^%s$", s);
-            if (regcomp(&d->m[i].u.r, buf, REG_EXTENDED | REG_NOSUB))
-            {
-                bRegExp = FALSE;
-                fprintf(stderr, "WARNING: error in regular expression,\n"
-                                "         will match '%s' as a simple string\n", s);
-            }
-            sfree(buf);
-#else
-            bRegExp = FALSE;
-            fprintf(stderr, "WARNING: no regular expressions support,\n"
-                            "         will match '%s' as a simple string\n", s);
-#endif
-        }
-        if (!bRegExp)
-        {
-            d->m[i].u.s = s;
-        }
-        d->m[i].bRegExp = bRegExp;
-    }
-    return 0;
-}
-
-/*!
- * \param data Data to free (should point to a \ref t_methoddata_kwstr).
- *
- * Frees the memory allocated for t_methoddata_kwstr::val.
- */
-static void
-free_data_kwstr(void *data)
-{
-    t_methoddata_kwstr *d = (t_methoddata_kwstr *)data;
-    int                 i;
-
-    for (i = 0; i < d->n; ++i)
-    {
-        if (d->m[i].bRegExp)
-        {
-#ifdef USE_REGEX
-            /* This branch should only be taken if regular expressions
-             * are available, but the ifdef is still needed. */
-            regfree(&d->m[i].u.r);
-#endif
-        }
-    }
-    sfree(d->m);
-}
-
-/*!
- * See sel_updatefunc() for description of the parameters.
- * \p data should point to a \c t_methoddata_kwstr.
- *
- * Does a linear search to find which atoms match the strings in the
- * \c t_methoddata_kwstr structure for this selection.
- * Wildcards are allowed in the strings.
- * Matching atoms are stored in \p out->u.g.
- */
-static int
-evaluate_keyword_str(t_topology *top, t_trxframe *fr, t_pbc *pbc,
-                     gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
-{
-    t_methoddata_kwstr *d = (t_methoddata_kwstr *)data;
-    int                 i, j;
-    gmx_bool                bFound;
-
-    out->u.g->isize = 0;
-    for (i = 0; i < g->isize; ++i)
-    {
-        bFound = FALSE;
-        for (j = 0; j < d->n && !bFound; ++j)
-        {
-            if (d->m[j].bRegExp)
-            {
-#ifdef USE_REGEX
-                /* This branch should only be taken if regular expressions
-                 * are available, but the ifdef is still needed. */
-                if (!regexec(&d->m[j].u.r, d->v[i], 0, NULL, 0))
-                {
-                    bFound = TRUE;
-                }
-#endif
-            }
-            else
-            {
-                if (gmx_wcmatch(d->m[j].u.s, d->v[i]) == 0)
-                {
-                    bFound = TRUE;
-                }
-            }
-        }
-        if (bFound)
-        {
-            out->u.g->index[out->u.g->isize++] = g->index[i];
-        }
-    }
-    return 0;
-}
-
-
-/********************************************************************
- * KEYWORD EVALUATION FOR ARBITRARY GROUPS
- ********************************************************************/
-
-/*!
- * \param[in] top   Not used.
- * \param[in] npar  Not used.
- * \param[in] param Not used.
- * \param[in] data  Should point to \ref t_methoddata_kweval.
- * \returns   0 on success, a non-zero error code on return.
- *
- * Calls the initialization method of the wrapped keyword.
- */
-static int
-init_kweval(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data)
-{
-    t_methoddata_kweval *d = (t_methoddata_kweval *)data;
-
-    return d->kwmethod->init(top, 0, NULL, d->kwmdata);
-}
-
-/*!
- * \param[in]     top   Not used.
- * \param[in,out] out   Pointer to output data structure.
- * \param[in,out] data  Should point to \c t_methoddata_kweval.
- * \returns       0 for success.
- */
-static int
-init_output_kweval(t_topology *top, gmx_ana_selvalue_t *out, void *data)
-{
-    t_methoddata_kweval *d = (t_methoddata_kweval *)data;
-
-    out->nr = d->g.isize;
-    return 0;
-}
-
-/*!
- * \param data Data to free (should point to a \c t_methoddata_kweval).
- *
- * Frees the memory allocated for all the members of \c t_methoddata_kweval.
- */
-static void
-free_data_kweval(void *data)
-{
-    t_methoddata_kweval *d = (t_methoddata_kweval *)data;
-
-    _gmx_selelem_free_method(d->kwmethod, d->kwmdata);
-}
-
-/*!
- * \param[in]  top  Topology.
- * \param[in]  fr   Current frame.
- * \param[in]  pbc  PBC structure.
- * \param      data Should point to a \ref t_methoddata_kweval.
- * \returns    0 on success, a non-zero error code on error.
- *
- * Creates a lookup structure that enables fast queries of whether a point
- * is within the solid angle or not.
- */
-static int
-init_frame_kweval(t_topology *top, t_trxframe *fr, t_pbc *pbc, void *data)
-{
-    t_methoddata_kweval *d = (t_methoddata_kweval *)data;
-
-    return d->kwmethod->init_frame(top, fr, pbc, d->kwmdata);
-}
-
-/*!
- * See sel_updatefunc() for description of the parameters.
- * \p data should point to a \c t_methoddata_kweval.
- *
- * Calls the evaluation function of the wrapped keyword with the given
- * parameters, with the exception of using \c t_methoddata_kweval::g for the
- * evaluation group.
- */
-static int
-evaluate_kweval(t_topology *top, t_trxframe *fr, t_pbc *pbc,
-                gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
-{
-    t_methoddata_kweval *d = (t_methoddata_kweval *)data;
-
-    return d->kwmethod->update(top, fr, pbc, &d->g, out, d->kwmdata);
-}
-
-/*!
- * \param[out]  selp    Pointer to receive a pointer to the created selection
- *      element (set to NULL on error).
- * \param[in]   method  Keyword selection method to evaluate.
- * \param[in]   param   Parameter that gives the group to evaluate \p method in.
- * \param[in]   scanner Scanner data structure.
- * \returns     0 on success, non-zero error code on error.
- *
- * Creates a \ref SEL_EXPRESSION selection element (pointer put in \c *selp)
- * that evaluates the keyword method given by \p method in the group given by
- * \p param.
- */
-int
-_gmx_sel_init_keyword_evaluator(t_selelem **selp, gmx_ana_selmethod_t *method,
-                                t_selexpr_param *param, void *scanner)
-{
-    t_selelem            *sel;
-    t_methoddata_kweval  *data;
-
-    if ((method->flags & (SMETH_SINGLEVAL | SMETH_VARNUMVAL))
-        || method->outinit || method->pupdate)
-    {
-        _gmx_selexpr_free_params(param);
-        gmx_incons("unsupported keyword method for arbitrary group evaluation");
-        return -1;
-    }
-
-    *selp = NULL;
-    sel = _gmx_selelem_create(SEL_EXPRESSION);
-    _gmx_selelem_set_method(sel, method, scanner);
-
-    snew(data, 1);
-    data->kwmethod = sel->u.expr.method;
-    data->kwmdata  = sel->u.expr.mdata;
-    gmx_ana_index_clear(&data->g);
-
-    snew(sel->u.expr.method, 1);
-    memcpy(sel->u.expr.method, data->kwmethod, sizeof(gmx_ana_selmethod_t));
-    sel->u.expr.method->flags       |= SMETH_VARNUMVAL;
-    sel->u.expr.method->init_data    = NULL;
-    sel->u.expr.method->set_poscoll  = NULL;
-    sel->u.expr.method->init         = method->init ? &init_kweval : NULL;
-    sel->u.expr.method->outinit      = &init_output_kweval;
-    sel->u.expr.method->free         = &free_data_kweval;
-    sel->u.expr.method->init_frame   = method->init_frame ? &init_frame_kweval : NULL;
-    sel->u.expr.method->update       = &evaluate_kweval;
-    sel->u.expr.method->pupdate      = NULL;
-    sel->u.expr.method->nparams      = asize(smparams_kweval);
-    sel->u.expr.method->param        = smparams_kweval;
-    _gmx_selelem_init_method_params(sel, scanner);
-    sel->u.expr.mdata = data;
-
-    sel->u.expr.method->param[0].val.u.g = &data->g;
-
-    sfree(param->name);
-    param->name = NULL;
-    if (!_gmx_sel_parse_params(param, sel->u.expr.method->nparams,
-                               sel->u.expr.method->param, sel, scanner))
-    {
-        _gmx_selelem_free(sel);
-        return -1;
-    }
-    *selp = sel;
-    return 0;
-}
diff --git a/src/gmxlib/selection/sm_merge.c b/src/gmxlib/selection/sm_merge.c
deleted file mode 100644 (file)
index 34d2b0d..0000000
+++ /dev/null
@@ -1,382 +0,0 @@
-/*
- *
- *                This source code is part of
- *
- *                 G   R   O   M   A   C   S
- *
- *          GROningen MAchine for Chemical Simulations
- *
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
- * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
- * Copyright (c) 2001-2009, The GROMACS development team,
- * check out http://www.gromacs.org for more information.
-
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * If you want to redistribute modifications, please consider that
- * scientific software is very special. Version control is crucial -
- * bugs must be traceable. We will be happy to consider code for
- * inclusion in the official distribution, but derived work must not
- * be called official GROMACS. Details are found in the README & COPYING
- * files - if they are missing, get the official version at www.gromacs.org.
- *
- * To help us fund GROMACS development, we humbly ask that you cite
- * the papers on the package - you can find them in the top README file.
- *
- * For more info, check our website at http://www.gromacs.org
- */
-/*! \internal \file
- * \brief Implementation of the merging selection modifier.
- */
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <macros.h>
-#include <smalloc.h>
-#include <vec.h>
-
-#include <position.h>
-#include <selmethod.h>
-
-/*! \internal \brief
- * Data structure for the merging selection modifiers.
- */
-typedef struct
-{
-    /** Input positions. */
-    gmx_ana_pos_t    p1;
-    /** Other input positions. */
-    gmx_ana_pos_t    p2;
-    /** Group to store the output atom indices. */
-    gmx_ana_index_t  g;
-    /** Stride for merging (\c stride values from \c p1 for each in \c p2). */
-    int              stride;
-} t_methoddata_merge;
-
-/** Allocates data for the merging selection modifiers. */
-static void *
-init_data_merge(int npar, gmx_ana_selparam_t *param);
-/** Initializes data for the merging selection modifiers. */
-static int
-init_merge(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
-/** Initializes output for the \p merge selection modifier. */
-static int
-init_output_merge(t_topology *top, gmx_ana_selvalue_t *out, void *data);
-/** Initializes output for the \p plus selection modifier. */
-static int
-init_output_plus(t_topology *top, gmx_ana_selvalue_t *out, void *data);
-/** Frees the memory allocated for the merging selection modifiers. */
-static void
-free_data_merge(void *data);
-/** Evaluates the \p merge selection modifier. */
-static int
-evaluate_merge(t_topology *top, t_trxframe *fr, t_pbc *pbc,
-               gmx_ana_pos_t *p, gmx_ana_selvalue_t *out, void *data);
-/** Evaluates the \p plus selection modifier. */
-static int
-evaluate_plus(t_topology *top, t_trxframe *fr, t_pbc *pbc,
-              gmx_ana_pos_t *p, gmx_ana_selvalue_t *out, void *data);
-
-/** Parameters for the merging selection modifiers. */
-static gmx_ana_selparam_t smparams_merge[] = {
-    {NULL,       {POS_VALUE, -1, {NULL}}, NULL, SPAR_DYNAMIC | SPAR_VARNUM},
-    {NULL,       {POS_VALUE, -1, {NULL}}, NULL, SPAR_DYNAMIC | SPAR_VARNUM},
-    {"stride",   {INT_VALUE,  1, {NULL}}, NULL, SPAR_OPTIONAL},
-};
-
-/** Help text for the merging selection modifiers. */
-static const char *help_merge[] = {
-    "MERGING SELECTIONS[PAR]",
-
-    "[TT]POSEXPR merge POSEXPR [stride INT][tt][BR]",
-    "[TT]POSEXPR merge POSEXPR [merge POSEXPR ...][tt][BR]",
-    "[TT]POSEXPR plus POSEXPR [plus POSEXPR ...][tt][PAR]",
-
-    "Basic selection keywords can only create selections where each atom",
-    "occurs at most once. The [TT]merge[tt] and [TT]plus[tt] selection",
-    "keywords can be used to work around this limitation. Both create",
-    "a selection that contains the positions from all the given position",
-    "expressions, even if they contain duplicates.",
-    "The difference between the two is that [TT]merge[tt] expects two or more",
-    "selections with the same number of positions, and the output contains",
-    "the input positions selected from each expression in turn, i.e.,",
-    "the output is like A1 B1 A2 B2 and so on. It is also possible to merge",
-    "selections of unequal size as long as the size of the first is a",
-    "multiple of the second one. The [TT]stride[tt] parameter can be used",
-    "to explicitly provide this multiplicity.",
-    "[TT]plus[tt] simply concatenates the positions after each other, and",
-    "can work also with selections of different sizes.",
-    "These keywords are valid only at the selection level, not in any",
-    "subexpressions.[PAR]",
-};
-
-/** \internal Selection method data for the \p plus modifier. */
-gmx_ana_selmethod_t sm_merge = {
-    "merge", POS_VALUE, SMETH_MODIFIER,
-    asize(smparams_merge), smparams_merge,
-    &init_data_merge,
-    NULL,
-    &init_merge,
-    &init_output_merge,
-    &free_data_merge,
-    NULL,
-    NULL,
-    &evaluate_merge,
-    {"merge POSEXPR", asize(help_merge), help_merge},
-};
-
-/** \internal Selection method data for the \p plus modifier. */
-gmx_ana_selmethod_t sm_plus = {
-    "plus", POS_VALUE, SMETH_MODIFIER,
-    asize(smparams_merge)-1, smparams_merge,
-    &init_data_merge,
-    NULL,
-    &init_merge,
-    &init_output_plus,
-    &free_data_merge,
-    NULL,
-    NULL,
-    &evaluate_plus,
-    {"plus POSEXPR", asize(help_merge), help_merge},
-};
-
-/*!
- * \param[in]     npar  Should be 2 for \c plus and 3 for \c merge.
- * \param[in,out] param Method parameters (should point to a copy of
- *   \ref smparams_merge).
- * \returns Pointer to the allocated data (\p t_methoddata_merge).
- *
- * Allocates memory for a \p t_methoddata_merge structure.
- */
-static void *
-init_data_merge(int npar, gmx_ana_selparam_t *param)
-{
-    t_methoddata_merge *data;
-
-    snew(data, 1);
-    data->stride = 0;
-    param[0].val.u.p = &data->p1;
-    param[1].val.u.p = &data->p2;
-    if (npar > 2)
-    {
-        param[2].val.u.i = &data->stride;
-    }
-    return data;
-}
-
-/*!
- * \param[in] top   Not used.
- * \param[in] npar  Not used (should be 2 or 3).
- * \param[in] param Method parameters (should point to \ref smparams_merge).
- * \param[in] data  Should point to a \p t_methoddata_merge.
- * \returns   0 if everything is successful, -1 on error.
- */
-static int
-init_merge(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data)
-{
-    t_methoddata_merge *d = (t_methoddata_merge *)data;
-    int                 i;
-
-    if (d->stride < 0)
-    {
-        fprintf(stderr, "error: stride for merging should be positive\n");
-        return -1;
-    }
-    /* If no stride given, deduce it from the input sizes */
-    if (d->stride == 0)
-    {
-        d->stride = d->p1.nr / d->p2.nr;
-    }
-    if (d->p1.nr != d->stride*d->p2.nr)
-    {
-        fprintf(stderr, "error: the number of positions to be merged are not compatible\n");
-        return -1;
-    }
-    /* We access the m.b.nra field instead of g->isize in the position
-     * data structures to handle cases where g is NULL
-     * (this occurs with constant positions. */
-    gmx_ana_index_reserve(&d->g, d->p1.m.b.nra + d->p2.m.b.nra);
-    d->g.isize = d->p1.m.b.nra + d->p2.m.b.nra;
-    return 0;
-}
-
-/*! \brief
- * Does common initialization to all merging modifiers.
- *
- * \param[in]     top   Topology data structure.
- * \param[in,out] out   Pointer to output data structure.
- * \param[in,out] data  Should point to \c t_methoddata_merge.
- * \returns       0 for success.
- */
-static int
-init_output_common(t_topology *top, gmx_ana_selvalue_t *out, void *data)
-{
-    t_methoddata_merge *d = (t_methoddata_merge *)data;
-
-    if (d->p1.m.type != d->p2.m.type)
-    {
-        /* TODO: Maybe we could pick something else here? */
-        out->u.p->m.type = INDEX_UNKNOWN;
-    }
-    else
-    {
-        out->u.p->m.type = d->p1.m.type;
-    }
-    gmx_ana_pos_reserve(out->u.p, d->p1.nr + d->p2.nr, d->g.isize);
-    if (d->p1.v)
-    {
-        gmx_ana_pos_reserve_velocities(out->u.p);
-    }
-    if (d->p1.f)
-    {
-        gmx_ana_pos_reserve_forces(out->u.p);
-    }
-    gmx_ana_pos_set_evalgrp(out->u.p, &d->g);
-    gmx_ana_pos_empty_init(out->u.p);
-    d->g.isize = 0;
-    return 0;
-}
-
-/*!
- * \param[in]     top   Topology data structure.
- * \param[in,out] out   Pointer to output data structure.
- * \param[in,out] data  Should point to \c t_methoddata_merge.
- * \returns       0 for success.
- */
-static int
-init_output_merge(t_topology *top, gmx_ana_selvalue_t *out, void *data)
-{
-    t_methoddata_merge *d = (t_methoddata_merge *)data;
-    int                 i, j;
-
-    init_output_common(top, out, data);
-    for (i = 0; i < d->p2.nr; ++i)
-    {
-        for (j = 0; j < d->stride; ++j)
-        {
-            gmx_ana_pos_append_init(out->u.p, &d->g, &d->p1, d->stride*i+j);
-        }
-        gmx_ana_pos_append_init(out->u.p, &d->g, &d->p2, i);
-    }
-    return 0;
-}
-
-/*!
- * \param[in]     top   Topology data structure.
- * \param[in,out] out   Pointer to output data structure.
- * \param[in,out] data  Should point to \c t_methoddata_merge.
- * \returns       0 for success.
- */
-static int
-init_output_plus(t_topology *top, gmx_ana_selvalue_t *out, void *data)
-{
-    t_methoddata_merge *d = (t_methoddata_merge *)data;
-    int                 i;
-
-    init_output_common(top, out, data);
-    for (i = 0; i < d->p1.nr; ++i)
-    {
-        gmx_ana_pos_append_init(out->u.p, &d->g, &d->p1, i);
-    }
-    for (i = 0; i < d->p2.nr; ++i)
-    {
-        gmx_ana_pos_append_init(out->u.p, &d->g, &d->p2, i);
-    }
-    return 0;
-}
-
-/*!
- * \param data Data to free (should point to a \p t_methoddata_merge).
- *
- * Frees the memory allocated for \c t_methoddata_merge.
- */
-static void
-free_data_merge(void *data)
-{
-    t_methoddata_merge *d = (t_methoddata_merge *)data;
-
-    gmx_ana_index_deinit(&d->g);
-}
-
-/*!
- * \param[in]  top   Not used.
- * \param[in]  fr    Not used.
- * \param[in]  pbc   Not used.
- * \param[in]  p     Positions to merge (should point to \p data->p1).
- * \param[out] out   Output data structure (\p out->u.p is used).
- * \param[in]  data  Should point to a \p t_methoddata_merge.
- * \returns    0 on success.
- */
-static int
-evaluate_merge(t_topology *top, t_trxframe *fr, t_pbc *pbc,
-               gmx_ana_pos_t *p, gmx_ana_selvalue_t *out, void *data)
-{
-    t_methoddata_merge *d = (t_methoddata_merge *)data;
-    int                 i, j;
-    int                 refid;
-
-    if (d->p1.nr != d->stride*d->p2.nr)
-    {
-        fprintf(stderr, "error: the number of positions to be merged are not compatible\n");
-        return -1;
-    }
-    d->g.isize = 0;
-    gmx_ana_pos_empty(out->u.p);
-    for (i = 0; i < d->p2.nr; ++i)
-    {
-        for (j = 0; j < d->stride; ++j)
-        {
-            refid = d->p1.m.refid[d->stride*i+j];
-            if (refid != -1)
-            {
-                refid = (d->stride+1) * (refid / d->stride) + (refid % d->stride);
-            }
-            gmx_ana_pos_append(out->u.p, &d->g, &d->p1, d->stride*i+j, refid);
-        }
-        refid = (d->stride+1)*d->p2.m.refid[i]+d->stride;
-        gmx_ana_pos_append(out->u.p, &d->g, &d->p2, i, refid);
-    }
-    gmx_ana_pos_append_finish(out->u.p);
-    return 0;
-}
-
-/*!
- * \param[in]  top   Not used.
- * \param[in]  fr    Not used.
- * \param[in]  pbc   Not used.
- * \param[in]  p     Positions to merge (should point to \p data->p1).
- * \param[out] out   Output data structure (\p out->u.p is used).
- * \param[in]  data  Should point to a \p t_methoddata_merge.
- * \returns    0 on success.
- */
-static int
-evaluate_plus(t_topology *top, t_trxframe *fr, t_pbc *pbc,
-              gmx_ana_pos_t *p, gmx_ana_selvalue_t *out, void *data)
-{
-    t_methoddata_merge *d = (t_methoddata_merge *)data;
-    int                 i;
-    int                 refid;
-
-    d->g.isize = 0;
-    gmx_ana_pos_empty(out->u.p);
-    for (i = 0; i < d->p1.nr; ++i)
-    {
-        refid = d->p1.m.refid[i];
-        gmx_ana_pos_append(out->u.p, &d->g, &d->p1, i, refid);
-    }
-    for (i = 0; i < d->p2.nr; ++i)
-    {
-        refid = d->p2.m.refid[i];
-        if (refid != -1)
-        {
-            refid += d->p1.m.b.nr;
-        }
-        gmx_ana_pos_append(out->u.p, &d->g, &d->p2, i, refid);
-    }
-    gmx_ana_pos_append_finish(out->u.p);
-    return 0;
-}
diff --git a/src/gmxlib/selection/sm_permute.c b/src/gmxlib/selection/sm_permute.c
deleted file mode 100644 (file)
index a318912..0000000
+++ /dev/null
@@ -1,267 +0,0 @@
-/*
- *
- *                This source code is part of
- *
- *                 G   R   O   M   A   C   S
- *
- *          GROningen MAchine for Chemical Simulations
- *
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
- * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
- * Copyright (c) 2001-2009, The GROMACS development team,
- * check out http://www.gromacs.org for more information.
-
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * If you want to redistribute modifications, please consider that
- * scientific software is very special. Version control is crucial -
- * bugs must be traceable. We will be happy to consider code for
- * inclusion in the official distribution, but derived work must not
- * be called official GROMACS. Details are found in the README & COPYING
- * files - if they are missing, get the official version at www.gromacs.org.
- *
- * To help us fund GROMACS development, we humbly ask that you cite
- * the papers on the package - you can find them in the top README file.
- *
- * For more info, check our website at http://www.gromacs.org
- */
-/*! \internal \file
- * \brief Implementation of the \p permute selection modifier.
- */
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <macros.h>
-#include <smalloc.h>
-#include <vec.h>
-
-#include <position.h>
-#include <selmethod.h>
-
-/*! \internal \brief
- * Data structure for the \p permute selection modifier.
- */
-typedef struct
-{
-    /** Positions to permute. */
-    gmx_ana_pos_t    p;
-    /** Group to receive the output permutation. */
-    gmx_ana_index_t  g;
-    /** Number of elements in the permutation. */
-    int              n;
-    /** Array describing the permutation. */
-    int             *perm;
-    /** Array that has the permutation reversed. */
-    int             *rperm;
-} t_methoddata_permute;
-
-/** Allocates data for the \p permute selection modifier. */
-static void *
-init_data_permute(int npar, gmx_ana_selparam_t *param);
-/** Initializes data for the \p permute selection modifier. */
-static int
-init_permute(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
-/** Initializes output for the \p permute selection modifier. */
-static int
-init_output_permute(t_topology *top, gmx_ana_selvalue_t *out, void *data);
-/** Frees the memory allocated for the \p permute selection modifier. */
-static void
-free_data_permute(void *data);
-/** Evaluates the \p permute selection modifier. */
-static int
-evaluate_permute(t_topology *top, t_trxframe *fr, t_pbc *pbc,
-                 gmx_ana_pos_t *p, gmx_ana_selvalue_t *out, void *data);
-
-/** Parameters for the \p permute selection modifier. */
-static gmx_ana_selparam_t smparams_permute[] = {
-    {NULL,       {POS_VALUE, -1, {NULL}}, NULL, SPAR_DYNAMIC | SPAR_VARNUM},
-    {NULL,       {INT_VALUE, -1, {NULL}}, NULL, SPAR_VARNUM},
-};
-
-/** Help text for the \p permute selection modifier. */
-static const char *help_permute[] = {
-    "PERMUTING SELECTIONS[PAR]",
-
-    "[TT]permute P1 ... PN[tt][PAR]",
-
-    "By default, all selections are evaluated such that the atom indices are",
-    "returned in ascending order. This can be changed by appending",
-    "[TT]permute P1 P2 ... PN[tt] to an expression.",
-    "The [TT]Pi[tt] should form a permutation of the numbers 1 to N.",
-    "This keyword permutes each N-position block in the selection such that",
-    "the i'th position in the block becomes Pi'th.",
-    "Note that it is the positions that are permuted, not individual atoms.",
-    "A fatal error occurs if the size of the selection is not a multiple of n.",
-    "It is only possible to permute the whole selection expression, not any",
-    "subexpressions, i.e., the [TT]permute[tt] keyword should appear last in",
-    "a selection.",
-};
-
-/** \internal Selection method data for the \p permute modifier. */
-gmx_ana_selmethod_t sm_permute = {
-    "permute", POS_VALUE, SMETH_MODIFIER,
-    asize(smparams_permute), smparams_permute,
-    &init_data_permute,
-    NULL,
-    &init_permute,
-    &init_output_permute,
-    &free_data_permute,
-    NULL,
-    NULL,
-    &evaluate_permute,
-    {"permute P1 ... PN", asize(help_permute), help_permute},
-};
-
-/*!
- * \param[in]     npar  Not used (should be 2).
- * \param[in,out] param Method parameters (should point to a copy of
- *   \ref smparams_permute).
- * \returns Pointer to the allocated data (\p t_methoddata_permute).
- *
- * Allocates memory for a \p t_methoddata_permute structure.
- */
-static void *
-init_data_permute(int npar, gmx_ana_selparam_t *param)
-{
-    t_methoddata_permute *data;
-
-    snew(data, 1);
-    param[0].val.u.p = &data->p;
-    return data;
-}
-
-/*!
- * \param[in] top   Not used.
- * \param[in] npar  Not used (should be 2).
- * \param[in] param Method parameters (should point to \ref smparams_permute).
- * \param[in] data  Should point to a \p t_methoddata_permute.
- * \returns   0 if the input permutation is valid, -1 on error.
- */
-static int
-init_permute(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data)
-{
-    t_methoddata_permute *d = (t_methoddata_permute *)data;
-    int                   i;
-
-    gmx_ana_index_reserve(&d->g, d->p.g->isize);
-    d->n    = param[1].val.nr;
-    d->perm = param[1].val.u.i;
-    if (d->p.nr % d->n != 0)
-    {
-        fprintf(stderr, "error: the number of positions to be permuted is not divisible by %d\n",
-                d->n);
-        return -1;
-    }
-    snew(d->rperm, d->n);
-    for (i = 0; i < d->n; ++i)
-    {
-        d->rperm[i] = -1;
-    }
-    for (i = 0; i < d->n; ++i)
-    {
-        d->perm[i]--;
-        if (d->perm[i] < 0 || d->perm[i] >= d->n)
-        {
-            fprintf(stderr, "invalid permutation");
-            return -1;
-        }
-        if (d->rperm[d->perm[i]] >= 0)
-        {
-            fprintf(stderr, "invalid permutation");
-            return -1;
-        }
-        d->rperm[d->perm[i]] = i;
-    }
-    return 0;
-}
-
-/*!
- * \param[in]     top   Topology data structure.
- * \param[in,out] out   Pointer to output data structure.
- * \param[in,out] data  Should point to \c t_methoddata_permute.
- * \returns       0 for success.
- */
-static int
-init_output_permute(t_topology *top, gmx_ana_selvalue_t *out, void *data)
-{
-    t_methoddata_permute *d = (t_methoddata_permute *)data;
-    int                   i, j, b, k;
-
-    gmx_ana_pos_copy(out->u.p, &d->p, TRUE);
-    gmx_ana_pos_set_evalgrp(out->u.p, &d->g);
-    d->g.isize = 0;
-    gmx_ana_pos_empty_init(out->u.p);
-    for (i = 0; i < d->p.nr; i += d->n)
-    {
-        for (j = 0; j < d->n; ++j)
-        {
-            b = i + d->rperm[j];
-            gmx_ana_pos_append_init(out->u.p, &d->g, &d->p, b);
-        }
-    }
-    return 0;
-}
-
-/*!
- * \param data Data to free (should point to a \p t_methoddata_permute).
- *
- * Frees the memory allocated for \c t_methoddata_permute.
- */
-static void
-free_data_permute(void *data)
-{
-    t_methoddata_permute *d = (t_methoddata_permute *)data;
-
-    gmx_ana_index_deinit(&d->g);
-    sfree(d->rperm);
-}
-
-/*!
- * \param[in]  top   Not used.
- * \param[in]  fr    Not used.
- * \param[in]  pbc   Not used.
- * \param[in]  p     Positions to permute (should point to \p data->p).
- * \param[out] out   Output data structure (\p out->u.p is used).
- * \param[in]  data  Should point to a \p t_methoddata_permute.
- * \returns    0 if \p p could be permuted, -1 on error.
- *
- * Returns -1 if the size of \p p is not divisible by the number of
- * elements in the permutation.
- */
-static int
-evaluate_permute(t_topology *top, t_trxframe *fr, t_pbc *pbc,
-                 gmx_ana_pos_t *p, gmx_ana_selvalue_t *out, void *data)
-{
-    t_methoddata_permute *d = (t_methoddata_permute *)data;
-    int                   i, j, b, k;
-    int                   refid;
-
-    if (d->p.nr % d->n != 0)
-    {
-        fprintf(stderr, "error: the number of positions to be permuted is not divisible by %d\n",
-                d->n);
-        return -1;
-    }
-    d->g.isize = 0;
-    gmx_ana_pos_empty(out->u.p);
-    for (i = 0; i < d->p.nr; i += d->n)
-    {
-        for (j = 0; j < d->n; ++j)
-        {
-            b = i + d->rperm[j];
-            refid = d->p.m.refid[b];
-            if (refid != -1)
-            {
-                /* De-permute the reference ID */
-                refid = refid - (refid % d->n) + d->perm[refid % d->n];
-            }
-            gmx_ana_pos_append(out->u.p, &d->g, p, b, refid);
-        }
-    }
-    gmx_ana_pos_append_finish(out->u.p);
-    return 0;
-}
diff --git a/src/gmxlib/selection/sm_position.c b/src/gmxlib/selection/sm_position.c
deleted file mode 100644 (file)
index 6a3ae6a..0000000
+++ /dev/null
@@ -1,373 +0,0 @@
-/*
- *
- *                This source code is part of
- *
- *                 G   R   O   M   A   C   S
- *
- *          GROningen MAchine for Chemical Simulations
- *
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
- * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
- * Copyright (c) 2001-2009, The GROMACS development team,
- * check out http://www.gromacs.org for more information.
-
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * If you want to redistribute modifications, please consider that
- * scientific software is very special. Version control is crucial -
- * bugs must be traceable. We will be happy to consider code for
- * inclusion in the official distribution, but derived work must not
- * be called official GROMACS. Details are found in the README & COPYING
- * files - if they are missing, get the official version at www.gromacs.org.
- *
- * To help us fund GROMACS development, we humbly ask that you cite
- * the papers on the package - you can find them in the top README file.
- *
- * For more info, check our website at http://www.gromacs.org
- */
-/*! \internal \file
- * \brief Implementation of position evaluation selection methods.
- */
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <macros.h>
-#include <smalloc.h>
-#include <string2.h>
-
-#include <indexutil.h>
-#include <poscalc.h>
-#include <position.h>
-#include <selmethod.h>
-
-#include "keywords.h"
-#include "selelem.h"
-
-/*! \internal \brief
- * Data structure for position keyword evaluation.
- */
-typedef struct
-{
-    /** Position calculation collection to use. */
-    gmx_ana_poscalc_coll_t *pcc;
-    /** Index group for which the center should be evaluated. */
-    gmx_ana_index_t    g;
-    /** Position evaluation data structure. */
-    gmx_ana_poscalc_t *pc;
-    /** TRUE if periodic boundary conditions should be used. */
-    gmx_bool               bPBC;
-    /** Type of positions to calculate. */
-    char              *type;
-    /** Flags for the position calculation. */
-    int                flags;
-} t_methoddata_pos;
-
-/** Allocates data for position evaluation selection methods. */
-static void *
-init_data_pos(int npar, gmx_ana_selparam_t *param);
-/** Sets the position calculation collection for position evaluation selection methods. */
-static void
-set_poscoll_pos(gmx_ana_poscalc_coll_t *pcc, void *data);
-/** Initializes position evaluation keywords. */
-static int
-init_kwpos(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
-/** Initializes the \p cog selection method. */
-static int
-init_cog(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
-/** Initializes the \p cog selection method. */
-static int
-init_com(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
-/** Initializes output for position evaluation selection methods. */
-static int
-init_output_pos(t_topology *top, gmx_ana_selvalue_t *out, void *data);
-/** Frees the data allocated for position evaluation selection methods. */
-static void
-free_data_pos(void *data);
-/** Evaluates position evaluation selection methods. */
-static int
-evaluate_pos(t_topology *top, t_trxframe *fr, t_pbc *pbc,
-             gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
-
-/** Parameters for position keyword evaluation. */
-static gmx_ana_selparam_t smparams_keyword_pos[] = {
-    {NULL,   {GROUP_VALUE, 1, {NULL}}, NULL, SPAR_DYNAMIC},
-};
-
-/** Parameters for the \p cog and \p com selection methods. */
-static gmx_ana_selparam_t smparams_com[] = {
-    {"of",   {GROUP_VALUE, 1, {NULL}}, NULL, SPAR_DYNAMIC},
-    {"pbc",  {NO_VALUE,    0, {NULL}}, NULL, 0},
-};
-
-/** \internal Selection method data for position keyword evaluation. */
-gmx_ana_selmethod_t sm_keyword_pos = {
-    "kw_pos", POS_VALUE, SMETH_DYNAMIC | SMETH_VARNUMVAL,
-    asize(smparams_keyword_pos), smparams_keyword_pos,
-    &init_data_pos,
-    &set_poscoll_pos,
-    &init_kwpos,
-    &init_output_pos,
-    &free_data_pos,
-     NULL,
-    &evaluate_pos,
-     NULL,
-    {NULL, 0, NULL},
-};
-
-/** \internal Selection method data for the \p cog method. */
-gmx_ana_selmethod_t sm_cog = {
-    "cog", POS_VALUE, SMETH_DYNAMIC | SMETH_SINGLEVAL,
-    asize(smparams_com), smparams_com,
-    &init_data_pos,
-    &set_poscoll_pos,
-    &init_cog,
-    &init_output_pos,
-    &free_data_pos,
-     NULL,
-    &evaluate_pos,
-     NULL,
-    {"cog of ATOM_EXPR [pbc]", 0, NULL},
-};
-
-/** \internal Selection method data for the \p com method. */
-gmx_ana_selmethod_t sm_com = {
-    "com", POS_VALUE, SMETH_REQTOP | SMETH_DYNAMIC | SMETH_SINGLEVAL,
-    asize(smparams_com), smparams_com,
-    &init_data_pos,
-    &set_poscoll_pos,
-    &init_com,
-    &init_output_pos,
-    &free_data_pos,
-     NULL,
-    &evaluate_pos,
-     NULL,
-    {"com of ATOM_EXPR [pbc]", 0, NULL},
-};
-
-/*!
- * \param[in]     npar  Should be 1 or 2.
- * \param[in,out] param Method parameters (should point to
- *   \ref smparams_keyword_pos or \ref smparams_com).
- * \returns       Pointer to the allocated data (\c t_methoddata_pos).
- *
- * Allocates memory for a \c t_methoddata_pos structure and initializes
- * the first parameter to define the value for \c t_methoddata_pos::g.
- * If a second parameter is present, it is used for setting the
- * \c t_methoddata_pos::bPBC flag.
- */
-static void *
-init_data_pos(int npar, gmx_ana_selparam_t *param)
-{
-    t_methoddata_pos *data;
-
-    snew(data, 1);
-    param[0].val.u.g = &data->g;
-    if (npar > 1)
-    {
-        param[1].val.u.b = &data->bPBC;
-    }
-    data->pc       = NULL;
-    data->bPBC     = FALSE;
-    data->type     = NULL;
-    data->flags    = -1;
-    return data;
-}
-
-/*!
- * \param[in]     pcc   Position calculation collection to use.
- * \param[in,out] data  Should point to \c t_methoddata_pos.
- */
-static void
-set_poscoll_pos(gmx_ana_poscalc_coll_t *pcc, void *data)
-{
-    ((t_methoddata_pos *)data)->pcc = pcc;
-}
-
-/*!
- * \param[in,out] sel   Selection element to initialize.
- * \param[in]     type  One of the enum values acceptable for
- *   gmx_ana_poscalc_type_from_enum().
- *
- * Initializes the reference position type for position evaluation.
- * If called multiple times, the first setting takes effect, and later calls
- * are neglected.
- */
-void
-_gmx_selelem_set_kwpos_type(t_selelem *sel, const char *type)
-{
-    t_methoddata_pos *d = (t_methoddata_pos *)sel->u.expr.mdata;
-
-    if (sel->type != SEL_EXPRESSION || !sel->u.expr.method
-        || sel->u.expr.method->name != sm_keyword_pos.name)
-    {
-        return;
-    }
-    if (!d->type && type)
-    {
-        d->type  = strdup(type);
-        /* FIXME: It would be better not to have the string here hardcoded. */
-        if (type[0] != 'a')
-        {
-            sel->u.expr.method->flags |= SMETH_REQTOP;
-        }
-    }
-}
-
-/*!
- * \param[in,out] sel   Selection element to initialize.
- * \param[in]     flags Default completion flags
- *   (see gmx_ana_poscalc_type_from_enum()).
- *
- * Initializes the flags for position evaluation.
- * If called multiple times, the first setting takes effect, and later calls
- * are neglected.
- */
-void
-_gmx_selelem_set_kwpos_flags(t_selelem *sel, int flags)
-{
-    t_methoddata_pos *d = (t_methoddata_pos *)sel->u.expr.mdata;
-
-    if (sel->type != SEL_EXPRESSION || !sel->u.expr.method
-        || sel->u.expr.method->name != sm_keyword_pos.name)
-    {
-        return;
-    }
-    if (d->flags == -1)
-    {
-        d->flags = flags;
-    }
-}
-
-/*!
- * \param[in] top   Not used.
- * \param[in] npar  Not used.
- * \param[in] param Not used.
- * \param[in,out] data  Should point to \c t_methoddata_pos.
- * \returns       0 on success, a non-zero error code on error.
- *
- * The \c t_methoddata_pos::type field should have been initialized
- * externally using _gmx_selelem_set_kwpos_type().
- */
-static int
-init_kwpos(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data)
-{
-    t_methoddata_pos *d = (t_methoddata_pos *)data;
-    int               rc;
-
-    if (!(param[0].flags & SPAR_DYNAMIC))
-    {
-        d->flags &= ~(POS_DYNAMIC | POS_MASKONLY);
-    }
-    else if (!(d->flags & POS_MASKONLY))
-    {
-        d->flags |= POS_DYNAMIC;
-    }
-    rc = gmx_ana_poscalc_create_enum(&d->pc, d->pcc, d->type, d->flags);
-    if (rc != 0)
-    {
-        return rc;
-    }
-    gmx_ana_poscalc_set_maxindex(d->pc, &d->g);
-    return 0;
-}
-
-/*!
- * \param[in]     top   Topology data structure.
- * \param[in]     npar  Not used.
- * \param[in]     param Not used.
- * \param[in,out] data  Should point to \c t_methoddata_pos.
- * \returns       0 on success, a non-zero error code on error.
- */
-static int
-init_cog(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data)
-{
-    t_methoddata_pos *d = (t_methoddata_pos *)data;
-    int               rc;
-
-    d->flags = (param[0].flags & SPAR_DYNAMIC) ? POS_DYNAMIC : 0;
-    rc = gmx_ana_poscalc_create(&d->pc, d->pcc, d->bPBC ? POS_ALL_PBC : POS_ALL,
-                                d->flags);
-    if (rc != 0)
-    {
-        return rc;
-    }
-    gmx_ana_poscalc_set_maxindex(d->pc, &d->g);
-    return 0;
-}
-
-/*!
- * \param[in]     top   Topology data structure.
- * \param[in]     npar  Not used.
- * \param[in]     param Not used.
- * \param[in,out] data  Should point to \c t_methoddata_pos.
- * \returns       0 on success, a non-zero error code on error.
- */
-static int
-init_com(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data)
-{
-    t_methoddata_pos *d = (t_methoddata_pos *)data;
-    int               rc;
-
-    d->flags  = (param[0].flags & SPAR_DYNAMIC) ? POS_DYNAMIC : 0;
-    d->flags |= POS_MASS;
-    rc = gmx_ana_poscalc_create(&d->pc, d->pcc, d->bPBC ? POS_ALL_PBC : POS_ALL,
-                                d->flags);
-    if (rc != 0)
-    {
-        return rc;
-    }
-    gmx_ana_poscalc_set_maxindex(d->pc, &d->g);
-    return 0;
-}
-
-/*!
- * \param[in]     top   Topology data structure.
- * \param[in,out] out   Pointer to output data structure.
- * \param[in,out] data  Should point to \c t_methoddata_pos.
- * \returns       0 for success.
- */
-static int
-init_output_pos(t_topology *top, gmx_ana_selvalue_t *out, void *data)
-{
-    t_methoddata_pos *d = (t_methoddata_pos *)data;
-
-    gmx_ana_poscalc_init_pos(d->pc, out->u.p);
-    gmx_ana_pos_set_evalgrp(out->u.p, &d->g);
-    return 0;
-}
-
-/*!
- * \param data Data to free (should point to a \c t_methoddata_pos).
- *
- * Frees the memory allocated for \c t_methoddata_pos::g and
- * \c t_methoddata_pos::pc.
- */
-static void
-free_data_pos(void *data)
-{
-    t_methoddata_pos *d = (t_methoddata_pos *)data;
-
-    sfree(d->type);
-    gmx_ana_poscalc_free(d->pc);
-}
-
-/*!
- * See sel_updatefunc() for description of the parameters.
- * \p data should point to a \c t_methoddata_pos.
- *
- * Calculates the positions using \c t_methoddata_pos::pc for the index group
- * in \c t_methoddata_pos::g and stores the results in \p out->u.p.
- */
-static int
-evaluate_pos(t_topology *top, t_trxframe *fr, t_pbc *pbc,
-             gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
-{
-    t_methoddata_pos *d = (t_methoddata_pos *)data;
-
-    gmx_ana_poscalc_update(d->pc, out->u.p, &d->g, fr, pbc);
-    return 0;
-}
diff --git a/src/gmxlib/selection/sm_same.c b/src/gmxlib/selection/sm_same.c
deleted file mode 100644 (file)
index d50221e..0000000
+++ /dev/null
@@ -1,529 +0,0 @@
-/*
- *
- *                This source code is part of
- *
- *                 G   R   O   M   A   C   S
- *
- *          GROningen MAchine for Chemical Simulations
- *
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
- * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
- * Copyright (c) 2001-2009, The GROMACS development team,
- * check out http://www.gromacs.org for more information.
-
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * If you want to redistribute modifications, please consider that
- * scientific software is very special. Version control is crucial -
- * bugs must be traceable. We will be happy to consider code for
- * inclusion in the official distribution, but derived work must not
- * be called official GROMACS. Details are found in the README & COPYING
- * files - if they are missing, get the official version at www.gromacs.org.
- *
- * To help us fund GROMACS development, we humbly ask that you cite
- * the papers on the package - you can find them in the top README file.
- *
- * For more info, check our website at http://www.gromacs.org
- */
-/*! \internal \file
- * \brief Implementation of the \p same selection method.
- */
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdlib.h>
-
-#include <macros.h>
-#include <smalloc.h>
-#include <string2.h>
-
-#include <selmethod.h>
-
-#include "keywords.h"
-#include "parsetree.h"
-#include "selelem.h"
-
-/*! \internal \brief
- * Data structure for the \p same selection method.
- *
- * To avoid duplicate initialization code, the same data structure is used
- * for matching both integer and string keywords; hence the unions.
- */
-typedef struct
-{
-    /** Value for each atom to match. */
-    union
-    {
-        int                 *i;
-        char               **s;
-        void                *ptr;
-    }                        val;
-    /*! \brief
-     * Number of values in the \p as array.
-     *
-     * For string values, this is actually the number of values in the
-     * \p as_s_sorted array.
-     */
-    int                      nas;
-    /** Values to match against. */
-    union
-    {
-        int                 *i;
-        char               **s;
-        void                *ptr;
-    }                        as;
-    /*! \brief
-     * Separate array for sorted \p as.s array.
-     *
-     * The array of strings returned as the output value of a parameter should
-     * not be messed with to avoid memory corruption (the pointers in the array
-     * may be reused for several evaluations), so we keep our own copy for
-     * modifications.
-     */
-    char                   **as_s_sorted;
-    /** Whether simple matching can be used. */
-    gmx_bool                     bSorted;
-} t_methoddata_same;
-
-/** Allocates data for the \p same selection method. */
-static void *
-init_data_same(int npar, gmx_ana_selparam_t *param);
-/** Initializes the \p same selection method. */
-static int
-init_same(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
-/** Frees the data allocated for the \p same selection method. */
-static void
-free_data_same(void *data);
-/** Initializes the evaluation of the \p same selection method for a frame. */
-static int
-init_frame_same_int(t_topology *top, t_trxframe *fr, t_pbc *pbc, void *data);
-/** Evaluates the \p same selection method. */
-static int
-evaluate_same_int(t_topology *top, t_trxframe *fr, t_pbc *pbc,
-                  gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
-/** Initializes the evaluation of the \p same selection method for a frame. */
-static int
-init_frame_same_str(t_topology *top, t_trxframe *fr, t_pbc *pbc, void *data);
-/** Evaluates the \p same selection method. */
-static int
-evaluate_same_str(t_topology *top, t_trxframe *fr, t_pbc *pbc,
-                 gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
-
-/** Parameters for the \p same selection method. */
-static gmx_ana_selparam_t smparams_same_int[] = {
-    {NULL, {INT_VALUE, -1, {NULL}}, NULL, SPAR_DYNAMIC | SPAR_ATOMVAL},
-    {"as", {INT_VALUE, -1, {NULL}}, NULL, SPAR_DYNAMIC | SPAR_VARNUM},
-};
-
-/** Parameters for the \p same selection method. */
-static gmx_ana_selparam_t smparams_same_str[] = {
-    {NULL, {STR_VALUE, -1, {NULL}}, NULL, SPAR_DYNAMIC | SPAR_ATOMVAL},
-    {"as", {STR_VALUE, -1, {NULL}}, NULL, SPAR_DYNAMIC | SPAR_VARNUM},
-};
-
-/** Help text for the \p same selection method. */
-static const char *help_same[] = {
-    "EXTENDING SELECTIONS[PAR]",
-
-    "[TT]same KEYWORD as ATOM_EXPR[tt][PAR]",
-
-    "The keyword [TT]same[tt] can be used to select all atoms for which",
-    "the given [TT]KEYWORD[tt] matches any of the atoms in [TT]ATOM_EXPR[tt].",
-    "Keywords that evaluate to integer or string values are supported.",
-};
-
-/*! \internal \brief Selection method data for the \p same method. */
-gmx_ana_selmethod_t sm_same = {
-    "same", GROUP_VALUE, 0,
-    asize(smparams_same_int), smparams_same_int,
-    &init_data_same,
-    NULL,
-    &init_same,
-    NULL,
-    &free_data_same,
-    &init_frame_same_int,
-    &evaluate_same_int,
-    NULL,
-    {"same KEYWORD as ATOM_EXPR", asize(help_same), help_same},
-};
-
-/*! \brief
- * Selection method data for the \p same method.
- *
- * This selection method is used for matching string keywords. The parser
- * never sees this method; _gmx_selelem_custom_init_same() replaces sm_same
- * with this method in cases where it is required.
- */
-static gmx_ana_selmethod_t sm_same_str = {
-    "same", GROUP_VALUE, SMETH_SINGLEVAL,
-    asize(smparams_same_str), smparams_same_str,
-    &init_data_same,
-    NULL,
-    &init_same,
-    NULL,
-    &free_data_same,
-    &init_frame_same_str,
-    &evaluate_same_str,
-    NULL,
-    {"same KEYWORD as ATOM_EXPR", asize(help_same), help_same},
-};
-
-/*!
- * \param[in]     npar  Not used (should be 2).
- * \param[in,out] param Method parameters (should point to 
- *   \ref smparams_same).
- * \returns Pointer to the allocated data (\ref t_methoddata_same).
- */
-static void *
-init_data_same(int npar, gmx_ana_selparam_t *param)
-{
-    t_methoddata_same *data;
-
-    snew(data, 1);
-    data->as_s_sorted = NULL;
-    param[1].nvalptr = &data->nas;
-    return data;
-}
-
-/*!
- * \param[in,out] method  The method to initialize.
- * \param[in,out] params  Pointer to the first parameter.
- * \param[in]     scanner Scanner data structure.
- * \returns       0 on success, a non-zero error code on error.
- *
- * If \p *method is not a \c same method, this function returns zero
- * immediately.
- */
-int
-_gmx_selelem_custom_init_same(gmx_ana_selmethod_t **method,
-                              t_selexpr_param *params,
-                              void *scanner)
-{
-    gmx_ana_selmethod_t *kwmethod;
-    t_selelem           *kwelem;
-    t_selexpr_param     *param;
-    char                *pname;
-    int                  rc;
-
-    /* Do nothing if this is not a same method. */
-    if (!*method || (*method)->name != sm_same.name)
-    {
-        return 0;
-    }
-
-    if (params->nval != 1 || !params->value->bExpr
-        || params->value->u.expr->type != SEL_EXPRESSION)
-    {
-        _gmx_selparser_error("error: 'same' should be followed by a single keyword");
-        return -1;
-    }
-    kwmethod = params->value->u.expr->u.expr.method;
-
-    if (kwmethod->type == STR_VALUE)
-    {
-        *method = &sm_same_str;
-    }
-
-    /* We do custom processing with the second parameter, so remove it from
-     * the params list, but save the name for later. */
-    param        = params->next;
-    params->next = NULL;
-    pname        = param->name;
-    param->name  = NULL;
-    /* Create a second keyword evaluation element for the keyword given as
-     * the first parameter, evaluating the keyword in the group given by the
-     * second parameter. */
-    rc = _gmx_sel_init_keyword_evaluator(&kwelem, kwmethod, param, scanner);
-    if (rc != 0)
-    {
-        sfree(pname);
-        return rc;
-    }
-    /* Replace the second parameter with one with a value from \p kwelem. */
-    param        = _gmx_selexpr_create_param(pname);
-    param->nval  = 1;
-    param->value = _gmx_selexpr_create_value_expr(kwelem);
-    params->next = param;
-    return 0;
-}
-
-/*!
- * \param   top   Not used.
- * \param   npar  Not used (should be 2).
- * \param   param Initialized method parameters (should point to a copy of
- *      \ref smparams_same).
- * \param   data  Pointer to \ref t_methoddata_same to initialize.
- * \returns 0 on success, -1 on failure.
- */
-static int
-init_same(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data)
-{
-    t_methoddata_same *d = (t_methoddata_same *)data;
-
-    d->val.ptr = param[0].val.u.ptr;
-    d->as.ptr  = param[1].val.u.ptr;
-    if (param[1].val.type == STR_VALUE)
-    {
-        snew(d->as_s_sorted, d->nas);
-    }
-    if (!(param[0].flags & SPAR_ATOMVAL))
-    {
-        fprintf(stderr, "ERROR: the same selection keyword combined with a "
-                        "non-keyword does not make sense\n");
-        return -1;
-    }
-    return 0;
-}
-
-/*!
- * \param data Data to free (should point to a \ref t_methoddata_same).
- */
-static void
-free_data_same(void *data)
-{
-    t_methoddata_same *d = (t_methoddata_same *)data;
-
-    sfree(d->as_s_sorted);
-}
-
-/*! \brief
- * Helper function for comparison of two integers.
- */
-static int
-cmp_int(const void *a, const void *b)
-{
-    if (*(int *)a < *(int *)b)
-    {
-        return -1;
-    }
-    if (*(int *)a > *(int *)b)
-    {
-        return 1;
-    }
-    return 0;
-}
-
-/*!
- * \param[in]  top  Not used.
- * \param[in]  fr   Current frame.
- * \param[in]  pbc  PBC structure.
- * \param      data Should point to a \ref t_methoddata_same.
- * \returns    0 on success, a non-zero error code on error.
- *
- * Sorts the \c data->as.i array and removes identical values for faster and
- * simpler lookup.
- */
-static int
-init_frame_same_int(t_topology *top, t_trxframe *fr, t_pbc *pbc, void *data)
-{
-    t_methoddata_same *d = (t_methoddata_same *)data;
-    int                i, j;
-
-    /* Collapse adjacent values, and check whether the array is sorted. */
-    d->bSorted = TRUE;
-    for (i = 1, j = 0; i < d->nas; ++i)
-    {
-        if (d->as.i[i] != d->as.i[j])
-        {
-            if (d->as.i[i] < d->as.i[j])
-            {
-                d->bSorted = FALSE;
-            }
-            ++j;
-            d->as.i[j] = d->as.i[i];
-        }
-    }
-    d->nas = j + 1;
-
-    if (!d->bSorted)
-    {
-        qsort(d->as.i, d->nas, sizeof(d->as.i[0]), &cmp_int);
-        /* More identical values may become adjacent after sorting. */
-        for (i = 1, j = 0; i < d->nas; ++i)
-        {
-            if (d->as.i[i] != d->as.i[j])
-            {
-                ++j;
-                d->as.i[j] = d->as.i[i];
-            }
-        }
-        d->nas = j + 1;
-    }
-    return 0;
-}
-
-/*!
- * See sel_updatefunc() for description of the parameters.
- * \p data should point to a \c t_methoddata_same.
- *
- * Calculates which values in \c data->val.i can be found in \c data->as.i
- * (assumed sorted), and writes the corresponding atoms to output.
- * If \c data->val is sorted, uses a linear scan of both arrays, otherwise a
- * binary search of \c data->as is performed for each block of values in
- * \c data->val.
- */
-static int
-evaluate_same_int(t_topology *top, t_trxframe *fr, t_pbc *pbc,
-                  gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
-{
-    t_methoddata_same *d = (t_methoddata_same *)data;
-    int                    i, j;
-
-    out->u.g->isize = 0;
-    i = j = 0;
-    while (j < g->isize)
-    {
-        if (d->bSorted)
-        {
-            /* If we are sorted, we can do a simple linear scan. */
-            while (i < d->nas && d->as.i[i] < d->val.i[j]) ++i;
-        }
-        else
-        {
-            /* If not, we must do a binary search of all the values. */
-            int i1, i2;
-
-            i1 = 0;
-            i2 = d->nas;
-            while (i2 - i1 > 1)
-            {
-                int itry = (i1 + i2) / 2;
-                if (d->as.i[itry] <= d->val.i[j])
-                {
-                    i1 = itry;
-                }
-                else
-                {
-                    i2 = itry;
-                }
-            }
-            i = (d->as.i[i1] == d->val.i[j] ? i1 : d->nas);
-        }
-        /* Check whether the value was found in the as list. */
-        if (i == d->nas || d->as.i[i] != d->val.i[j])
-        {
-            /* If not, skip all atoms with the same value. */
-            int tmpval = d->val.i[j];
-            ++j;
-            while (j < g->isize && d->val.i[j] == tmpval) ++j;
-        }
-        else
-        {
-            /* Copy all the atoms with this value to the output. */
-            while (j < g->isize && d->val.i[j] == d->as.i[i])
-            {
-                out->u.g->index[out->u.g->isize++] = g->index[j];
-                ++j;
-            }
-        }
-        if (j < g->isize && d->val.i[j] < d->val.i[j - 1])
-        {
-            d->bSorted = FALSE;
-        }
-    }
-    return 0;
-}
-
-/*! \brief
- * Helper function for comparison of two strings.
- */
-static int
-cmp_str(const void *a, const void *b)
-{
-    return strcmp(*(char **)a, *(char **)b);
-}
-
-/*!
- * \param[in]  top  Not used.
- * \param[in]  fr   Current frame.
- * \param[in]  pbc  PBC structure.
- * \param      data Should point to a \ref t_methoddata_same.
- * \returns    0 on success, a non-zero error code on error.
- *
- * Sorts the \c data->as.s array and removes identical values for faster and
- * simpler lookup.
- */
-static int
-init_frame_same_str(t_topology *top, t_trxframe *fr, t_pbc *pbc, void *data)
-{
-    t_methoddata_same *d = (t_methoddata_same *)data;
-    int                i, j;
-
-    /* Collapse adjacent values.
-     * For strings, it's unlikely that the values would be sorted originally,
-     * so set bSorted always to FALSE. */
-    d->bSorted = FALSE;
-    d->as_s_sorted[0] = d->as.s[0];
-    for (i = 1, j = 0; i < d->nas; ++i)
-    {
-        if (strcmp(d->as.s[i], d->as_s_sorted[j]) != 0)
-        {
-            ++j;
-            d->as_s_sorted[j] = d->as.s[i];
-        }
-    }
-    d->nas = j + 1;
-
-    qsort(d->as_s_sorted, d->nas, sizeof(d->as_s_sorted[0]), &cmp_str);
-    /* More identical values may become adjacent after sorting. */
-    for (i = 1, j = 0; i < d->nas; ++i)
-    {
-        if (strcmp(d->as_s_sorted[i], d->as_s_sorted[j]) != 0)
-        {
-            ++j;
-            d->as_s_sorted[j] = d->as_s_sorted[i];
-        }
-    }
-    d->nas = j + 1;
-    return 0;
-}
-
-/*!
- * See sel_updatefunc() for description of the parameters.
- * \p data should point to a \c t_methoddata_same.
- *
- * Calculates which strings in \c data->val.s can be found in \c data->as.s
- * (assumed sorted), and writes the corresponding atoms to output.
- * A binary search of \c data->as is performed for each block of values in
- * \c data->val.
- */
-static int
-evaluate_same_str(t_topology *top, t_trxframe *fr, t_pbc *pbc,
-                  gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
-{
-    t_methoddata_same *d = (t_methoddata_same *)data;
-    int                    i, j;
-
-    out->u.g->isize = 0;
-    j = 0;
-    while (j < g->isize)
-    {
-        /* Do a binary search of the strings. */
-        void *ptr;
-        ptr = bsearch(&d->val.s[j], d->as_s_sorted, d->nas,
-                      sizeof(d->as_s_sorted[0]), &cmp_str);
-        /* Check whether the value was found in the as list. */
-        if (ptr == NULL)
-        {
-            /* If not, skip all atoms with the same value. */
-            const char *tmpval = d->val.s[j];
-            ++j;
-            while (j < g->isize && strcmp(d->val.s[j], tmpval) == 0) ++j;
-        }
-        else
-        {
-            const char *tmpval = d->val.s[j];
-            /* Copy all the atoms with this value to the output. */
-            while (j < g->isize && strcmp(d->val.s[j], tmpval) == 0)
-            {
-                out->u.g->index[out->u.g->isize++] = g->index[j];
-                ++j;
-            }
-        }
-    }
-    return 0;
-}
diff --git a/src/gmxlib/selection/sm_simple.c b/src/gmxlib/selection/sm_simple.c
deleted file mode 100644 (file)
index 1810b12..0000000
+++ /dev/null
@@ -1,866 +0,0 @@
-/*
- *
- *                This source code is part of
- *
- *                 G   R   O   M   A   C   S
- *
- *          GROningen MAchine for Chemical Simulations
- *
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
- * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
- * Copyright (c) 2001-2009, The GROMACS development team,
- * check out http://www.gromacs.org for more information.
-
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * If you want to redistribute modifications, please consider that
- * scientific software is very special. Version control is crucial -
- * bugs must be traceable. We will be happy to consider code for
- * inclusion in the official distribution, but derived work must not
- * be called official GROMACS. Details are found in the README & COPYING
- * files - if they are missing, get the official version at www.gromacs.org.
- *
- * To help us fund GROMACS development, we humbly ask that you cite
- * the papers on the package - you can find them in the top README file.
- *
- * For more info, check our website at http://www.gromacs.org
- */
-/*! \internal \file
- * \brief Implementations of simple keyword selection methods.
- */
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <position.h>
-#include <selmethod.h>
-
-/** Evaluates the \p all selection keyword. */
-static int
-evaluate_all(t_topology *top, t_trxframe *fr, t_pbc *pbc,
-             gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
-/** Evaluates the \p none selection keyword. */
-static int
-evaluate_none(t_topology *top, t_trxframe *fr, t_pbc *pbc,
-              gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
-/** Evaluates the \p atomnr selection keyword. */
-static int
-evaluate_atomnr(t_topology *top, t_trxframe *fr, t_pbc *pbc,
-                gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
-/** Evaluates the \p resnr selection keyword. */
-static int
-evaluate_resnr(t_topology *top, t_trxframe *fr, t_pbc *pbc,
-               gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
-/** Evaluates the \p resindex selection keyword. */
-static int
-evaluate_resindex(t_topology *top, t_trxframe *fr, t_pbc *pbc,
-                  gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
-/** Checks whether molecule information is present in the topology. */
-static int
-check_molecules(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
-/** Evaluates the \p molindex selection keyword. */
-static int
-evaluate_molindex(t_topology *top, t_trxframe *fr, t_pbc *pbc,
-                  gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
-/** Evaluates the \p name selection keyword. */
-static int
-evaluate_atomname(t_topology *top, t_trxframe *fr, t_pbc *pbc,
-                  gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
-/** Checks whether atom types are present in the topology. */
-static int
-check_atomtype(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
-/** Evaluates the \p type selection keyword. */
-static int
-evaluate_atomtype(t_topology *top, t_trxframe *fr, t_pbc *pbc,
-                  gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
-/** Evaluates the \p insertcode selection keyword. */
-static int
-evaluate_insertcode(t_topology *top, t_trxframe *fr, t_pbc *pbc,
-                    gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
-/** Evaluates the \p chain selection keyword. */
-static int
-evaluate_chain(t_topology *top, t_trxframe *fr, t_pbc *pbc,
-               gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
-/** Evaluates the \p mass selection keyword. */
-static int
-evaluate_mass(t_topology *top, t_trxframe *fr, t_pbc *pbc,
-              gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
-/** Evaluates the \p charge selection keyword. */
-static int
-evaluate_charge(t_topology *top, t_trxframe *fr, t_pbc *pbc,
-                gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
-/** Checks whether PDB info is present in the topology. */
-static int
-check_pdbinfo(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
-/** Evaluates the \p altloc selection keyword. */
-static int
-evaluate_altloc(t_topology *top, t_trxframe *fr, t_pbc *pbc,
-                gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
-/** Evaluates the \p occupancy selection keyword. */
-static int
-evaluate_occupancy(t_topology *top, t_trxframe *fr, t_pbc *pbc,
-                   gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
-/** Evaluates the \p betafactor selection keyword. */
-static int
-evaluate_betafactor(t_topology *top, t_trxframe *fr, t_pbc *pbc,
-                    gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
-/** Evaluates the \p resname selection keyword. */
-static int
-evaluate_resname(t_topology *top, t_trxframe *fr, t_pbc *pbc,
-                 gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
-
-/** Evaluates the \p x selection keyword. */
-static int
-evaluate_x(t_topology *top, t_trxframe *fr, t_pbc *pbc,
-           gmx_ana_pos_t *pos, gmx_ana_selvalue_t *out, void *data);
-/** Evaluates the \p y selection keyword. */
-static int
-evaluate_y(t_topology *top, t_trxframe *fr, t_pbc *pbc,
-           gmx_ana_pos_t *pos, gmx_ana_selvalue_t *out, void *data);
-/** Evaluates the \p z selection keyword. */
-static int
-evaluate_z(t_topology *top, t_trxframe *fr, t_pbc *pbc,
-           gmx_ana_pos_t *pos, gmx_ana_selvalue_t *out, void *data);
-
-/** \internal Selection method data for \p all selection keyword. */
-gmx_ana_selmethod_t sm_all = {
-    "all", GROUP_VALUE, 0,
-    0, NULL,
-    NULL,
-    NULL,
-    NULL,
-    NULL,
-    NULL,
-    NULL,
-    &evaluate_all,
-    NULL,
-};
-
-/** \internal Selection method data for \p none selection keyword. */
-gmx_ana_selmethod_t sm_none = {
-    "none", GROUP_VALUE, 0,
-    0, NULL,
-    NULL,
-    NULL,
-    NULL,
-    NULL,
-    NULL,
-    NULL,
-    &evaluate_none,
-    NULL,
-};
-
-/** \internal Selection method data for \p atomnr selection keyword. */
-gmx_ana_selmethod_t sm_atomnr = {
-    "atomnr", INT_VALUE, 0,
-    0, NULL,
-    NULL,
-    NULL,
-    NULL,
-    NULL,
-    NULL,
-    NULL,
-    &evaluate_atomnr,
-    NULL,
-};
-
-/** \internal Selection method data for \p resnr selection keyword. */
-gmx_ana_selmethod_t sm_resnr = {
-    "resnr", INT_VALUE, SMETH_REQTOP,
-    0, NULL,
-    NULL,
-    NULL,
-    NULL,
-    NULL,
-    NULL,
-    NULL,
-    &evaluate_resnr,
-    NULL,
-};
-
-/** \internal Selection method data for \p resindex selection keyword. */
-gmx_ana_selmethod_t sm_resindex = {
-    "resindex", INT_VALUE, SMETH_REQTOP,
-    0, NULL,
-    NULL,
-    NULL,
-    NULL,
-    NULL,
-    NULL,
-    NULL,
-    &evaluate_resindex,
-    NULL,
-};
-
-/** \internal Selection method data for \p molindex selection keyword. */
-gmx_ana_selmethod_t sm_molindex = {
-    "molindex", INT_VALUE, SMETH_REQTOP,
-    0, NULL,
-    NULL,
-    NULL,
-    &check_molecules,
-    NULL,
-    NULL,
-    NULL,
-    &evaluate_molindex,
-    NULL,
-};
-
-/** \internal Selection method data for \p name selection keyword. */
-gmx_ana_selmethod_t sm_atomname = {
-    "name", STR_VALUE, SMETH_REQTOP,
-    0, NULL,
-    NULL,
-    NULL,
-    NULL,
-    NULL,
-    NULL,
-    NULL,
-    &evaluate_atomname,
-    NULL,
-};
-
-/** \internal Selection method data for \p type selection keyword. */
-gmx_ana_selmethod_t sm_atomtype = {
-    "type", STR_VALUE, SMETH_REQTOP,
-    0, NULL,
-    NULL,
-    NULL,
-    &check_atomtype,
-    NULL,
-    NULL,
-    NULL,
-    &evaluate_atomtype,
-    NULL,
-};
-
-/** \internal Selection method data for \p resname selection keyword. */
-gmx_ana_selmethod_t sm_resname = {
-    "resname", STR_VALUE, SMETH_REQTOP,
-    0, NULL,
-    NULL,
-    NULL,
-    NULL,
-    NULL,
-    NULL,
-    NULL,
-    &evaluate_resname,
-    NULL,
-};
-
-/** \internal Selection method data for \p chain selection keyword. */
-gmx_ana_selmethod_t sm_insertcode = {
-    "insertcode", STR_VALUE, SMETH_REQTOP | SMETH_CHARVAL,
-    0, NULL,
-    NULL,
-    NULL,
-    NULL,
-    NULL,
-    NULL,
-    NULL,
-    &evaluate_insertcode,
-    NULL,
-};
-
-/** \internal Selection method data for \p chain selection keyword. */
-gmx_ana_selmethod_t sm_chain = {
-    "chain", STR_VALUE, SMETH_REQTOP | SMETH_CHARVAL,
-    0, NULL,
-    NULL,
-    NULL,
-    NULL,
-    NULL,
-    NULL,
-    NULL,
-    &evaluate_chain,
-    NULL,
-};
-
-/** \internal Selection method data for \p mass selection keyword. */
-gmx_ana_selmethod_t sm_mass = {
-    "mass", REAL_VALUE, SMETH_REQTOP,
-    0, NULL,
-    NULL,
-    NULL,
-    NULL,
-    NULL,
-    NULL,
-    NULL,
-    &evaluate_mass,
-    NULL,
-};
-
-/** \internal Selection method data for \p charge selection keyword. */
-gmx_ana_selmethod_t sm_charge = {
-    "charge", REAL_VALUE, SMETH_REQTOP,
-    0, NULL,
-    NULL,
-    NULL,
-    NULL,
-    NULL,
-    NULL,
-    NULL,
-    &evaluate_charge,
-    NULL,
-};
-
-/** \internal Selection method data for \p chain selection keyword. */
-gmx_ana_selmethod_t sm_altloc = {
-    "altloc", STR_VALUE, SMETH_REQTOP | SMETH_CHARVAL,
-    0, NULL,
-    NULL,
-    NULL,
-    &check_pdbinfo,
-    NULL,
-    NULL,
-    NULL,
-    &evaluate_altloc,
-    NULL,
-};
-
-/** \internal Selection method data for \p occupancy selection keyword. */
-gmx_ana_selmethod_t sm_occupancy = {
-    "occupancy", REAL_VALUE, SMETH_REQTOP,
-    0, NULL,
-    NULL,
-    NULL,
-    &check_pdbinfo,
-    NULL,
-    NULL,
-    NULL,
-    &evaluate_occupancy,
-    NULL,
-};
-
-/** \internal Selection method data for \p betafactor selection keyword. */
-gmx_ana_selmethod_t sm_betafactor = {
-    "betafactor", REAL_VALUE, SMETH_REQTOP,
-    0, NULL,
-    NULL,
-    NULL,
-    &check_pdbinfo,
-    NULL,
-    NULL,
-    NULL,
-    &evaluate_betafactor,
-    NULL,
-};
-
-/** \internal Selection method data for \p x selection keyword. */
-gmx_ana_selmethod_t sm_x = {
-    "x", REAL_VALUE, SMETH_DYNAMIC,
-    0, NULL,
-     NULL,
-     NULL,
-     NULL,
-     NULL,
-     NULL,
-     NULL,
-     NULL,
-    &evaluate_x,
-};
-
-/** \internal Selection method data for \p y selection keyword. */
-gmx_ana_selmethod_t sm_y = {
-    "y", REAL_VALUE, SMETH_DYNAMIC,
-    0, NULL,
-     NULL,
-     NULL,
-     NULL,
-     NULL,
-     NULL,
-     NULL,
-     NULL,
-    &evaluate_y,
-};
-
-/** \internal Selection method data for \p z selection keyword. */
-gmx_ana_selmethod_t sm_z = {
-    "z", REAL_VALUE, SMETH_DYNAMIC,
-    0, NULL,
-     NULL,
-     NULL,
-     NULL,
-     NULL,
-     NULL,
-     NULL,
-     NULL,
-    &evaluate_z,
-};
-
-/*!
- * See sel_updatefunc() for description of the parameters.
- * \p data is not used.
- *
- * Copies \p g to \p out->u.g.
- */
-static int
-evaluate_all(t_topology *top, t_trxframe *fr, t_pbc *pbc,
-             gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
-{
-    gmx_ana_index_copy(out->u.g, g, FALSE);
-    return 0;
-}
-
-/*!
- * See sel_updatefunc() for description of the parameters.
- * \p data is not used.
- *
- * Returns an empty \p out->u.g.
- */
-static int
-evaluate_none(t_topology *top, t_trxframe *fr, t_pbc *pbc,
-              gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
-{
-    out->u.g->isize = 0;
-    return 0;
-}
-
-/*!
- * See sel_updatefunc() for description of the parameters.
- * \p data is not used.
- *
- * Returns the indices for each atom in \p out->u.i.
- */
-static int
-evaluate_atomnr(t_topology *top, t_trxframe *fr, t_pbc *pbc,
-                gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
-{
-    int  i;
-
-    out->nr = g->isize;
-    for (i = 0; i < g->isize; ++i)
-    {
-        out->u.i[i] = g->index[i] + 1;
-    }
-    return 0;
-}
-
-/*!
- * See sel_updatefunc() for description of the parameters.
- * \p data is not used.
- *
- * Returns the residue numbers for each atom in \p out->u.i.
- */
-static int
-evaluate_resnr(t_topology *top, t_trxframe *fr, t_pbc *pbc,
-               gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
-{
-    int  i;
-    int  resind;
-
-    out->nr = g->isize;
-    for (i = 0; i < g->isize; ++i)
-    {
-        resind = top->atoms.atom[g->index[i]].resind;
-        out->u.i[i] = top->atoms.resinfo[resind].nr;
-    }
-    return 0;
-}
-
-/*!
- * See sel_updatefunc() for description of the parameters.
- * \p data is not used.
- *
- * Returns the residue indices for each atom in \p out->u.i.
- */
-static int
-evaluate_resindex(t_topology *top, t_trxframe *fr, t_pbc *pbc,
-                  gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
-{
-    int  i;
-
-    out->nr = g->isize;
-    for (i = 0; i < g->isize; ++i)
-    {
-        out->u.i[i] = top->atoms.atom[g->index[i]].resind + 1;
-    }
-    return 0;
-}
-
-/*!
- * \param[in] top  Topology structure.
- * \param     npar Not used.
- * \param     param Not used.
- * \param     data Not used.
- * \returns   0 if molecule info is present in the topology, -1 otherwise.
- *
- * If molecule information is not found, also prints an error message.
- */
-static int
-check_molecules(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data)
-{
-    gmx_bool bOk;
-
-    bOk = (top != NULL && top->mols.nr > 0);
-    if (!bOk)
-    {
-        fprintf(stderr, "Molecule information not available in topology!\n");
-        return -1;
-    }
-    return 0;
-}
-
-/*!
- * See sel_updatefunc() for description of the parameters.
- * \p data is not used.
- *
- * Returns the molecule indices for each atom in \p out->u.i.
- */
-static int
-evaluate_molindex(t_topology *top, t_trxframe *fr, t_pbc *pbc,
-                  gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
-{
-    int  i, j;
-
-    out->nr = g->isize;
-    for (i = j = 0; i < g->isize; ++i)
-    {
-        while (top->mols.index[j + 1] <= g->index[i]) ++j;
-        out->u.i[i] = j + 1;
-    }
-    return 0;
-}
-
-/*!
- * See sel_updatefunc() for description of the parameters.
- * \p data is not used.
- *
- * Returns the atom name for each atom in \p out->u.s.
- */
-static int
-evaluate_atomname(t_topology *top, t_trxframe *fr, t_pbc *pbc,
-                  gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
-{
-    int  i;
-
-    out->nr = g->isize;
-    for (i = 0; i < g->isize; ++i)
-    {
-        out->u.s[i] = *top->atoms.atomname[g->index[i]];
-    }
-    return 0;
-}
-
-/*!
- * \param[in] top  Topology structure.
- * \param     npar Not used.
- * \param     param Not used.
- * \param     data Not used.
- * \returns   0 if atom types are present in the topology, -1 otherwise.
- *
- * If the atom types are not found, also prints an error message.
- */
-static int
-check_atomtype(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data)
-{
-    gmx_bool bOk;
-
-    bOk = (top != NULL && top->atoms.atomtype != NULL);
-    if (!bOk)
-    {
-        fprintf(stderr, "Atom types not available in topology!\n");
-        return -1;
-    }
-    return 0;
-}
-
-/*!
- * See sel_updatefunc() for description of the parameters.
- * \p data is not used.
- *
- * Returns the atom type for each atom in \p out->u.s.
- * Segfaults if atom types are not found in the topology.
- */
-static int
-evaluate_atomtype(t_topology *top, t_trxframe *fr, t_pbc *pbc,
-                  gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
-{
-    int  i;
-
-    out->nr = g->isize;
-    for (i = 0; i < g->isize; ++i)
-    {
-        out->u.s[i] = *top->atoms.atomtype[g->index[i]];
-    }
-    return 0;
-}
-
-/*!
- * See sel_updatefunc() for description of the parameters.
- * \p data is not used.
- *
- * Returns the residue name for each atom in \p out->u.s.
- */
-static int
-evaluate_resname(t_topology *top, t_trxframe *fr, t_pbc *pbc,
-                 gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
-{
-    int  i;
-    int  resind;
-
-    out->nr = g->isize;
-    for (i = 0; i < g->isize; ++i)
-    {
-        resind = top->atoms.atom[g->index[i]].resind;
-        out->u.s[i] = *top->atoms.resinfo[resind].name;
-    }
-    return 0;
-}
-
-/*!
- * See sel_updatefunc() for description of the parameters.
- * \p data is not used.
- *
- * Returns the insertion code for each atom in \p out->u.s.
- */
-static int
-evaluate_insertcode(t_topology *top, t_trxframe *fr, t_pbc *pbc,
-                    gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
-{
-    int  i;
-    int  resind;
-
-    out->nr = g->isize;
-    for (i = 0; i < g->isize; ++i)
-    {
-        resind = top->atoms.atom[g->index[i]].resind;
-        out->u.s[i][0] = top->atoms.resinfo[resind].ic;
-    }
-    return 0;
-}
-
-/*!
- * See sel_updatefunc() for description of the parameters.
- * \p data is not used.
- *
- * Returns the chain for each atom in \p out->u.s.
- */
-static int
-evaluate_chain(t_topology *top, t_trxframe *fr, t_pbc *pbc,
-               gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
-{
-    int  i;
-    int  resind;
-
-    out->nr = g->isize;
-    for (i = 0; i < g->isize; ++i)
-    {
-        resind = top->atoms.atom[g->index[i]].resind;
-        out->u.s[i][0] = top->atoms.resinfo[resind].chainid;
-    }
-    return 0;
-}
-
-/*!
- * See sel_updatefunc() for description of the parameters.
- * \p data is not used.
- *
- * Returns the mass for each atom in \p out->u.r.
- */
-static int
-evaluate_mass(t_topology *top, t_trxframe *fr, t_pbc *pbc,
-              gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
-{
-    int  i;
-
-    out->nr = g->isize;
-    for (i = 0; i < g->isize; ++i)
-    {
-        out->u.r[i] = top->atoms.atom[g->index[i]].m;
-    }
-    return 0;
-}
-
-/*!
- * See sel_updatefunc() for description of the parameters.
- * \p data is not used.
- *
- * Returns the charge for each atom in \p out->u.r.
- */
-static int
-evaluate_charge(t_topology *top, t_trxframe *fr, t_pbc *pbc,
-                gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
-{
-    int  i;
-
-    out->nr = g->isize;
-    for (i = 0; i < g->isize; ++i)
-    {
-        out->u.r[i] = top->atoms.atom[g->index[i]].q;
-    }
-    return 0;
-}
-
-/*!
- * \param[in] top  Topology structure.
- * \param     npar Not used.
- * \param     param Not used.
- * \param     data Not used.
- * \returns   0 if PDB info is present in the topology, -1 otherwise.
- *
- * If PDB info is not found, also prints an error message.
- */
-static int
-check_pdbinfo(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data)
-{
-    gmx_bool bOk;
-
-    bOk = (top != NULL && top->atoms.pdbinfo != NULL);
-    if (!bOk)
-    {
-        fprintf(stderr, "PDB info not available in topology!\n");
-        return -1;
-    }
-    return 0;
-}
-
-/*!
- * See sel_updatefunc() for description of the parameters.
- * \p data is not used.
- *
- * Returns the alternate location identifier for each atom in \p out->u.s.
- */
-static int
-evaluate_altloc(t_topology *top, t_trxframe *fr, t_pbc *pbc,
-                gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
-{
-    int  i;
-
-    out->nr = g->isize;
-    for (i = 0; i < g->isize; ++i)
-    {
-        out->u.s[i][0] = top->atoms.pdbinfo[g->index[i]].altloc;
-    }
-    return 0;
-}
-
-/*!
- * See sel_updatefunc() for description of the parameters.
- * \p data is not used.
- *
- * Returns the occupancy numbers for each atom in \p out->u.r.
- * Segfaults if PDB info is not found in the topology.
- */
-static int
-evaluate_occupancy(t_topology *top, t_trxframe *fr, t_pbc *pbc,
-                   gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
-{
-    int  i;
-
-    out->nr = g->isize;
-    for (i = 0; i < g->isize; ++i)
-    {
-        out->u.r[i] = top->atoms.pdbinfo[g->index[i]].occup;
-    }
-    return 0;
-}
-
-/*!
- * See sel_updatefunc() for description of the parameters.
- * \p data is not used.
- *
- * Returns the B-factors for each atom in \p out->u.r.
- * Segfaults if PDB info is not found in the topology.
- */
-static int
-evaluate_betafactor(t_topology *top, t_trxframe *fr, t_pbc *pbc,
-                    gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
-{
-    int  i;
-
-    out->nr = g->isize;
-    for (i = 0; i < g->isize; ++i)
-    {
-        out->u.r[i] = top->atoms.pdbinfo[g->index[i]].bfac;
-    }
-    return 0;
-}
-
-/*! \brief
- * Internal utility function for position keyword evaluation.
- *
- * \param[in]  fr   Current frame.
- * \param[in]  g    Index group for which the coordinates should be evaluated.
- * \param[out] out  Output array.
- * \param[in]  pos  Position data to use instead of atomic coordinates
- *   (can be NULL).
- * \param[in]  d    Coordinate index to evaluate (\p XX, \p YY or \p ZZ).
- *
- * This function is used internally by evaluate_x(), evaluate_y() and
- * evaluate_z() to do the actual evaluation.
- */
-static void
-evaluate_coord(t_trxframe *fr, gmx_ana_index_t *g, real out[],
-               gmx_ana_pos_t *pos, int d)
-{
-    int  b, i;
-    real v;
-
-    if (pos)
-    {
-        for (b = 0; b < pos->nr; ++b)
-        {
-            v = pos->x[b][d];
-            for (i = pos->m.mapb.index[b]; i < pos->m.mapb.index[b+1]; ++i)
-            {
-                out[i] = v;
-            }
-        }
-    }
-    else
-    {
-        for (i = 0; i < g->isize; ++i)
-        {
-            out[i] = fr->x[g->index[i]][d];
-        }
-    }
-}
-
-/*!
- * See sel_updatefunc_pos() for description of the parameters.
- * \p data is not used.
- *
- * Returns the \p x coordinate for each atom in \p out->u.r.
- */
-static int
-evaluate_x(t_topology *top, t_trxframe *fr, t_pbc *pbc,
-           gmx_ana_pos_t *pos, gmx_ana_selvalue_t *out, void *data)
-{
-    out->nr = pos->g->isize;
-    evaluate_coord(fr, pos->g, out->u.r, pos, XX);
-    return 0;
-}
-
-/*!
- * See sel_updatefunc() for description of the parameters.
- * \p data is not used.
- *
- * Returns the \p y coordinate for each atom in \p out->u.r.
- */
-static int
-evaluate_y(t_topology *top, t_trxframe *fr, t_pbc *pbc,
-           gmx_ana_pos_t *pos, gmx_ana_selvalue_t *out, void *data)
-{
-    out->nr = pos->g->isize;
-    evaluate_coord(fr, pos->g, out->u.r, pos, YY);
-    return 0;
-}
-
-/*!
- * See sel_updatefunc() for description of the parameters.
- * \p data is not used.
- *
- * Returns the \p z coordinate for each atom in \p out->u.r.
- */
-static int
-evaluate_z(t_topology *top, t_trxframe *fr, t_pbc *pbc,
-           gmx_ana_pos_t *pos, gmx_ana_selvalue_t *out, void *data)
-{
-    out->nr = pos->g->isize;
-    evaluate_coord(fr, pos->g, out->u.r, pos, ZZ);
-    return 0;
-}
diff --git a/src/gmxlib/selection/symrec.c b/src/gmxlib/selection/symrec.c
deleted file mode 100644 (file)
index 2e40096..0000000
+++ /dev/null
@@ -1,507 +0,0 @@
-/*
- *
- *                This source code is part of
- *
- *                 G   R   O   M   A   C   S
- *
- *          GROningen MAchine for Chemical Simulations
- *
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
- * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
- * Copyright (c) 2001-2009, The GROMACS development team,
- * check out http://www.gromacs.org for more information.
-
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * If you want to redistribute modifications, please consider that
- * scientific software is very special. Version control is crucial -
- * bugs must be traceable. We will be happy to consider code for
- * inclusion in the official distribution, but derived work must not
- * be called official GROMACS. Details are found in the README & COPYING
- * files - if they are missing, get the official version at www.gromacs.org.
- *
- * To help us fund GROMACS development, we humbly ask that you cite
- * the papers on the package - you can find them in the top README file.
- *
- * For more info, check our website at http://www.gromacs.org
- */
-/*! \internal \file
- * \brief Implementation of functions in symrec.h.
- */
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <macros.h>
-#include <smalloc.h>
-#include <string2.h>
-#include <typedefs.h>
-#include <gmx_fatal.h>
-
-#include <poscalc.h>
-
-#include "selelem.h"
-#include "symrec.h"
-
-/*! \internal \brief
- * Symbol table for the selection parser.
- */
-struct gmx_sel_symtab_t
-{
-    /** Pointer to the first symbol in the linked list of symbols. */
-    gmx_sel_symrec_t *first;
-};
-
-/*! \internal \brief
- * Single symbol for the selection parser.
- */
-struct gmx_sel_symrec_t
-{
-    /** Name of the symbol. */
-    char                           *name;
-    /** Type of the symbol. */
-    e_symbol_t                      type;
-    /** Value of the symbol. */
-    union {
-        /** Pointer to the method structure (\ref SYMBOL_METHOD). */
-        struct gmx_ana_selmethod_t *meth;
-        /** Pointer to the variable value (\ref SYMBOL_VARIABLE). */
-        struct t_selelem           *var;
-    }                               u;
-    /** Pointer to the next symbol. */
-    struct gmx_sel_symrec_t        *next;
-};
-
-/** List of reserved symbols to register in add_reserved_symbols(). */
-static const char *const sym_reserved[] = {
-    "group",
-    "to",
-    "not",
-    "and",
-    "or",
-    "xor",
-    "yes",
-    "no",
-    "on",
-    "off",
-    "help",
-};
-
-/*!
- * \param[in] sym Symbol to query.
- * \returns   The name of \p sym.
- *
- * The returned pointer should not be free'd.
- */
-char *
-_gmx_sel_sym_name(gmx_sel_symrec_t *sym)
-{
-    return sym->name;
-}
-
-/*!
- * \param[in] sym Symbol to query.
- * \returns   The type of \p sym.
- */
-e_symbol_t
-_gmx_sel_sym_type(gmx_sel_symrec_t *sym)
-{
-    return sym->type;
-}
-
-/*!
- * \param[in] sym Symbol to query.
- * \returns   The method associated with \p sym, or NULL if \p sym is not a
- *   \ref SYMBOL_METHOD symbol.
- */
-struct gmx_ana_selmethod_t *
-_gmx_sel_sym_value_method(gmx_sel_symrec_t *sym)
-{
-    if (sym->type != SYMBOL_METHOD)
-    {
-        gmx_call("symbol is not a method symbol");
-        return NULL;
-    }
-    return sym->u.meth;
-}
-
-/*!
- * \param[in] sym Symbol to query.
- * \returns   The variable expression associated with \p sym, or NULL if
- *   \p sym is not a \ref SYMBOL_VARIABLE symbol.
- */
-struct t_selelem *
-_gmx_sel_sym_value_var(gmx_sel_symrec_t *sym)
-{
-    if (sym->type != SYMBOL_VARIABLE)
-    {
-        gmx_call("symbol is not a variable symbol");
-        return NULL;
-    }
-    return sym->u.var;
-}
-
-/*! \brief
- * Adds the reserved symbols to a symbol table.
- * 
- * \param[in,out] tab  Symbol table to which the symbols are added.
- *
- * Assumes that the symbol table is empty.
- */
-static void
-add_reserved_symbols(gmx_sel_symtab_t *tab)
-{
-    gmx_sel_symrec_t *sym;
-    gmx_sel_symrec_t *last;
-    size_t            i;
-
-    last = NULL;
-    for (i = 0; i < asize(sym_reserved); ++i)
-    {
-        snew(sym, 1);
-        sym->name = strdup(sym_reserved[i]);
-        sym->type = SYMBOL_RESERVED;
-        sym->next = NULL;
-        if (last)
-        {
-            last->next = sym;
-        }
-        else
-        {
-            tab->first = sym;
-        }
-        last = sym;
-    }
-}
-
-/*! \brief
- * Adds the position symbols to the symbol list.
- * 
- * \param[in,out] tab  Symbol table to which the symbols are added.
- */
-static void
-add_position_symbols(gmx_sel_symtab_t *tab)
-{
-    const char       **postypes;
-    gmx_sel_symrec_t  *sym;
-    gmx_sel_symrec_t  *last;
-    int                i;
-
-    postypes = gmx_ana_poscalc_create_type_enum(TRUE);
-    last = tab->first;
-    while (last && last->next)
-    {
-        last = last->next;
-    }
-    for (i = 1; postypes[i] != NULL; ++i)
-    {
-        snew(sym, 1);
-        sym->name = strdup(postypes[i]);
-        sym->type = SYMBOL_POS;
-        sym->next = NULL;
-        if (last)
-        {
-            last->next = sym;
-        }
-        else
-        {
-            tab->first = sym;
-        }
-        last = sym;
-    }
-    sfree(postypes);
-}
-
-/*!
- * \param[out] tabp Symbol table pointer to initialize.
- *
- * Reserved and position symbols are added to the created table.
- */
-int
-_gmx_sel_symtab_create(gmx_sel_symtab_t **tabp)
-{
-    gmx_sel_symtab_t *tab;
-
-    snew(tab, 1);
-    add_reserved_symbols(tab);
-    add_position_symbols(tab);
-    *tabp = tab;
-    return 0;
-}
-
-/*!
- * \param[in] tab Symbol table to free.
- *
- * The pointer \p tab is invalid after the call.
- */
-void
-_gmx_sel_symtab_free(gmx_sel_symtab_t *tab)
-{
-    gmx_sel_symrec_t *sym;
-
-    while (tab->first)
-    {
-        sym = tab->first;
-        tab->first = sym->next;
-        if (sym->type == SYMBOL_VARIABLE)
-        {
-            _gmx_selelem_free(sym->u.var);
-        }
-        sfree(sym->name);
-        sfree(sym);
-    }
-    sfree(tab);
-}
-
-/*!
- * \param[in] tab    Symbol table to search.
- * \param[in] name   Symbol name to find.
- * \param[in] bExact If FALSE, symbols that begin with \p name are also
- *   considered.
- * \returns   Pointer to the symbol with name \p name, or NULL if not found.
- *
- * If no exact match is found and \p bExact is FALSE, returns a symbol that
- * begins with \p name if a unique matching symbol is found.
- */
-gmx_sel_symrec_t *
-_gmx_sel_find_symbol(gmx_sel_symtab_t *tab, const char *name, gmx_bool bExact)
-{
-    return _gmx_sel_find_symbol_len(tab, name, strlen(name), bExact);
-}
-
-/*!
- * \param[in] tab    Symbol table to search.
- * \param[in] name   Symbol name to find.
- * \param[in] len    Only consider the first \p len characters of \p name.
- * \param[in] bExact If FALSE, symbols that begin with \p name are also
- *   considered.
- * \returns   Pointer to the symbol with name \p name, or NULL if not found.
- *
- * If no exact match is found and \p bExact is FALSE, returns a symbol that
- * begins with \p name if a unique matching symbol is found.
- *
- * The parameter \p len is there to allow using this function from scanner.l
- * without modifying the text to be scanned or copying it.
- */
-gmx_sel_symrec_t *
-_gmx_sel_find_symbol_len(gmx_sel_symtab_t *tab, const char *name, size_t len,
-                         gmx_bool bExact)
-{
-    gmx_sel_symrec_t *sym;
-    gmx_sel_symrec_t *match;
-    gmx_bool              bUnique;
-    gmx_bool              bMatch;
-
-    match = NULL;
-    bUnique = TRUE;
-    bMatch  = FALSE;
-    sym = tab->first;
-    while (sym)
-    {
-        if (!strncmp(sym->name, name, len))
-        {
-            if (strlen(sym->name) == len)
-            {
-                return sym;
-            }
-            if (bMatch)
-            {
-                bUnique = FALSE;
-            }
-            bMatch = TRUE;
-            if (sym->type == SYMBOL_METHOD)
-            {
-                match = sym;
-            }
-        }
-        sym = sym->next;
-    }
-    if (bExact)
-    {
-        return NULL;
-    }
-
-    if (!bUnique)
-    {
-        fprintf(stderr, "parse error: ambiguous symbol\n");
-        return NULL;
-    }
-    return match;
-}
-
-/*!
- * \param[in] tab   Symbol table to search.
- * \param[in] type  Type of symbol to find.
- * \returns   The first symbol in \p tab with type \p type,
- *   or NULL if there are no such symbols.
- */
-gmx_sel_symrec_t *
-_gmx_sel_first_symbol(gmx_sel_symtab_t *tab, e_symbol_t type)
-{
-    gmx_sel_symrec_t *sym;
-
-    sym = tab->first;
-    while (sym)
-    {
-        if (sym->type == type)
-        {
-            return sym;
-        }
-        sym = sym->next;
-    }
-    return NULL;
-}
-
-/*!
- * \param[in] after Start the search after this symbol.
- * \param[in] type  Type of symbol to find.
- * \returns   The next symbol after \p after with type \p type,
- *   or NULL if there are no more symbols.
- */
-gmx_sel_symrec_t *
-_gmx_sel_next_symbol(gmx_sel_symrec_t *after, e_symbol_t type)
-{
-    gmx_sel_symrec_t *sym;
-
-    sym = after->next;
-    while (sym)
-    {
-        if (sym->type == type)
-        {
-            return sym;
-        }
-        sym = sym->next;
-    }
-    return NULL;
-}
-
-/*! \brief
- * Internal utility function used in adding symbols to a symbol table.
- *
- * \param[in,out] tab   Symbol table to add the symbol to.
- * \param[in]     name  Name of the symbol to add.
- * \param[out]    ctype On error, the type of the conflicting symbol is
- *   written to \p *ctype.
- * \returns       Pointer to the new symbol record, or NULL if \p name
- *   conflicts with an existing symbol.
- */
-static gmx_sel_symrec_t *
-add_symbol(gmx_sel_symtab_t *tab, const char *name, e_symbol_t *ctype)
-{
-    gmx_sel_symrec_t *sym, *psym;
-    int               len;
-
-    /* Check if there is a conflicting symbol */
-    psym = NULL;
-    sym  = tab->first;
-    while (sym)
-    {
-        if (!gmx_strcasecmp(sym->name, name))
-        {
-            *ctype = sym->type;
-            return NULL;
-        }
-        psym = sym;
-        sym  = sym->next;
-    }
-
-    /* Create a new symbol record */
-    if (psym == NULL)
-    {
-        snew(tab->first, 1);
-        sym = tab->first;
-    }
-    else
-    {
-        snew(psym->next, 1);
-        sym = psym->next;
-    }
-    sym->name = strdup(name);
-    return sym;
-}
-
-/*!
- * \param[in,out] tab    Symbol table to add the symbol to.
- * \param[in]     name   Name of the new symbol.
- * \param[in]     sel    Value of the variable.
- * \returns       Pointer to the created symbol record, or NULL if there was a
- *   symbol with the same name.
- */
-gmx_sel_symrec_t *
-_gmx_sel_add_var_symbol(gmx_sel_symtab_t *tab, const char *name,
-                        struct t_selelem *sel)
-{
-    gmx_sel_symrec_t *sym;
-    e_symbol_t        ctype;
-
-    sym = add_symbol(tab, name, &ctype);
-    if (!sym)
-    {
-        fprintf(stderr, "parse error: ");
-        switch (ctype)
-        {
-            case SYMBOL_RESERVED:
-            case SYMBOL_POS:
-                fprintf(stderr, "variable name (%s) conflicts with a reserved keyword\n",
-                        name);
-                break;
-            case SYMBOL_VARIABLE:
-                fprintf(stderr, "duplicate variable name (%s)\n", name);
-                break;
-            case SYMBOL_METHOD:
-                fprintf(stderr, "variable name (%s) conflicts with a selection keyword\n",
-                        name);
-                break;
-        }
-        return NULL;
-    }
-
-    sym->type  = SYMBOL_VARIABLE;
-    sym->u.var = sel;
-    sel->refcount++;
-    return sym;
-}
-
-/*!
- * \param[in,out] tab    Symbol table to add the symbol to.
- * \param[in]     name   Name of the new symbol.
- * \param[in]     method Method that this symbol represents.
- * \returns       Pointer to the created symbol record, or NULL if there was a
- *   symbol with the same name.
- */
-gmx_sel_symrec_t *
-_gmx_sel_add_method_symbol(gmx_sel_symtab_t *tab, const char *name,
-                           struct gmx_ana_selmethod_t *method)
-{
-    gmx_sel_symrec_t *sym;
-    e_symbol_t        ctype;
-
-    sym = add_symbol(tab, name, &ctype);
-    if (!sym)
-    {
-        fprintf(stderr, "parse error: ");
-        switch (ctype)
-        {
-            case SYMBOL_RESERVED:
-            case SYMBOL_POS:
-                fprintf(stderr, "method name (%s) conflicts with a reserved keyword\n",
-                        name);
-                break;
-            case SYMBOL_VARIABLE:
-                fprintf(stderr, "method name (%s) conflicts with a variable name\n",
-                        name);
-                break;
-            case SYMBOL_METHOD:
-                fprintf(stderr, "duplicate method name (%s)\n", name);
-                break;
-        }
-        return NULL;
-    }
-
-    sym->type   = SYMBOL_METHOD;
-    sym->u.meth = method;
-    return sym;
-}
diff --git a/src/gmxlib/selection/symrec.h b/src/gmxlib/selection/symrec.h
deleted file mode 100644 (file)
index bbf21b1..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- *
- *                This source code is part of
- *
- *                 G   R   O   M   A   C   S
- *
- *          GROningen MAchine for Chemical Simulations
- *
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
- * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
- * Copyright (c) 2001-2009, The GROMACS development team,
- * check out http://www.gromacs.org for more information.
-
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * If you want to redistribute modifications, please consider that
- * scientific software is very special. Version control is crucial -
- * bugs must be traceable. We will be happy to consider code for
- * inclusion in the official distribution, but derived work must not
- * be called official GROMACS. Details are found in the README & COPYING
- * files - if they are missing, get the official version at www.gromacs.org.
- *
- * To help us fund GROMACS development, we humbly ask that you cite
- * the papers on the package - you can find them in the top README file.
- *
- * For more info, check our website at http://www.gromacs.org
- */
-/*! \internal \file
- * \brief Handling of selection parser symbol table.
- *
- * This is an implementation header: there should be no need to use it outside
- * this directory.
- */
-#ifndef SELECTION_SYMREC_H
-#define SELECTION_SYMREC_H
-
-struct t_selelem;
-struct gmx_ana_selmethod_t;
-
-/** Defines the type of the symbol. */
-typedef enum
-{
-    SYMBOL_RESERVED,    /**< The symbol is a reserved keyword. */
-    SYMBOL_VARIABLE,    /**< The symbol is a variable. */
-    SYMBOL_METHOD,      /**< The symbol is a selection method. */
-    SYMBOL_POS          /**< The symbol is a position keyword. */
-} e_symbol_t;
-
-/** Symbol table for the selection parser. */
-typedef struct gmx_sel_symtab_t gmx_sel_symtab_t;
-/** Single symbol for the selection parser. */
-typedef struct gmx_sel_symrec_t gmx_sel_symrec_t;
-
-/** Returns the name of a symbol. */
-char *
-_gmx_sel_sym_name(gmx_sel_symrec_t *sym);
-/** Returns the type of a symbol. */
-e_symbol_t
-_gmx_sel_sym_type(gmx_sel_symrec_t *sym);
-/** Returns the method associated with a \ref SYMBOL_METHOD symbol. */
-struct gmx_ana_selmethod_t *
-_gmx_sel_sym_value_method(gmx_sel_symrec_t *sym);
-/** Returns the method associated with a \ref SYMBOL_VARIABLE symbol. */
-struct t_selelem *
-_gmx_sel_sym_value_var(gmx_sel_symrec_t *sym);
-
-/** Creates a new symbol table. */
-int
-_gmx_sel_symtab_create(gmx_sel_symtab_t **tabp);
-/** Frees all memory allocated for a symbol table. */
-void
-_gmx_sel_symtab_free(gmx_sel_symtab_t *tab);
-/** Finds a symbol by name. */
-gmx_sel_symrec_t *
-_gmx_sel_find_symbol(gmx_sel_symtab_t *tab, const char *name, gmx_bool bExact);
-/** Finds a symbol by name. */
-gmx_sel_symrec_t *
-_gmx_sel_find_symbol_len(gmx_sel_symtab_t *tab, const char *name, size_t len,
-                         gmx_bool bExact);
-/** Returns the first symbol of a given type. */
-gmx_sel_symrec_t *
-_gmx_sel_first_symbol(gmx_sel_symtab_t *tab, e_symbol_t type);
-/** Returns the next symbol of a given type. */
-gmx_sel_symrec_t *
-_gmx_sel_next_symbol(gmx_sel_symrec_t *after, e_symbol_t type);
-/** Adds a new variable symbol. */
-gmx_sel_symrec_t *
-_gmx_sel_add_var_symbol(gmx_sel_symtab_t *tab, const char *name,
-                        struct t_selelem *sel);
-/** Adds a new method symbol. */
-gmx_sel_symrec_t *
-_gmx_sel_add_method_symbol(gmx_sel_symtab_t *tab, const char *name,
-                           struct gmx_ana_selmethod_t *method);
-
-#endif
diff --git a/src/gmxlib/selection/test_selection.c b/src/gmxlib/selection/test_selection.c
deleted file mode 100644 (file)
index bde0ad1..0000000
+++ /dev/null
@@ -1,231 +0,0 @@
-/*
- *
- *                This source code is part of
- *
- *                 G   R   O   M   A   C   S
- *
- *          GROningen MAchine for Chemical Simulations
- *
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
- * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
- * Copyright (c) 2001-2009, The GROMACS development team,
- * check out http://www.gromacs.org for more information.
-
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * If you want to redistribute modifications, please consider that
- * scientific software is very special. Version control is crucial -
- * bugs must be traceable. We will be happy to consider code for
- * inclusion in the official distribution, but derived work must not
- * be called official GROMACS. Details are found in the README & COPYING
- * files - if they are missing, get the official version at www.gromacs.org.
- *
- * To help us fund GROMACS development, we humbly ask that you cite
- * the papers on the package - you can find them in the top README file.
- *
- * For more info, check our website at http://www.gromacs.org
- */
-/*! \internal \file
- * \brief Testing/debugging tool for the selection engine.
- */
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <copyrite.h>
-#include <filenm.h>
-#include <macros.h>
-#include <smalloc.h>
-#include <statutil.h>
-
-#include <trajana.h>
-
-typedef struct
-{
-    gmx_bool                     bFrameTree;
-    int                      nmaxind;
-    gmx_ana_selcollection_t *sc;
-} t_dumpdata;
-
-int
-dump_frame(t_topology * top, t_trxframe * fr, t_pbc * pbc,
-           int nr, gmx_ana_selection_t *sel[], void *data)
-{
-    t_dumpdata         *d = (t_dumpdata *)data;
-    int                 g, i, n;
-
-    fprintf(stderr, "\n");
-    if (d->bFrameTree)
-    {
-        gmx_ana_selcollection_print_tree(stderr, d->sc, TRUE);
-    }
-    for (g = 0; g < nr; ++g)
-    {
-        gmx_ana_index_dump(sel[g]->g, g, d->nmaxind);
-        fprintf(stderr, "  Positions (%d pcs):\n", sel[g]->p.nr);
-        n = sel[g]->p.nr;
-        if (d->nmaxind >= 0 && n > d->nmaxind)
-        {
-            n = d->nmaxind;
-        }
-        for (i = 0; i < n; ++i)
-        {
-            fprintf(stderr, "    (%.2f,%.2f,%.2f) r=%d, m=%d, b=%d-%d\n",
-                    sel[g]->p.x[i][XX], sel[g]->p.x[i][YY], sel[g]->p.x[i][ZZ],
-                    sel[g]->p.m.refid[i], sel[g]->p.m.mapid[i],
-                    sel[g]->p.m.mapb.index[i]+1,
-                    sel[g]->p.m.mapb.index[i+1]);
-        }
-        if (n < sel[g]->p.nr)
-        {
-            fprintf(stderr, "    ...\n");
-        }
-    }
-    fprintf(stderr, "\n");
-    return 0;
-}
-
-static void
-print_selections(int nr, gmx_ana_selection_t **sel, int nmaxind)
-{
-    int                 g, i, n;
-
-    fprintf(stderr, "\nSelections:\n");
-    for (g = 0; g < nr; ++g)
-    {
-        fprintf(stderr, "  ");
-        gmx_ana_selection_print_info(sel[g]);
-        fprintf(stderr, "    ");
-        gmx_ana_index_dump(sel[g]->g, g, nmaxind);
-
-        fprintf(stderr, "    Block (size=%d):", sel[g]->p.m.mapb.nr);
-        if (!sel[g]->p.m.mapb.index)
-        {
-            fprintf(stderr, " (null)");
-        }
-        else
-        {
-            n = sel[g]->p.m.mapb.nr;
-            if (nmaxind >= 0 && n > nmaxind)
-                n = nmaxind;
-            for (i = 0; i <= n; ++i)
-                fprintf(stderr, " %d", sel[g]->p.m.mapb.index[i]);
-            if (n < sel[g]->p.m.mapb.nr)
-                fprintf(stderr, " ...");
-        }
-        fprintf(stderr, "\n");
-
-        n = sel[g]->p.m.nr;
-        if (nmaxind >= 0 && n > nmaxind)
-            n = nmaxind;
-        fprintf(stderr, "    RefId:");
-        if (!sel[g]->p.m.refid)
-        {
-            fprintf(stderr, " (null)");
-        }
-        else
-        {
-            for (i = 0; i < n; ++i)
-                fprintf(stderr, " %d", sel[g]->p.m.refid[i]);
-            if (n < sel[g]->p.m.nr)
-                fprintf(stderr, " ...");
-        }
-        fprintf(stderr, "\n");
-
-        fprintf(stderr, "    MapId:");
-        if (!sel[g]->p.m.mapid)
-        {
-            fprintf(stderr, " (null)");
-        }
-        else
-        {
-            for (i = 0; i < n; ++i)
-                fprintf(stderr, " %d", sel[g]->p.m.mapid[i]);
-            if (n < sel[g]->p.m.nr)
-                fprintf(stderr, " ...");
-        }
-        fprintf(stderr, "\n");
-    }
-    fprintf(stderr, "\n");
-}
-
-int
-gmx_test_selection(int argc, char *argv[])
-{
-    const char         *desc[] = {
-        "This is a test program for selections.",
-    };
-
-    gmx_bool                bMaskOnly  = FALSE;
-    gmx_bool                bFrameTree = FALSE;
-    gmx_bool                bDebugCompile = FALSE;
-    int                 nref       = 0;
-    int                 nmaxind    = 20;
-    t_pargs             pa[] = {
-        {"-mask",   FALSE, etBOOL, {&bMaskOnly},
-         "Test position mask functionality"},
-        {"-compdebug", FALSE, etBOOL, {&bDebugCompile},
-         "Print intermediate trees during compilation"},
-        {"-frtree", FALSE, etBOOL, {&bFrameTree},
-         "Print the whole evaluation tree for each frame"},
-        {"-nref",   FALSE, etINT,  {&nref},
-         "Number of reference selections to ask for"},
-        {"-pmax",   FALSE, etINT,  {&nmaxind},
-         "Maximum number of indices to print in lists (-1 = print all)"},
-    };
-
-    t_filenm            fnm[] = {
-        {efDAT, "-o", "debug", ffOPTWR},
-    };
-
-    gmx_ana_traj_t       *trj;
-    t_dumpdata            d;
-    int                   ngrps;
-    gmx_ana_selection_t **sel;
-    output_env_t          oenv;
-
-#define NFILE asize(fnm)
-
-    CopyRight(stderr, argv[0]);
-
-    gmx_ana_traj_create(&trj, ANA_DEBUG_SELECTION | ANA_USER_SELINIT | ANA_USE_FULLGRPS);
-    gmx_ana_get_selcollection(trj, &d.sc);
-    gmx_ana_set_nanagrps(trj, -1);
-    parse_trjana_args(trj, &argc, argv, 0,
-                      NFILE, fnm, asize(pa), pa, asize(desc), desc, 0, NULL,
-                      &oenv);
-    if (bMaskOnly)
-    {
-        gmx_ana_add_flags(trj, ANA_USE_POSMASK);
-        gmx_ana_selcollection_set_outpostype(d.sc, NULL, TRUE);
-    }
-    gmx_ana_selcollection_set_compile_debug(d.sc, bDebugCompile);
-    gmx_ana_set_nrefgrps(trj, nref);
-    gmx_ana_init_selections(trj);
-    gmx_ana_get_ngrps(trj, &ngrps);
-    gmx_ana_get_anagrps(trj, &sel);
-
-    d.bFrameTree = bFrameTree;
-    d.nmaxind    = nmaxind;
-
-    print_selections(ngrps, sel, d.nmaxind);
-
-    gmx_ana_do(trj, 0, &dump_frame, &d);
-
-    print_selections(ngrps, sel, d.nmaxind);
-
-    gmx_ana_traj_free(trj);
-    done_filenms(NFILE, fnm);
-
-    return 0;
-}
-
-int
-main(int argc, char *argv[])
-{
-    gmx_test_selection(argc, argv);
-    return 0;
-}
diff --git a/src/gmxlib/statistics/.gitignore b/src/gmxlib/statistics/.gitignore
deleted file mode 100644 (file)
index c8b0843..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-.deps
-.libs
diff --git a/src/gmxlib/statistics/Makefile.am b/src/gmxlib/statistics/Makefile.am
deleted file mode 100644 (file)
index 8390adc..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-# Convenience library for statistics routine - not installed
-
-AM_CPPFLAGS= -I$(top_srcdir)/include 
-
-noinst_LTLIBRARIES = libstatistics.la
-
-libstatistics_la_SOURCES =     \
-       gmx_statistics.c        histogram.c
-
-LDADD =        ../libgmx@LIBSUFFIX@.la
-
-EXTRA_PROGRAMS = gmx_statistics_test
-
-CLEANFILES     = *.la *~ \\\#* 
diff --git a/src/gmxlib/statistics/gmx_statistics.c b/src/gmxlib/statistics/gmx_statistics.c
deleted file mode 100644 (file)
index 7b50f92..0000000
+++ /dev/null
@@ -1,786 +0,0 @@
-/* -*- mode: c; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; c-file-style: "stroustrup"; -*- */
-/*
- * 
- *                This source code is part of
- * 
- *                 G   R   O   M   A   C   S
- * 
- *          GROningen MAchine for Chemical Simulations
- * 
- *                        VERSION 3.2.0
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
- * 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.
-
- * 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:
- * Green Red Orange Magenta Azure Cyan Skyblue
- */
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <math.h>
-#include "typedefs.h"
-#include "smalloc.h"
-#include "gmx_statistics.h"
-
-static double sqr(double x)
-{
-    return x*x;
-}
-
-static int gmx_nint(double x)
-{
-    return (int) (x+0.5);
-}
-
-typedef struct gmx_stats {
-    double aa,a,b,sigma_aa,sigma_a,sigma_b,aver,sigma_aver,error;
-    double rmsd,Rdata,Rfit,Rfitaa,chi2,chi2aa;
-    double *x,*y,*dx,*dy;
-    int    computed;
-    int    np,np_c,nalloc;
-} gmx_stats;
-
-gmx_stats_t gmx_stats_init()
-{
-    gmx_stats *stats;
-  
-    snew(stats,1);
-  
-    return (gmx_stats_t) stats;
-}
-
-int gmx_stats_get_npoints(gmx_stats_t gstats, int *N)
-{
-    gmx_stats *stats = (gmx_stats *) gstats;
-  
-    *N = stats->np;
-  
-    return estatsOK;
-}
-
-int gmx_stats_done(gmx_stats_t gstats)
-{
-    gmx_stats *stats = (gmx_stats *) gstats;
-  
-    sfree(stats->x);
-    stats->x = NULL;
-    sfree(stats->y);
-    stats->y = NULL;
-    sfree(stats->dx);
-    stats->dx = NULL;
-    sfree(stats->dy);
-    stats->dy = NULL;
-  
-    return estatsOK;
-}
-
-int gmx_stats_add_point(gmx_stats_t gstats,double x,double y,
-                        double dx,double dy)
-{
-    gmx_stats *stats = (gmx_stats *) gstats;
-    int i;
-  
-    if (stats->np+1 >= stats->nalloc) 
-    {
-        if (stats->nalloc == 0) 
-            stats->nalloc = 1024;
-        else
-            stats->nalloc *= 2;
-        srenew(stats->x,stats->nalloc);
-        srenew(stats->y,stats->nalloc);
-        srenew(stats->dx,stats->nalloc);
-        srenew(stats->dy,stats->nalloc);
-        for(i=stats->np; (i<stats->nalloc); i++) 
-        {
-            stats->x[i]  = 0;
-            stats->y[i]  = 0;
-            stats->dx[i] = 0;
-            stats->dy[i] = 0;
-        }
-    }
-    stats->x[stats->np]  = x;
-    stats->y[stats->np]  = y;
-    stats->dx[stats->np] = dx;
-    stats->dy[stats->np] = dy;
-    stats->np++;
-    stats->computed = 0;
-  
-    return estatsOK;
-}
-
-int gmx_stats_get_point(gmx_stats_t gstats,real *x,real *y,
-                        real *dx,real *dy)
-{
-    gmx_stats *stats = (gmx_stats *) gstats;
-  
-    if (stats->np_c < stats->np) 
-    {
-        if (NULL != x)  *x  = stats->x[stats->np_c];
-        if (NULL != y)  *y  = stats->y[stats->np_c];
-        if (NULL != dx) *dx = stats->dx[stats->np_c];
-        if (NULL != dy) *dy = stats->dy[stats->np_c];
-        stats->np_c++;
-    
-        return estatsOK;
-    }
-    stats->np_c = 0;
-  
-    return estatsNO_POINTS;
-}
-
-int gmx_stats_add_points(gmx_stats_t gstats,int n,real *x,real *y,
-                         real *dx,real *dy)
-{
-    int i,ok;
-  
-    for(i=0; (i<n); i++) 
-    {
-        if ((ok = gmx_stats_add_point(gstats,x[i],y[i],
-                                      (NULL != dx) ? dx[i] : 0,
-                                      (NULL != dy) ? dy[i] : 0)) != estatsOK)
-        {
-            return ok;
-        }
-    }
-    return estatsOK;
-}
-
-static int gmx_stats_compute(gmx_stats *stats,int weight)
-{
-    double yy,yx,xx,sx,sy,dy,chi2,chi2aa,d2;
-    double ssxx,ssyy,ssxy;
-    double w,wtot,yx_nw,sy_nw,sx_nw,yy_nw,xx_nw,dx2,dy2;
-    int i,N;
-  
-    N = stats->np;
-    if (stats->computed == 0) 
-    {
-        if (N < 1)
-        {
-            return estatsNO_POINTS;
-        }
-      
-        xx = xx_nw = 0;
-        yy = yy_nw = 0;
-        yx = yx_nw = 0;
-        sx = sx_nw = 0;
-        sy = sy_nw = 0;
-        wtot = 0;
-        d2   = 0;
-        for(i=0; (i<N); i++) 
-        {
-            d2 += sqr(stats->x[i]-stats->y[i]);
-            if ((stats->dy[i]) && (weight == elsqWEIGHT_Y))
-            {
-                w = 1/sqr(stats->dy[i]);
-            }
-            else
-            {
-                w = 1;
-            }
-            
-            wtot  += w;
-            
-            xx    += w*sqr(stats->x[i]);
-            xx_nw += sqr(stats->x[i]);
-            
-            yy    += w*sqr(stats->y[i]);
-            yy_nw += sqr(stats->y[i]);
-            
-            yx    += w*stats->y[i]*stats->x[i];
-            yx_nw += stats->y[i]*stats->x[i];
-            
-            sx    += w*stats->x[i];
-            sx_nw += stats->x[i];
-            
-            sy    += w*stats->y[i];
-            sy_nw += stats->y[i];
-        }
-      
-        /* Compute average, sigma and error */
-        stats->aver       = sy_nw/N;
-        stats->sigma_aver = sqrt(yy_nw/N - sqr(sy_nw/N));
-        stats->error      = stats->sigma_aver/sqrt(N);
-
-        /* Compute RMSD between x and y */
-        stats->rmsd = sqrt(d2/N);
-       
-        /* Correlation coefficient for data */
-        yx_nw /= N;
-        xx_nw /= N;
-        yy_nw /= N;
-        sx_nw /= N;
-        sy_nw /= N;
-        ssxx = N*(xx_nw - sqr(sx_nw));
-        ssyy = N*(yy_nw - sqr(sy_nw));
-        ssxy = N*(yx_nw - (sx_nw*sy_nw));
-        stats->Rdata = sqrt(sqr(ssxy)/(ssxx*ssyy)); 
-        
-        /* Compute straight line through datapoints, either with intercept
-           zero (result in aa) or with intercept variable (results in a
-           and b) */
-        yx = yx/wtot;
-        xx = xx/wtot;
-        sx = sx/wtot;
-        sy = sy/wtot;
-  
-        stats->aa = (yx/xx);  
-        stats->a  = (yx-sx*sy)/(xx-sx*sx);
-        stats->b  = (sy)-(stats->a)*(sx);
-    
-        /* Compute chi2, deviation from a line y = ax+b. Also compute
-           chi2aa which returns the deviation from a line y = ax. */
-        chi2   = 0;
-        chi2aa = 0;
-        for(i=0; (i<N); i++) 
-        {
-            if (stats->dy[i] > 0)
-            {
-                dy = stats->dy[i];
-            }
-            else
-            {
-                dy = 1;
-            }
-            chi2aa += sqr((stats->y[i]-(stats->aa*stats->x[i]))/dy);
-            chi2   += sqr((stats->y[i]-(stats->a*stats->x[i]+stats->b))/dy);
-        }
-        if (N > 2) 
-        {
-            stats->chi2   = sqrt(chi2/(N-2));
-            stats->chi2aa = sqrt(chi2aa/(N-2));
-            
-            /* Look up equations! */
-            dx2 = (xx-sx*sx);
-            dy2 = (yy-sy*sy);
-            stats->sigma_a = sqrt(stats->chi2/((N-2)*dx2));
-            stats->sigma_b = stats->sigma_a*sqrt(xx);
-            stats->Rfit    = fabs(ssxy)/sqrt(ssxx*ssyy);
-                /*stats->a*sqrt(dx2/dy2);*/
-            stats->Rfitaa  = stats->aa*sqrt(dx2/dy2);  
-        }
-        else
-        {
-            stats->chi2    = 0;
-            stats->chi2aa  = 0;
-            stats->sigma_a = 0;
-            stats->sigma_b = 0;
-            stats->Rfit    = 0;
-            stats->Rfitaa  = 0;
-        }    
-
-        stats->computed = 1;
-    }
-  
-    return estatsOK;
-}
-
-int gmx_stats_get_ab(gmx_stats_t gstats,int weight,
-                     real *a,real *b,real *da,real *db,
-                     real *chi2,real *Rfit)
-{
-    gmx_stats *stats = (gmx_stats *) gstats;
-    int ok;
-  
-    if ((ok = gmx_stats_compute(stats,weight)) != estatsOK)
-        return ok;
-    if (NULL != a)
-    {
-        *a    = stats->a;
-    }
-    if (NULL != b)   
-    {
-        *b    = stats->b;
-    }
-    if (NULL != da)  
-    {
-        *da   = stats->sigma_a;
-    }
-    if (NULL != db)  
-    {
-        *db   = stats->sigma_b;
-    }
-    if (NULL != chi2) 
-    {
-        *chi2 = stats->chi2;
-    }
-    if (NULL != Rfit) 
-    {
-        *Rfit = stats->Rfit;
-    }
-    
-    return estatsOK;
-}
-
-int gmx_stats_get_a(gmx_stats_t gstats,int weight,real *a,real *da,
-                    real *chi2,real *Rfit)
-{
-    gmx_stats *stats = (gmx_stats *) gstats;
-    int ok;
-  
-    if ((ok = gmx_stats_compute(stats,weight)) != estatsOK)
-        return ok;
-    if (NULL != a)    *a    = stats->aa;
-    if (NULL != da)   *da   = stats->sigma_aa;
-    if (NULL != chi2) *chi2 = stats->chi2aa;
-    if (NULL != Rfit) *Rfit = stats->Rfitaa;
-  
-    return estatsOK;
-}
-
-int gmx_stats_get_average(gmx_stats_t gstats,real *aver)
-{
-    gmx_stats *stats = (gmx_stats *) gstats;
-    int ok;
-  
-    if ((ok = gmx_stats_compute(stats,elsqWEIGHT_NONE)) != estatsOK)
-    {
-        return ok;
-    }
-    
-    *aver = stats->aver;
-  
-    return estatsOK;
-}
-
-int gmx_stats_get_ase(gmx_stats_t gstats,real *aver,real *sigma,real *error)
-{
-    gmx_stats *stats = (gmx_stats *) gstats;
-    int ok;
-  
-    if ((ok = gmx_stats_compute(stats,elsqWEIGHT_NONE)) != estatsOK)
-    {
-        return ok;
-    }
-    
-    if (NULL != aver)
-    {
-        *aver  = stats->aver;
-    }
-    if (NULL != sigma) 
-    {
-        *sigma = stats->sigma_aver;
-    }
-    if (NULL != error) 
-    {
-        *error = stats->error;
-    }
-    
-    return estatsOK;
-}
-
-int gmx_stats_get_sigma(gmx_stats_t gstats,real *sigma)
-{
-    gmx_stats *stats = (gmx_stats *) gstats;
-    int ok;
-  
-    if ((ok = gmx_stats_compute(stats,elsqWEIGHT_NONE)) != estatsOK)
-        return ok;
-
-    *sigma = stats->sigma_aver;
-    
-    return estatsOK;
-}
-
-int gmx_stats_get_error(gmx_stats_t gstats,real *error)
-{
-    gmx_stats *stats = (gmx_stats *) gstats;
-    int ok;
-  
-    if ((ok = gmx_stats_compute(stats,elsqWEIGHT_NONE)) != estatsOK)
-        return ok;
-
-    *error = stats->error;
-  
-    return estatsOK;
-}
-
-int gmx_stats_get_corr_coeff(gmx_stats_t gstats,real *R)
-{
-    gmx_stats *stats = (gmx_stats *) gstats;
-    int ok;
-  
-    if ((ok = gmx_stats_compute(stats,elsqWEIGHT_NONE)) != estatsOK)
-        return ok;
-
-    *R = stats->Rdata;
-  
-    return estatsOK;
-}
-
-int gmx_stats_get_rmsd(gmx_stats_t gstats,real *rmsd)
-{
-    gmx_stats *stats = (gmx_stats *) gstats;
-    int ok;
-  
-    if ((ok = gmx_stats_compute(stats,elsqWEIGHT_NONE)) != estatsOK)
-    {
-        return ok;
-    }
-    
-    *rmsd = stats->rmsd;
-  
-    return estatsOK;
-}
-
-int gmx_stats_dump_xy(gmx_stats_t gstats,FILE *fp)
-{
-    gmx_stats *stats = (gmx_stats *) gstats;
-    int i,ok;
-  
-    for(i=0; (i<stats->np); i++) 
-    {
-        fprintf(fp,"%12g  %12g  %12g  %12g\n",stats->x[i],stats->y[i],
-                stats->dx[i],stats->dy[i]);
-    }
-    
-    return estatsOK;
-}
-
-int gmx_stats_remove_outliers(gmx_stats_t gstats,double level)
-{
-    gmx_stats *stats = (gmx_stats *) gstats;
-    int  i,iter=1,done=0,ok;
-    real rmsd,r;
-  
-    while ((stats->np >= 10) && !done) 
-    {
-        if ((ok = gmx_stats_get_rmsd(gstats,&rmsd)) != estatsOK)
-        {
-            return ok;
-        }
-        done = 1;
-        for(i=0; (i<stats->np); ) 
-        {
-            r = fabs(stats->x[i]-stats->y[i]);
-            if (r > level*rmsd) 
-            {
-                fprintf(stderr,"Removing outlier, iter = %d, rmsd = %g, x = %g, y = %g\n",
-                        iter,rmsd,stats->x[i],stats->y[i]);
-                if (i < stats->np-1) 
-                {
-                    stats->x[i]  = stats->x[stats->np-1];
-                    stats->y[i]  = stats->y[stats->np-1];
-                    stats->dx[i] = stats->dx[stats->np-1];
-                    stats->dy[i] = stats->dy[stats->np-1];
-                }
-                stats->np--;
-                done = 0;
-            }
-            else 
-            {
-                i++;
-            }
-        }
-        iter++;
-    }
-    
-    return estatsOK;
-}
-
-int gmx_stats_make_histogram(gmx_stats_t gstats,real binwidth,int *nb,
-                             int ehisto,int normalized,real **x,real **y)
-{
-    gmx_stats *stats = (gmx_stats *) gstats;
-    int    i,ok,index=0,nbins=*nb,*nindex;
-    double minx,maxx,maxy,miny,delta,dd,minh;
-  
-    if (((binwidth <= 0) && (nbins <= 0)) ||
-        ((binwidth > 0) && (nbins > 0)))
-    {
-        return estatsINVALID_INPUT;
-    }
-    if (stats->np <= 2)
-    {
-        return estatsNO_POINTS;
-    }
-    minx = maxx = stats->x[0];
-    miny = maxy = stats->y[0];
-    for(i=1; (i<stats->np); i++) 
-    {
-        miny = (stats->y[i] < miny) ? stats->y[i] : miny;
-        maxy = (stats->y[i] > maxy) ? stats->y[i] : maxy;
-        minx = (stats->x[i] < minx) ? stats->x[i] : minx;
-        maxx = (stats->x[i] > maxx) ? stats->x[i] : maxx;
-    }
-    if (ehisto == ehistoX)
-    {
-        delta = maxx-minx;
-        minh = minx;
-    }
-    else if (ehisto == ehistoY)
-    {
-        delta = maxy-miny;
-        minh = miny;
-    }
-    else
-        return estatsINVALID_INPUT;
-        
-    if (binwidth == 0)
-    {
-        binwidth = (delta)/nbins;
-    }
-    else
-    {
-        nbins = gmx_nint((delta)/binwidth + 0.5);
-    }
-    snew(*x,nbins);
-    snew(nindex,nbins);
-    for(i=0; (i<nbins); i++) 
-    {
-        (*x)[i] = minh + binwidth*(i+0.5);
-    }
-    if (normalized == 0)
-    {
-        dd = 1;
-    }
-    else
-    {
-        dd = 1.0/(binwidth*stats->np);
-    }
-    
-    snew(*y,nbins);
-    for(i=0; (i<stats->np); i++) 
-    {
-        if (ehisto == ehistoY)
-            index = (stats->y[i]-miny)/binwidth;
-               else if (ehisto == ehistoX)
-            index = (stats->x[i]-minx)/binwidth;
-               if (index<0)
-               {
-                       index = 0;
-               }
-               if (index>nbins-1)
-               {
-                       index = nbins-1;
-               }
-        (*y)[index] += dd;
-        nindex[index]++;
-    }
-    if (*nb == 0)
-        *nb = nbins;
-    for(i=0; (i<nbins); i++)
-        if (nindex[i] > 0)
-            (*y)[i] /= nindex[i];
-            
-    sfree(nindex);
-    
-    return estatsOK;
-}
-
-static const char *stats_error[estatsNR] = 
-{
-    "All well in STATS land",
-    "No points",
-    "Not enough memory",
-    "Invalid histogram input",
-    "Unknown error",
-    "Not implemented yet"
-};
-
-const char *gmx_stats_message(int estats)
-{
-    if ((estats >= 0) && (estats < estatsNR))
-    {
-        return stats_error[estats];
-    }
-    else
-    {
-        return stats_error[estatsERROR];
-    }
-}
-    
-/* Old convenience functions, should be merged with the core
-   statistics above. */
-int lsq_y_ax(int n, real x[], real y[], real *a)
-{
-    gmx_stats_t lsq = gmx_stats_init();
-    int  ok;
-    real da,chi2,Rfit;
-  
-    gmx_stats_add_points(lsq,n,x,y,0,0);
-    if ((ok = gmx_stats_get_a(lsq,elsqWEIGHT_NONE,a,&da,&chi2,&Rfit)) != estatsOK)
-    {
-        return ok;
-    }
-    
-    /*  int    i;
-        double xx,yx;
-  
-        yx=xx=0.0;
-        for (i=0; i<n; i++) {
-        yx+=y[i]*x[i];
-        xx+=x[i]*x[i];
-        }
-        *a=yx/xx;
-        */
-    return estatsOK;
-}
-
-static int low_lsq_y_ax_b(int n, real *xr, double *xd, real yr[],
-                          real *a, real *b,real *r,real *chi2)
-{
-    int    i,ok;
-    gmx_stats_t lsq;
-  
-    lsq = gmx_stats_init();
-    for(i=0; (i<n); i++) 
-    {
-        if ((ok = gmx_stats_add_point(lsq,(NULL != xd) ? xd[i] : xr[i],yr[i],0,0)) 
-            != estatsOK)
-        {
-            return ok;
-        }
-    }
-    if ((ok = gmx_stats_get_ab(lsq,elsqWEIGHT_NONE,a,b,NULL,NULL,chi2,r)) != estatsOK)
-    {
-        return ok;
-    }
-    
-    return estatsOK;
-    /*
-      double x,y,yx,xx,yy,sx,sy,chi2;
-
-      yx=xx=yy=sx=sy=0.0;
-      for (i=0; i<n; i++) {
-      if (xd != NULL) {
-      x = xd[i];
-      } else {
-      x = xr[i];
-      }
-      y =   yr[i];
-
-      yx += y*x;
-      xx += x*x;
-      yy += y*y;
-      sx += x;
-      sy += y;
-      }
-      *a = (n*yx-sy*sx)/(n*xx-sx*sx);
-      *b = (sy-(*a)*sx)/n;
-      *r = sqrt((xx-sx*sx)/(yy-sy*sy));
-  
-      chi2 = 0;
-      if (xd != NULL) {
-      for(i=0; i<n; i++)
-      chi2 += sqr(yr[i] - ((*a)*xd[i] + (*b)));
-      } else {
-      for(i=0; i<n; i++)
-      chi2 += sqr(yr[i] - ((*a)*xr[i] + (*b)));
-      }
-  
-      if (n > 2)
-      return sqrt(chi2/(n-2));
-      else
-      return 0;
-    */
-}
-
-int lsq_y_ax_b(int n, real x[], real y[], real *a, real *b,real *r,real *chi2)
-{
-    return low_lsq_y_ax_b(n,x,NULL,y,a,b,r,chi2);
-}
-
-int lsq_y_ax_b_xdouble(int n, double x[], real y[], real *a, real *b,
-                       real *r,real *chi2)
-{
-    return low_lsq_y_ax_b(n,NULL,x,y,a,b,r,chi2);
-}
-
-int lsq_y_ax_b_error(int n, real x[], real y[], real dy[],
-                     real *a, real *b, real *da, real *db,
-                     real *r,real *chi2)
-{
-    gmx_stats_t lsq;
-    int    i,ok;
-  
-    lsq = gmx_stats_init();
-    for(i=0; (i<n); i++)
-    {
-        if ((ok = gmx_stats_add_point(lsq,x[i],y[i],0,dy[i])) != estatsOK)
-        {
-            return ok;
-        }
-    }
-    if ((ok = gmx_stats_get_ab(lsq,elsqWEIGHT_Y,a,b,da,db,chi2,r)) != estatsOK)
-    {
-        return ok;
-    }
-    if ((ok = gmx_stats_done(lsq)) != estatsOK)
-    {
-        return ok;
-    }
-    sfree(lsq);
-
-    return estatsOK;
-    /*
-      double sxy,sxx,syy,sx,sy,w,s_2,dx2,dy2,mins;
-
-      sxy=sxx=syy=sx=sy=w=0.0;
-      mins = dy[0];
-      for(i=1; (i<n); i++)
-      mins = min(mins,dy[i]);
-      if (mins <= 0)
-      gmx_fatal(FARGS,"Zero or negative weigths in linear regression analysis");
-    
-      for (i=0; i<n; i++) {
-      s_2  = sqr(1.0/dy[i]);
-      sxx += s_2*sqr(x[i]);
-      sxy += s_2*y[i]*x[i];
-      syy += s_2*sqr(y[i]);
-      sx  += s_2*x[i];
-      sy  += s_2*y[i];
-      w   += s_2;
-      }
-      sxx = sxx/w;
-      sxy = sxy/w;
-      syy = syy/w;
-      sx  = sx/w;
-      sy  = sy/w;
-      dx2 = (sxx-sx*sx);
-      dy2 = (syy-sy*sy);
-      *a=(sxy-sy*sx)/dx2;
-      *b=(sy-(*a)*sx);
-  
-      *chi2=0;
-      for(i=0; i<n; i++)
-      *chi2+=sqr((y[i]-((*a)*x[i]+(*b)))/dy[i]);
-      *chi2 = *chi2/w;
-  
-      *da = sqrt(*chi2/((n-2)*dx2));
-      *db = *da*sqrt(sxx);
-      *r  = *a*sqrt(dx2/dy2);
-  
-      if (debug)
-      fprintf(debug,"sx = %g, sy = %g, sxy = %g, sxx = %g, w = %g\n"
-      "chi2 = %g, dx2 = %g\n",
-      sx,sy,sxy,sxx,w,*chi2,dx2);
-  
-      if (n > 2)
-      *chi2 = sqrt(*chi2/(n-2));
-      else
-      *chi2 = 0;
-      */
-}
-
-
diff --git a/src/gmxlib/string2.c b/src/gmxlib/string2.c
deleted file mode 100644 (file)
index 8f5f20b..0000000
+++ /dev/null
@@ -1,602 +0,0 @@
-/*
- * 
- *                This source code is part of
- * 
- *                 G   R   O   M   A   C   S
- * 
- *          GROningen MAchine for Chemical Simulations
- * 
- *                        VERSION 3.2.0
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
- * 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.
-
- * 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:
- * GROningen Mixture of Alchemy and Childrens' Stories
- */
-/* This file is completely threadsafe - keep it that way! */
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#ifdef GMX_CRAY_XT3
-#undef HAVE_PWD_H
-#endif
-
-#include <stdio.h>
-#include <ctype.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <sys/types.h>
-#include <time.h>
-
-#ifdef HAVE_SYS_TIME_H
-#include <sys/time.h>
-#endif
-
-
-#ifdef HAVE_PWD_H
-#include <pwd.h>
-#endif
-#include <time.h>
-
-#include "typedefs.h"
-#include "smalloc.h"
-#include "gmx_fatal.h"
-#include "macros.h"
-#include "string2.h"
-#include "futil.h"
-
-int continuing(char *s)
-/* strip trailing spaces and if s ends with a CONTINUE remove that too.
- * returns TRUE if s ends with a CONTINUE, FALSE otherwise.
- */
-{
-  int sl;
-
-  rtrim(s);
-  sl = strlen(s);
-  if ((sl > 0) && (s[sl-1] == CONTINUE)) {
-    s[sl-1] = 0;
-    return TRUE;
-  }
-  else
-    return FALSE;
-}
-
-
-
-char *fgets2(char *line, int n, FILE *stream)
-/* This routine reads a string from stream of max length n
- * and zero terminated, without newlines
- * line should be long enough (>= n)
- */
-{
-  char *c;
-  if (fgets(line,n,stream) == NULL) {
-    return NULL;
-  }
-  if ((c=strchr(line,'\n')) != NULL) {
-    *c = '\0';
-  } else {
-    /* A line not ending in a newline can only occur at the end of a file,
-     * or because of n being too small.
-     * Since both cases occur very infrequently, we can check for EOF.
-     */
-    if (!gmx_eof(stream)) {
-      gmx_fatal(FARGS,"An input file contains a line longer than %d characters, while the buffer passed to fgets2 has size %d. The line starts with: '%20.20s'",n,n,line);
-    }
-  }
-  if ((c=strchr(line,'\r')) != NULL) {
-    *c = '\0';
-  }
-
-  return line;
-}
-
-void strip_comment (char *line)
-{
-  char *c;
-
-  if (!line)
-    return;
-
-  /* search for a comment mark and replace it by a zero */
-  if ((c = strchr(line,COMMENTSIGN)) != NULL) 
-    (*c) = 0;
-}
-
-void upstring (char *str)
-{
-  int i;
-
-  for (i=0; (i < (int)strlen(str)); i++) 
-    str[i] = toupper(str[i]);
-}
-
-void ltrim (char *str)
-{
-  char *tr;
-  int i,c;
-
-  if (NULL == str)
-    return;
-
-  c = 0;
-  while (('\0' != str[c]) && isspace(str[c]))
-    c++;
-  if (c > 0) 
-    {
-      for(i=c; ('\0' != str[i]); i++)
-       str[i-c] = str[i];
-      str[i-c] = '\0';
-    }
-}
-
-void rtrim (char *str)
-{
-  int nul;
-
-  if (NULL == str)
-    return;
-
-  nul = strlen(str)-1;
-  while ((nul > 0) && ((str[nul] == ' ') || (str[nul] == '\t')) ) {
-    str[nul] = '\0';
-    nul--;
-  }
-}
-
-void trim (char *str)
-{
-  ltrim (str);
-  rtrim (str);
-}
-
-char *
-gmx_ctime_r(const time_t *clock,char *buf, int n)
-{
-    char tmpbuf[STRLEN];
-  
-#if ((defined WIN32 || defined _WIN32 || defined WIN64 || defined _WIN64) && !defined __CYGWIN__ && !defined __CYGWIN32__)
-    /* Windows */
-    ctime_s( tmpbuf, STRLEN, clock );
-#else
-    ctime_r(clock,tmpbuf);
-#endif
-    strncpy(buf,tmpbuf,n-1);
-    buf[n-1]='\0';
-    
-    return buf;
-}
-          
-void nice_header (FILE *out,const char *fn)
-{
-  const char *unk = "onbekend";
-  time_t clock;
-  char   *user=NULL;
-  int    gh;
-  uid_t  uid;
-  char   buf[256];
-  char   timebuf[STRLEN];
-#ifdef HAVE_PWD_H
-  struct passwd *pw;
-#endif
-
-  /* Print a nice header above the file */
-  time(&clock);
-  fprintf (out,"%c\n",COMMENTSIGN);
-  fprintf (out,"%c\tFile '%s' was generated\n",COMMENTSIGN,fn ? fn : unk);
-  
-#ifdef HAVE_PWD_H
-  uid = getuid();
-  pw  = getpwuid(uid);
-  gh  = gethostname(buf,255);
-  user= pw->pw_name;
-#else
-  uid = 0;
-  gh  = -1;
-#endif
-  
-  gmx_ctime_r(&clock,timebuf,STRLEN);
-  fprintf (out,"%c\tBy user: %s (%d)\n",COMMENTSIGN,
-          user ? user : unk,(int) uid);
-  fprintf(out,"%c\tOn host: %s\n",COMMENTSIGN,(gh == 0) ? buf : unk);
-
-  fprintf (out,"%c\tAt date: %s",COMMENTSIGN,timebuf);
-  fprintf (out,"%c\n",COMMENTSIGN);
-}
-
-int gmx_strcasecmp_min(const char *str1, const char *str2)
-{
-  char ch1,ch2;
-  
-  do
-    {
-      do
-       ch1=toupper(*(str1++));
-      while ((ch1=='-') || (ch1=='_'));
-      do 
-       ch2=toupper(*(str2++));
-      while ((ch2=='-') || (ch2=='_'));
-      if (ch1!=ch2) return (ch1-ch2);
-    }
-  while (ch1);
-  return 0; 
-}
-
-int gmx_strncasecmp_min(const char *str1, const char *str2, int n)
-{
-  char ch1,ch2;
-  char *stri1, *stri2;
-
-  stri1=(char *)str1;
-  stri2=(char *)str2;  
-  do
-    {
-      do
-       ch1=toupper(*(str1++));
-      while ((ch1=='-') || (ch1=='_'));
-      do 
-       ch2=toupper(*(str2++));
-      while ((ch2=='-') || (ch2=='_'));
-      if (ch1!=ch2) return (ch1-ch2);
-    }
-  while (ch1 && (str1-stri1<n) && (str2-stri2<n));
-  return 0; 
-}
-
-int gmx_strcasecmp(const char *str1, const char *str2)
-{
-  char ch1,ch2;
-  
-  do
-    {
-      ch1=toupper(*(str1++));
-      ch2=toupper(*(str2++));
-      if (ch1!=ch2) return (ch1-ch2);
-    }
-  while (ch1);
-  return 0; 
-}
-
-int gmx_strncasecmp(const char *str1, const char *str2, int n)
-{
-  char ch1,ch2;
-  if(n==0) 
-    return 0;
-
-  do
-    {
-      ch1=toupper(*(str1++));
-      ch2=toupper(*(str2++));
-      if (ch1!=ch2) return (ch1-ch2);
-      n--;
-    }
-  while (ch1 && n);
-  return 0; 
-}
-
-char *gmx_strdup(const char *src)
-{
-  char *dest;
-
-  snew(dest,strlen(src)+1);
-  strcpy(dest,src);
-  
-  return dest;
-}
-
-char *
-gmx_strndup(const char *src, int n)
-{
-    int   len;
-    char *dest;
-
-    len = strlen(src);
-    if (len > n) 
-    {
-        len = n;
-    }
-    snew(dest, len+1);
-    strncpy(dest, src, len);
-    dest[len] = 0;
-    return dest;
-}
-
-/*!
- * \param[in] pattern  Pattern to match against.
- * \param[in] str      String to match.
- * \returns   0 on match, GMX_NO_WCMATCH if there is no match.
- *
- * Matches \p str against \p pattern, which may contain * and ? wildcards.
- * All other characters are matched literally.
- * Currently, it is not possible to match literal * or ?.
- */
-int
-gmx_wcmatch(const char *pattern, const char *str)
-{
-    while (*pattern)
-    {
-        if (*pattern == '*')
-        {
-            /* Skip multiple wildcards in a sequence */
-            while (*pattern == '*' || *pattern == '?')
-            {
-                ++pattern;
-                /* For ?, we need to check that there are characters left
-                 * in str. */
-                if (*pattern == '?')
-                {
-                    if (*str == 0)
-                    {
-                        return GMX_NO_WCMATCH;
-                    }
-                    else
-                    {
-                        ++str;
-                    }
-                }
-            }
-            /* If the pattern ends after the star, we have a match */
-            if (*pattern == 0)
-            {
-                return 0;
-            }
-            /* Match the rest against each possible suffix of str */
-            while (*str)
-            {
-                /* Only do the recursive call if the first character
-                 * matches. We don't have to worry about wildcards here,
-                 * since we have processed them above. */
-                if (*pattern == *str)
-                {
-                    int rc;
-                    /* Match the suffix, and return if a match or an error */
-                    rc = gmx_wcmatch(pattern, str);
-                    if (rc != GMX_NO_WCMATCH)
-                    {
-                        return rc;
-                    }
-                }
-                ++str;
-            }
-            /* If no suffix of str matches, we don't have a match */
-            return GMX_NO_WCMATCH;
-        }
-        else if ((*pattern == '?' && *str != 0) || *pattern == *str)
-        {
-            ++str;
-        }
-        else
-        {
-            return GMX_NO_WCMATCH;
-        }
-        ++pattern;
-    }
-    /* When the pattern runs out, we have a match if the string has ended. */
-    return (*str == 0) ? 0 : GMX_NO_WCMATCH;
-}
-
-char *wrap_lines(const char *buf,int line_width, int indent,gmx_bool bIndentFirst)
-{
-  char *b2;
-  int i,i0,i2,j,b2len,lspace=0,l2space=0;
-  gmx_bool bFirst,bFitsOnLine;
-
-  /* characters are copied from buf to b2 with possible spaces changed
-   * into newlines and extra space added for indentation.
-   * i indexes buf (source buffer) and i2 indexes b2 (destination buffer)
-   * i0 points to the beginning of the current line (in buf, source)
-   * lspace and l2space point to the last space on the current line
-   * bFirst is set to prevent indentation of first line
-   * bFitsOnLine says if the first space occurred before line_width, if 
-   * that is not the case, we have a word longer than line_width which 
-   * will also not fit on the next line, so we might as well keep it on 
-   * the current line (where it also won't fit, but looks better)
-   */
-  
-  b2=NULL;
-  b2len=strlen(buf)+1+indent;
-  snew(b2,b2len);
-  i0=i2=0;
-  if (bIndentFirst)
-    for(i2=0; (i2<indent); i2++)
-      b2[i2] = ' ';
-  bFirst=TRUE;
-  do {
-    l2space = -1;
-    /* find the last space before end of line */
-    for(i=i0; ((i-i0 < line_width) || (l2space==-1)) && (buf[i]); i++) {
-      b2[i2++] = buf[i];
-      /* remember the position of a space */
-      if (buf[i] == ' ') {
-        lspace = i;
-       l2space = i2-1;
-      }
-      /* if we have a newline before the line is full, reset counters */
-      if (buf[i]=='\n' && buf[i+1]) { 
-       i0=i+1;
-       b2len+=indent;
-       srenew(b2, b2len);
-       /* add indentation after the newline */
-       for(j=0; (j<indent); j++)
-         b2[i2++]=' ';
-      }
-    }
-    /* If we are at the last newline, copy it */
-    if (buf[i]=='\n' && !buf[i+1]) {
-      b2[i2++] = buf[i++];
-    }
-    /* if we're not at the end of the string */
-    if (buf[i]) {
-      /* check if one word does not fit on the line */
-      bFitsOnLine = (i-i0 <= line_width);
-      /* reset line counters to just after the space */
-      i0 = lspace+1;
-      i2 = l2space+1;
-      /* if the words fit on the line, and we're beyond the indentation part */
-      if ( (bFitsOnLine) && (l2space >= indent) ) {
-       /* start a new line */
-       b2[l2space] = '\n';
-       /* and add indentation */
-       if (indent) {
-         if (bFirst) {
-           line_width-=indent;
-           bFirst=FALSE;
-         }
-         b2len+=indent;
-         srenew(b2, b2len);
-         for(j=0; (j<indent); j++)
-           b2[i2++]=' ';
-         /* no extra spaces after indent; */
-         while(buf[i0]==' ')
-           i0++;
-       }
-      }
-    }
-  } while (buf[i]);
-  b2[i2] = '\0';
-  
-  return b2;
-}
-
-char **split(char sep,char *str)
-{
-  char **ptr = NULL;
-  int  n,nn,nptr = 0;
-  
-  if (str == NULL)
-    return NULL;
-  nn = strlen(str);
-  for(n=0; (n<nn); n++)
-    if (str[n] == sep)
-      nptr++;
-  snew(ptr,nptr+2);
-  nptr = 0;
-  while (*str != '\0') {
-    while ((*str != '\0') && (*str == sep))
-      str++;
-    if (*str != '\0') {
-      snew(ptr[nptr],1+strlen(str));
-      n = 0;
-      while ((*str != '\0') && (*str != sep)) {
-       ptr[nptr][n] = *str;
-       str++;
-       n++;
-      }
-      ptr[nptr][n] = '\0';
-      nptr++;
-    }
-  }
-  ptr[nptr] = NULL;
-  
-  return ptr;
-}
-
-
-gmx_large_int_t
-str_to_large_int_t(const char *str, char **endptr)
-{
-       int         sign = 1;
-       gmx_large_int_t  val  = 0;
-       char        ch;
-       const char  *p;
-       
-       p = str;
-       if(p==NULL)
-       {
-               *endptr=NULL;
-               return 0;
-       }
-       
-       /* Strip off initial white space */
-       while(isspace(*p))
-       {
-               p++;
-       }
-       /* Conform to ISO C99 - return original pointer if string does not contain a number */
-       if(*str=='\0')
-       {
-               *endptr=(char *)str;
-       }
-       
-       if(*p=='-')
-       {
-               p++;
-               sign *= -1;
-       }
-       
-       while( ((ch=*p) != '\0') && isdigit(ch) )
-       {
-               /* Important to add sign here, so we dont overflow in final multiplication */
-               ch = (ch-'0')*sign; 
-               val = val*10 + ch;
-               if(ch != val%10) 
-               {
-                       /* Some sort of overflow has occured, set endptr to original string */
-                       *endptr=(char *)str;
-                       errno = ERANGE;
-                       return(0);
-               }
-               p++;
-       }
-       
-       *endptr=(char *)p;
-       
-       return val;
-}
-
-char *gmx_strsep(char **stringp, const char *delim)
-{
-    char *ret;
-    int len=strlen(delim);
-    int i,j=0;
-    int found=0;
-
-    if (! *stringp)
-        return NULL;
-    ret=*stringp;
-    do
-    {
-        if ( (*stringp)[j] == '\0')
-        {
-            found=1;
-            *stringp=NULL;
-            break;
-        }
-        for (i=0;i<len;i++)
-        {
-            if ( (*stringp)[j]==delim[i])
-            {
-                (*stringp)[j]='\0';
-                *stringp=*stringp+j+1;
-                found=1;
-                break;
-            }
-        }
-        j++;
-    } while (!found);
-
-    return ret;
-}
-
diff --git a/src/gmxlib/thread_mpi/Makefile.am b/src/gmxlib/thread_mpi/Makefile.am
deleted file mode 100644 (file)
index 51a7cac..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-# Cross-platform threading library/MPI implementation.
-#
-# This Makefile.am can be used both for linking the final executables against
-# the libthread_mpi.a object created here, or for linking into libraries.
-# 
-
-
-AM_CPPFLAGS= -I$(top_srcdir)/include
-
-noinst_LTLIBRARIES = libthread_mpi.la
-
-# again, we assume that we're using pthreads if we're using autotools.
-libthread_mpi_la_SOURCES = alltoall.c      impl.h          pthreads.h \
-                          barrier.c       list.c          reduce.c \
-                          bcast.c         lock.c          reduce_fast.c \
-                          collective.c    once.c          scatter.c \
-                          collective.h    p2p.h           settings.h \
-                          comm.c          p2p_protocol.c  tmpi_init.c \
-                          errhandler.c    p2p_send_recv.c tmpi_ops.h \
-                          event.c         p2p_wait.c      topology.c \
-                          gather.c        profile.c       type.c \
-                          group.c         profile.h       winthreads.c \
-                          hwinfo.c        pthreads.c      winthreads.h
-
-
-CLEANFILES     = *.la *~ \\\#*
-
diff --git a/src/gmxlib/tpxio.c b/src/gmxlib/tpxio.c
deleted file mode 100644 (file)
index fd30a89..0000000
+++ /dev/null
@@ -1,2426 +0,0 @@
-/* -*- mode: c; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; c-file-style: "stroustrup"; -*-
- *
- * 
- *                This source code is part of
- * 
- *                 G   R   O   M   A   C   S
- * 
- *          GROningen MAchine for Chemical Simulations
- * 
- *                        VERSION 3.2.0
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
- * 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.
-
- * 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:
- * GROningen Mixture of Alchemy and Childrens' Stories
- */
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-/* This file is completely threadsafe - keep it that way! */
-#ifdef GMX_THREADS
-#include <thread_mpi.h>
-#endif
-
-
-#include <ctype.h>
-#include "sysstuff.h"
-#include "smalloc.h"
-#include "string2.h"
-#include "gmx_fatal.h"
-#include "macros.h"
-#include "names.h"
-#include "symtab.h"
-#include "futil.h"
-#include "filenm.h"
-#include "gmxfio.h"
-#include "topsort.h"
-#include "tpxio.h"
-#include "txtdump.h"
-#include "confio.h"
-#include "atomprop.h"
-#include "copyrite.h"
-#include "vec.h"
-#include "mtop_util.h"
-
-/* This number should be increased whenever the file format changes! */
-static const int tpx_version = 73;
-
-/* This number should only be increased when you edit the TOPOLOGY section
- * of the tpx format. This way we can maintain forward compatibility too
- * for all analysis tools and/or external programs that only need to
- * know the atom/residue names, charges, and bond connectivity.
- *  
- * It first appeared in tpx version 26, when I also moved the inputrecord
- * to the end of the tpx file, so we can just skip it if we only
- * want the topology.
- */
-static const int tpx_generation = 23;
-
-/* This number should be the most recent backwards incompatible version 
- * I.e., if this number is 9, we cannot read tpx version 9 with this code.
- */
-static const int tpx_incompatible_version = 9;
-
-
-
-/* Struct used to maintain tpx compatibility when function types are added */
-typedef struct {
-  int fvnr; /* file version number in which the function type first appeared */
-  int ftype; /* function type */
-} t_ftupd;
-
-/* 
- *The entries should be ordered in:
- * 1. ascending file version number
- * 2. ascending function type number
- */
-/*static const t_ftupd ftupd[] = {
-  { 20, F_CUBICBONDS        },
-  { 20, F_CONNBONDS         },
-  { 20, F_HARMONIC          },
-  { 20, F_EQM,              },
-  { 22, F_DISRESVIOL        },
-  { 22, F_ORIRES            },
-  { 22, F_ORIRESDEV         },
-  { 26, F_FOURDIHS          },
-  { 26, F_PIDIHS            },
-  { 26, F_DIHRES            },
-  { 26, F_DIHRESVIOL        },
-  { 30, F_CROSS_BOND_BONDS  },
-  { 30, F_CROSS_BOND_ANGLES },
-  { 30, F_UREY_BRADLEY      },
-  { 30, F_POLARIZATION      }
-  };*/
-  
-/* 
- *The entries should be ordered in:
- * 1. ascending function type number
- * 2. ascending file version number
- */
-static const t_ftupd ftupd[] = {
-  { 20, F_CUBICBONDS        },
-  { 20, F_CONNBONDS         },
-  { 20, F_HARMONIC          },
-  { 34, F_FENEBONDS         },
-  { 43, F_TABBONDS          },
-  { 43, F_TABBONDSNC        },
-  { 70, F_RESTRBONDS        },
-  { 30, F_CROSS_BOND_BONDS  },
-  { 30, F_CROSS_BOND_ANGLES },
-  { 30, F_UREY_BRADLEY      },
-  { 34, F_QUARTIC_ANGLES    },
-  { 43, F_TABANGLES         },
-  { 26, F_FOURDIHS          },
-  { 26, F_PIDIHS            },
-  { 43, F_TABDIHS           },
-  { 65, F_CMAP              },
-  { 60, F_GB12              },
-  { 61, F_GB13              },
-  { 61, F_GB14              }, 
-  { 72, F_GBPOL             },
-  { 72, F_NPSOLVATION       },
-  { 41, F_LJC14_Q           },
-  { 41, F_LJC_PAIRS_NB      },
-  { 32, F_BHAM_LR           },
-  { 32, F_RF_EXCL           },
-  { 32, F_COUL_RECIP        },
-  { 46, F_DPD               },
-  { 30, F_POLARIZATION      },
-  { 36, F_THOLE_POL         },
-  { 22, F_DISRESVIOL        },
-  { 22, F_ORIRES            },
-  { 22, F_ORIRESDEV         },
-  { 26, F_DIHRES            },
-  { 26, F_DIHRESVIOL        },
-  { 49, F_VSITE4FDN         },
-  { 50, F_VSITEN            },
-  { 46, F_COM_PULL          },
-  { 20, F_EQM               },
-  { 46, F_ECONSERVED        },
-  { 69, F_VTEMP             },
-  { 66, F_PDISPCORR         },
-  { 54, F_DHDL_CON          },
-};
-#define NFTUPD asize(ftupd)
-
-/* Needed for backward compatibility */
-#define MAXNODES 256
-
-static void _do_section(t_fileio *fio,int key,gmx_bool bRead,const char *src,
-                        int line)
-{
-  char buf[STRLEN];
-  gmx_bool bDbg;
-
-  if (gmx_fio_getftp(fio) == efTPA) {
-    if (!bRead) {
-      gmx_fio_write_string(fio,itemstr[key]);
-      bDbg       = gmx_fio_getdebug(fio);
-      gmx_fio_setdebug(fio,FALSE);
-      gmx_fio_write_string(fio,comment_str[key]);
-      gmx_fio_setdebug(fio,bDbg);
-    }
-    else {
-      if (gmx_fio_getdebug(fio))
-       fprintf(stderr,"Looking for section %s (%s, %d)",
-               itemstr[key],src,line);
-      
-      do {
-       gmx_fio_do_string(fio,buf);
-      } while ((gmx_strcasecmp(buf,itemstr[key]) != 0));
-      
-      if (gmx_strcasecmp(buf,itemstr[key]) != 0) 
-       gmx_fatal(FARGS,"\nCould not find section heading %s",itemstr[key]);
-      else if (gmx_fio_getdebug(fio))
-       fprintf(stderr," and found it\n");
-    }
-  }
-}
-
-#define do_section(fio,key,bRead) _do_section(fio,key,bRead,__FILE__,__LINE__)
-
-/**************************************************************
- *
- * Now the higer level routines that do io of the structures and arrays
- *
- **************************************************************/
-static void do_pullgrp(t_fileio *fio, t_pullgrp *pgrp, gmx_bool bRead, 
-                       int file_version)
-{
-  gmx_bool bDum=TRUE;
-  int  i;
-
-  gmx_fio_do_int(fio,pgrp->nat);
-  if (bRead)
-    snew(pgrp->ind,pgrp->nat);
-  bDum=gmx_fio_ndo_int(fio,pgrp->ind,pgrp->nat);
-  gmx_fio_do_int(fio,pgrp->nweight);
-  if (bRead)
-    snew(pgrp->weight,pgrp->nweight);
-  bDum=gmx_fio_ndo_real(fio,pgrp->weight,pgrp->nweight);
-  gmx_fio_do_int(fio,pgrp->pbcatom);
-  gmx_fio_do_rvec(fio,pgrp->vec);
-  gmx_fio_do_rvec(fio,pgrp->init);
-  gmx_fio_do_real(fio,pgrp->rate);
-  gmx_fio_do_real(fio,pgrp->k);
-  if (file_version >= 56) {
-    gmx_fio_do_real(fio,pgrp->kB);
-  } else {
-    pgrp->kB = pgrp->k;
-  }
-}
-
-static void do_pull(t_fileio *fio, t_pull *pull,gmx_bool bRead, int file_version)
-{
-  int g;
-
-  gmx_fio_do_int(fio,pull->ngrp);
-  gmx_fio_do_int(fio,pull->eGeom);
-  gmx_fio_do_ivec(fio,pull->dim);
-  gmx_fio_do_real(fio,pull->cyl_r1);
-  gmx_fio_do_real(fio,pull->cyl_r0);
-  gmx_fio_do_real(fio,pull->constr_tol);
-  gmx_fio_do_int(fio,pull->nstxout);
-  gmx_fio_do_int(fio,pull->nstfout);
-  if (bRead)
-    snew(pull->grp,pull->ngrp+1);
-  for(g=0; g<pull->ngrp+1; g++)
-    do_pullgrp(fio,&pull->grp[g],bRead,file_version);
-}
-
-static void do_inputrec(t_fileio *fio, t_inputrec *ir,gmx_bool bRead, 
-                        int file_version, real *fudgeQQ)
-{
-    int  i,j,k,*tmp,idum=0; 
-    gmx_bool bDum=TRUE;
-    real rdum,bd_temp;
-    rvec vdum;
-    gmx_bool bSimAnn;
-    real zerotemptime,finish_t,init_temp,finish_temp;
-    
-    if (file_version != tpx_version)
-    {
-        /* Give a warning about features that are not accessible */
-        fprintf(stderr,"Note: tpx file_version %d, software version %d\n",
-                file_version,tpx_version);
-    }
-
-    if (bRead)
-    {
-        init_inputrec(ir);
-    }
-
-    if (file_version == 0)
-    {
-        return;
-    }
-
-    /* Basic inputrec stuff */  
-    gmx_fio_do_int(fio,ir->eI); 
-    if (file_version >= 62) {
-      gmx_fio_do_gmx_large_int(fio, ir->nsteps);
-    } else {
-      gmx_fio_do_int(fio,idum);
-      ir->nsteps = idum;
-    }
-    if(file_version > 25) {
-      if (file_version >= 62) {
-       gmx_fio_do_gmx_large_int(fio, ir->init_step);
-      } else {
-       gmx_fio_do_int(fio,idum);
-       ir->init_step = idum;
-      }
-    }  else {
-      ir->init_step=0;
-    }
-
-       if(file_version >= 58)
-         gmx_fio_do_int(fio,ir->simulation_part);
-       else
-         ir->simulation_part=1;
-         
-    if (file_version >= 67) {
-      gmx_fio_do_int(fio,ir->nstcalcenergy);
-    } else {
-      ir->nstcalcenergy = 1;
-    }
-    if (file_version < 53) {
-      /* The pbc info has been moved out of do_inputrec,
-       * since we always want it, also without reading the inputrec.
-       */
-      gmx_fio_do_int(fio,ir->ePBC);
-      if ((file_version <= 15) && (ir->ePBC == 2))
-       ir->ePBC = epbcNONE;
-      if (file_version >= 45) {
-       gmx_fio_do_int(fio,ir->bPeriodicMols);
-      } else {
-       if (ir->ePBC == 2) {
-         ir->ePBC = epbcXYZ;
-         ir->bPeriodicMols = TRUE;
-       } else {
-       ir->bPeriodicMols = FALSE;
-       }
-      }
-    }
-    gmx_fio_do_int(fio,ir->ns_type);
-    gmx_fio_do_int(fio,ir->nstlist);
-    gmx_fio_do_int(fio,ir->ndelta);
-    if (file_version < 41) {
-      gmx_fio_do_int(fio,idum);
-      gmx_fio_do_int(fio,idum);
-    }
-    if (file_version >= 45)
-      gmx_fio_do_real(fio,ir->rtpi);
-    else
-      ir->rtpi = 0.05;
-    gmx_fio_do_int(fio,ir->nstcomm); 
-    if (file_version > 34)
-      gmx_fio_do_int(fio,ir->comm_mode);
-    else if (ir->nstcomm < 0) 
-      ir->comm_mode = ecmANGULAR;
-    else
-      ir->comm_mode = ecmLINEAR;
-    ir->nstcomm = abs(ir->nstcomm);
-    
-    if(file_version > 25)
-      gmx_fio_do_int(fio,ir->nstcheckpoint);
-    else
-      ir->nstcheckpoint=0;
-    
-    gmx_fio_do_int(fio,ir->nstcgsteep); 
-
-    if(file_version>=30)
-      gmx_fio_do_int(fio,ir->nbfgscorr); 
-    else if (bRead)
-      ir->nbfgscorr = 10;
-
-    gmx_fio_do_int(fio,ir->nstlog); 
-    gmx_fio_do_int(fio,ir->nstxout); 
-    gmx_fio_do_int(fio,ir->nstvout); 
-    gmx_fio_do_int(fio,ir->nstfout); 
-    gmx_fio_do_int(fio,ir->nstenergy); 
-    gmx_fio_do_int(fio,ir->nstxtcout); 
-    if (file_version >= 59) {
-      gmx_fio_do_double(fio,ir->init_t);
-      gmx_fio_do_double(fio,ir->delta_t);
-    } else {
-      gmx_fio_do_real(fio,rdum);
-      ir->init_t = rdum;
-      gmx_fio_do_real(fio,rdum);
-      ir->delta_t = rdum;
-    }
-    gmx_fio_do_real(fio,ir->xtcprec); 
-    if (file_version < 19) {
-      gmx_fio_do_int(fio,idum); 
-      gmx_fio_do_int(fio,idum);
-    }
-    if(file_version < 18)
-      gmx_fio_do_int(fio,idum); 
-    gmx_fio_do_real(fio,ir->rlist); 
-    if (file_version >= 67) {
-      gmx_fio_do_real(fio,ir->rlistlong);
-    }
-    gmx_fio_do_int(fio,ir->coulombtype); 
-    if (file_version < 32 && ir->coulombtype == eelRF)
-      ir->coulombtype = eelRF_NEC;      
-    gmx_fio_do_real(fio,ir->rcoulomb_switch); 
-    gmx_fio_do_real(fio,ir->rcoulomb); 
-    gmx_fio_do_int(fio,ir->vdwtype);
-    gmx_fio_do_real(fio,ir->rvdw_switch); 
-    gmx_fio_do_real(fio,ir->rvdw); 
-    if (file_version < 67) {
-      ir->rlistlong = max_cutoff(ir->rlist,max_cutoff(ir->rvdw,ir->rcoulomb));
-    }
-    gmx_fio_do_int(fio,ir->eDispCorr); 
-    gmx_fio_do_real(fio,ir->epsilon_r);
-    if (file_version >= 37) {
-      gmx_fio_do_real(fio,ir->epsilon_rf);
-    } else {
-      if (EEL_RF(ir->coulombtype)) {
-       ir->epsilon_rf = ir->epsilon_r;
-       ir->epsilon_r  = 1.0;
-      } else {
-       ir->epsilon_rf = 1.0;
-      }
-    }
-    if (file_version >= 29)
-      gmx_fio_do_real(fio,ir->tabext);
-    else
-      ir->tabext=1.0;
-    if(file_version > 25) {
-      gmx_fio_do_int(fio,ir->gb_algorithm);
-      gmx_fio_do_int(fio,ir->nstgbradii);
-      gmx_fio_do_real(fio,ir->rgbradii);
-      gmx_fio_do_real(fio,ir->gb_saltconc);
-      gmx_fio_do_int(fio,ir->implicit_solvent);
-    } else {
-      ir->gb_algorithm=egbSTILL;
-      ir->nstgbradii=1;
-      ir->rgbradii=1.0;
-      ir->gb_saltconc=0;
-      ir->implicit_solvent=eisNO;
-    }
-       if(file_version>=55)
-       {
-               gmx_fio_do_real(fio,ir->gb_epsilon_solvent);
-               gmx_fio_do_real(fio,ir->gb_obc_alpha);
-               gmx_fio_do_real(fio,ir->gb_obc_beta);
-               gmx_fio_do_real(fio,ir->gb_obc_gamma);
-               if(file_version>=60)
-               {
-                       gmx_fio_do_real(fio,ir->gb_dielectric_offset);
-                       gmx_fio_do_int(fio,ir->sa_algorithm);
-               }
-               else
-               {
-                       ir->gb_dielectric_offset = 0.009;
-                       ir->sa_algorithm = esaAPPROX;
-               }
-               gmx_fio_do_real(fio,ir->sa_surface_tension);
-
-    /* Override sa_surface_tension if it is not changed in the mpd-file */
-    if(ir->sa_surface_tension<0)
-    {
-      if(ir->gb_algorithm==egbSTILL)
-      {
-        ir->sa_surface_tension = 0.0049 * 100 * CAL2JOULE;
-      }
-      else if(ir->gb_algorithm==egbHCT || ir->gb_algorithm==egbOBC)
-      {
-        ir->sa_surface_tension = 0.0054 * 100 * CAL2JOULE;
-      }
-    }
-    
-       }
-       else
-       {
-               /* Better use sensible values than insane (0.0) ones... */
-               ir->gb_epsilon_solvent = 80;
-               ir->gb_obc_alpha       = 1.0;
-               ir->gb_obc_beta        = 0.8;
-               ir->gb_obc_gamma       = 4.85;
-               ir->sa_surface_tension = 2.092;
-       }
-
-         
-    gmx_fio_do_int(fio,ir->nkx); 
-    gmx_fio_do_int(fio,ir->nky); 
-    gmx_fio_do_int(fio,ir->nkz);
-    gmx_fio_do_int(fio,ir->pme_order);
-    gmx_fio_do_real(fio,ir->ewald_rtol);
-
-    if (file_version >=24) 
-      gmx_fio_do_int(fio,ir->ewald_geometry);
-    else
-      ir->ewald_geometry=eewg3D;
-
-    if (file_version <=17) {
-      ir->epsilon_surface=0;
-      if (file_version==17)
-       gmx_fio_do_int(fio,idum);
-    } 
-    else
-      gmx_fio_do_real(fio,ir->epsilon_surface);
-    
-    gmx_fio_do_gmx_bool(fio,ir->bOptFFT);
-
-    gmx_fio_do_gmx_bool(fio,ir->bContinuation); 
-    gmx_fio_do_int(fio,ir->etc);
-    /* before version 18, ir->etc was a gmx_bool (ir->btc),
-     * but the values 0 and 1 still mean no and
-     * berendsen temperature coupling, respectively.
-     */
-    if (file_version >= 71)
-    {
-        gmx_fio_do_int(fio,ir->nsttcouple);
-    }
-    else
-    {
-        ir->nsttcouple = ir->nstcalcenergy;
-    }
-    if (file_version <= 15)
-    {
-        gmx_fio_do_int(fio,idum);
-    }
-    if (file_version <=17)
-    {
-        gmx_fio_do_int(fio,ir->epct); 
-        if (file_version <= 15)
-        {
-            if (ir->epct == 5)
-            {
-                ir->epct = epctSURFACETENSION;
-            }
-            gmx_fio_do_int(fio,idum);
-        }
-        ir->epct -= 1;
-        /* we have removed the NO alternative at the beginning */
-        if(ir->epct==-1)
-        {
-            ir->epc=epcNO;
-            ir->epct=epctISOTROPIC;
-        } 
-        else
-        {
-            ir->epc=epcBERENDSEN;
-        }
-    } 
-    else
-    {
-        gmx_fio_do_int(fio,ir->epc);
-        gmx_fio_do_int(fio,ir->epct);
-    }
-    if (file_version >= 71)
-    {
-        gmx_fio_do_int(fio,ir->nstpcouple);
-    }
-    else
-    {
-        ir->nstpcouple = ir->nstcalcenergy;
-    }
-    gmx_fio_do_real(fio,ir->tau_p); 
-    if (file_version <= 15) {
-      gmx_fio_do_rvec(fio,vdum);
-      clear_mat(ir->ref_p);
-      for(i=0; i<DIM; i++)
-       ir->ref_p[i][i] = vdum[i];
-    } else {
-      gmx_fio_do_rvec(fio,ir->ref_p[XX]);
-      gmx_fio_do_rvec(fio,ir->ref_p[YY]);
-      gmx_fio_do_rvec(fio,ir->ref_p[ZZ]);
-    }
-    if (file_version <= 15) {
-      gmx_fio_do_rvec(fio,vdum);
-      clear_mat(ir->compress);
-      for(i=0; i<DIM; i++)
-       ir->compress[i][i] = vdum[i];
-    } 
-    else {
-      gmx_fio_do_rvec(fio,ir->compress[XX]);
-      gmx_fio_do_rvec(fio,ir->compress[YY]);
-      gmx_fio_do_rvec(fio,ir->compress[ZZ]);
-    }
-    if (file_version >= 47) {
-      gmx_fio_do_int(fio,ir->refcoord_scaling);
-      gmx_fio_do_rvec(fio,ir->posres_com);
-      gmx_fio_do_rvec(fio,ir->posres_comB);
-    } else {
-      ir->refcoord_scaling = erscNO;
-      clear_rvec(ir->posres_com);
-      clear_rvec(ir->posres_comB);
-    }
-    if(file_version > 25)
-      gmx_fio_do_int(fio,ir->andersen_seed);
-    else
-      ir->andersen_seed=0;
-    
-    if(file_version < 26) {
-      gmx_fio_do_gmx_bool(fio,bSimAnn); 
-      gmx_fio_do_real(fio,zerotemptime);
-    }
-    
-    if (file_version < 37)
-      gmx_fio_do_real(fio,rdum); 
-
-    gmx_fio_do_real(fio,ir->shake_tol);
-    if (file_version < 54)
-      gmx_fio_do_real(fio,*fudgeQQ);
-    gmx_fio_do_int(fio,ir->efep);
-    if (file_version <= 14 && ir->efep > efepNO)
-      ir->efep = efepYES;
-    if (file_version >= 59) {
-      gmx_fio_do_double(fio, ir->init_lambda); 
-      gmx_fio_do_double(fio, ir->delta_lambda);
-    } else {
-      gmx_fio_do_real(fio,rdum);
-      ir->init_lambda = rdum;
-      gmx_fio_do_real(fio,rdum);
-      ir->delta_lambda = rdum;
-    }
-    if (file_version >= 64) {
-      gmx_fio_do_int(fio,ir->n_flambda);
-      if (bRead) {
-       snew(ir->flambda,ir->n_flambda);
-      }
-      bDum=gmx_fio_ndo_double(fio,ir->flambda,ir->n_flambda);
-    } else {
-      ir->n_flambda = 0;
-      ir->flambda   = NULL;
-    }
-    if (file_version >= 13)
-      gmx_fio_do_real(fio,ir->sc_alpha);
-    else
-      ir->sc_alpha = 0;
-    if (file_version >= 38)
-      gmx_fio_do_int(fio,ir->sc_power);
-    else
-      ir->sc_power = 2;
-    if (file_version >= 15)
-      gmx_fio_do_real(fio,ir->sc_sigma);
-    else
-      ir->sc_sigma = 0.3;
-    if (bRead)
-    {
-        if (file_version >= 71)
-        {
-            ir->sc_sigma_min = ir->sc_sigma;
-        }
-        else
-        {
-            ir->sc_sigma_min = 0;
-        }
-    }
-    if (file_version >= 64) {
-      gmx_fio_do_int(fio,ir->nstdhdl);
-    } else {
-      ir->nstdhdl = 1;
-    }
-
-    if (file_version >= 73)
-    {
-        gmx_fio_do_int(fio, ir->separate_dhdl_file);
-        gmx_fio_do_int(fio, ir->dhdl_derivatives);
-    }
-    else
-    {
-        ir->separate_dhdl_file = sepdhdlfileYES;
-        ir->dhdl_derivatives = dhdlderivativesYES;
-    }
-
-    if (file_version >= 71)
-    {
-        gmx_fio_do_int(fio,ir->dh_hist_size);
-        gmx_fio_do_double(fio,ir->dh_hist_spacing);
-    }
-    else
-    {
-        ir->dh_hist_size    = 0;
-        ir->dh_hist_spacing = 0.1;
-    }
-    if (file_version >= 57) {
-      gmx_fio_do_int(fio,ir->eDisre); 
-    }
-    gmx_fio_do_int(fio,ir->eDisreWeighting); 
-    if (file_version < 22) {
-      if (ir->eDisreWeighting == 0)
-       ir->eDisreWeighting = edrwEqual;
-      else
-       ir->eDisreWeighting = edrwConservative;
-    }
-    gmx_fio_do_gmx_bool(fio,ir->bDisreMixed); 
-    gmx_fio_do_real(fio,ir->dr_fc); 
-    gmx_fio_do_real(fio,ir->dr_tau); 
-    gmx_fio_do_int(fio,ir->nstdisreout);
-    if (file_version >= 22) {
-      gmx_fio_do_real(fio,ir->orires_fc);
-      gmx_fio_do_real(fio,ir->orires_tau);
-      gmx_fio_do_int(fio,ir->nstorireout);
-    } else {
-      ir->orires_fc = 0;
-      ir->orires_tau = 0;
-      ir->nstorireout = 0;
-    }
-    if(file_version >= 26) {
-      gmx_fio_do_real(fio,ir->dihre_fc);
-      if (file_version < 56) {
-       gmx_fio_do_real(fio,rdum);
-       gmx_fio_do_int(fio,idum);
-      }
-    } else {
-      ir->dihre_fc=0;
-    }
-
-    gmx_fio_do_real(fio,ir->em_stepsize); 
-    gmx_fio_do_real(fio,ir->em_tol); 
-    if (file_version >= 22) 
-      gmx_fio_do_gmx_bool(fio,ir->bShakeSOR);
-    else if (bRead)
-      ir->bShakeSOR = TRUE;
-    if (file_version >= 11)
-      gmx_fio_do_int(fio,ir->niter);
-    else if (bRead) {
-      ir->niter = 25;
-      fprintf(stderr,"Note: niter not in run input file, setting it to %d\n",
-             ir->niter);
-    }
-    if (file_version >= 21)
-      gmx_fio_do_real(fio,ir->fc_stepsize);
-    else
-      ir->fc_stepsize = 0;
-    gmx_fio_do_int(fio,ir->eConstrAlg);
-    gmx_fio_do_int(fio,ir->nProjOrder);
-    gmx_fio_do_real(fio,ir->LincsWarnAngle);
-    if (file_version <= 14)
-      gmx_fio_do_int(fio,idum);
-    if (file_version >=26)
-      gmx_fio_do_int(fio,ir->nLincsIter);
-    else if (bRead) {
-      ir->nLincsIter = 1;
-      fprintf(stderr,"Note: nLincsIter not in run input file, setting it to %d\n",
-             ir->nLincsIter);
-    }
-    if (file_version < 33)
-      gmx_fio_do_real(fio,bd_temp);
-    gmx_fio_do_real(fio,ir->bd_fric);
-    gmx_fio_do_int(fio,ir->ld_seed);
-    if (file_version >= 33) {
-      for(i=0; i<DIM; i++)
-       gmx_fio_do_rvec(fio,ir->deform[i]);
-    } else {
-      for(i=0; i<DIM; i++)
-       clear_rvec(ir->deform[i]);
-    }
-    if (file_version >= 14)
-      gmx_fio_do_real(fio,ir->cos_accel);
-    else if (bRead)
-      ir->cos_accel = 0;
-    gmx_fio_do_int(fio,ir->userint1); 
-    gmx_fio_do_int(fio,ir->userint2); 
-    gmx_fio_do_int(fio,ir->userint3); 
-    gmx_fio_do_int(fio,ir->userint4); 
-    gmx_fio_do_real(fio,ir->userreal1); 
-    gmx_fio_do_real(fio,ir->userreal2); 
-    gmx_fio_do_real(fio,ir->userreal3); 
-    gmx_fio_do_real(fio,ir->userreal4); 
-    
-    /* pull stuff */
-    if (file_version >= 48) {
-      gmx_fio_do_int(fio,ir->ePull);
-      if (ir->ePull != epullNO) {
-       if (bRead)
-         snew(ir->pull,1);
-       do_pull(fio, ir->pull,bRead,file_version);
-      }
-    } else {
-      ir->ePull = epullNO;
-    }
-    
-    /* grpopts stuff */
-    gmx_fio_do_int(fio,ir->opts.ngtc); 
-    if (file_version >= 69) {
-      gmx_fio_do_int(fio,ir->opts.nhchainlength);
-    } else {
-      ir->opts.nhchainlength = 1;
-    }
-    gmx_fio_do_int(fio,ir->opts.ngacc); 
-    gmx_fio_do_int(fio,ir->opts.ngfrz); 
-    gmx_fio_do_int(fio,ir->opts.ngener);
-    
-    if (bRead) {
-      snew(ir->opts.nrdf,   ir->opts.ngtc); 
-      snew(ir->opts.ref_t,  ir->opts.ngtc); 
-      snew(ir->opts.annealing, ir->opts.ngtc); 
-      snew(ir->opts.anneal_npoints, ir->opts.ngtc); 
-      snew(ir->opts.anneal_time, ir->opts.ngtc); 
-      snew(ir->opts.anneal_temp, ir->opts.ngtc); 
-      snew(ir->opts.tau_t,  ir->opts.ngtc); 
-      snew(ir->opts.nFreeze,ir->opts.ngfrz); 
-      snew(ir->opts.acc,    ir->opts.ngacc); 
-      snew(ir->opts.egp_flags,ir->opts.ngener*ir->opts.ngener);
-    } 
-    if (ir->opts.ngtc > 0) {
-      if (bRead && file_version<13) {
-       snew(tmp,ir->opts.ngtc);
-       bDum=gmx_fio_ndo_int(fio,tmp, ir->opts.ngtc);
-       for(i=0; i<ir->opts.ngtc; i++)
-         ir->opts.nrdf[i] = tmp[i];
-       sfree(tmp);
-      } else {
-       bDum=gmx_fio_ndo_real(fio,ir->opts.nrdf, ir->opts.ngtc);
-      }
-      bDum=gmx_fio_ndo_real(fio,ir->opts.ref_t,ir->opts.ngtc); 
-      bDum=gmx_fio_ndo_real(fio,ir->opts.tau_t,ir->opts.ngtc); 
-      if (file_version<33 && ir->eI==eiBD) {
-       for(i=0; i<ir->opts.ngtc; i++)
-         ir->opts.tau_t[i] = bd_temp;
-      }
-    }
-    if (ir->opts.ngfrz > 0) 
-      bDum=gmx_fio_ndo_ivec(fio,ir->opts.nFreeze,ir->opts.ngfrz);
-    if (ir->opts.ngacc > 0) 
-      gmx_fio_ndo_rvec(fio,ir->opts.acc,ir->opts.ngacc); 
-    if (file_version >= 12)
-      bDum=gmx_fio_ndo_int(fio,ir->opts.egp_flags,
-                           ir->opts.ngener*ir->opts.ngener);
-
-    if(bRead && file_version < 26) {
-      for(i=0;i<ir->opts.ngtc;i++) {
-       if(bSimAnn) {
-         ir->opts.annealing[i] = eannSINGLE;
-         ir->opts.anneal_npoints[i] = 2;
-         snew(ir->opts.anneal_time[i],2);
-         snew(ir->opts.anneal_temp[i],2);
-         /* calculate the starting/ending temperatures from reft, zerotemptime, and nsteps */
-         finish_t = ir->init_t + ir->nsteps * ir->delta_t;
-         init_temp = ir->opts.ref_t[i]*(1-ir->init_t/zerotemptime);
-         finish_temp = ir->opts.ref_t[i]*(1-finish_t/zerotemptime);
-         ir->opts.anneal_time[i][0] = ir->init_t;
-         ir->opts.anneal_time[i][1] = finish_t;
-         ir->opts.anneal_temp[i][0] = init_temp;
-         ir->opts.anneal_temp[i][1] = finish_temp;
-       } else {
-         ir->opts.annealing[i] = eannNO;
-         ir->opts.anneal_npoints[i] = 0;
-       }
-      }
-    } else {
-      /* file version 26 or later */
-      /* First read the lists with annealing and npoints for each group */
-      bDum=gmx_fio_ndo_int(fio,ir->opts.annealing,ir->opts.ngtc);
-      bDum=gmx_fio_ndo_int(fio,ir->opts.anneal_npoints,ir->opts.ngtc);
-      for(j=0;j<(ir->opts.ngtc);j++) {
-       k=ir->opts.anneal_npoints[j];
-       if(bRead) {
-         snew(ir->opts.anneal_time[j],k);
-         snew(ir->opts.anneal_temp[j],k);
-       }
-       bDum=gmx_fio_ndo_real(fio,ir->opts.anneal_time[j],k);
-       bDum=gmx_fio_ndo_real(fio,ir->opts.anneal_temp[j],k);
-      }
-    }
-    /* Walls */
-    if (file_version >= 45) {
-      gmx_fio_do_int(fio,ir->nwall);
-      gmx_fio_do_int(fio,ir->wall_type);
-      if (file_version >= 50)
-       gmx_fio_do_real(fio,ir->wall_r_linpot);
-      else
-       ir->wall_r_linpot = -1;
-      gmx_fio_do_int(fio,ir->wall_atomtype[0]);
-      gmx_fio_do_int(fio,ir->wall_atomtype[1]);
-      gmx_fio_do_real(fio,ir->wall_density[0]);
-      gmx_fio_do_real(fio,ir->wall_density[1]);
-      gmx_fio_do_real(fio,ir->wall_ewald_zfac);
-    } else {
-      ir->nwall = 0;
-      ir->wall_type = 0;
-      ir->wall_atomtype[0] = -1;
-      ir->wall_atomtype[1] = -1;
-      ir->wall_density[0] = 0;
-      ir->wall_density[1] = 0;
-      ir->wall_ewald_zfac = 3;
-    }
-    /* Cosine stuff for electric fields */
-    for(j=0; (j<DIM); j++) {
-      gmx_fio_do_int(fio,ir->ex[j].n);
-      gmx_fio_do_int(fio,ir->et[j].n);
-      if (bRead) {
-       snew(ir->ex[j].a,  ir->ex[j].n);
-       snew(ir->ex[j].phi,ir->ex[j].n);
-       snew(ir->et[j].a,  ir->et[j].n);
-       snew(ir->et[j].phi,ir->et[j].n);
-      }
-      bDum=gmx_fio_ndo_real(fio,ir->ex[j].a,  ir->ex[j].n);
-      bDum=gmx_fio_ndo_real(fio,ir->ex[j].phi,ir->ex[j].n);
-      bDum=gmx_fio_ndo_real(fio,ir->et[j].a,  ir->et[j].n);
-      bDum=gmx_fio_ndo_real(fio,ir->et[j].phi,ir->et[j].n);
-    }
-    
-    /* QMMM stuff */
-    if(file_version>=39){
-      gmx_fio_do_gmx_bool(fio,ir->bQMMM);
-      gmx_fio_do_int(fio,ir->QMMMscheme);
-      gmx_fio_do_real(fio,ir->scalefactor);
-      gmx_fio_do_int(fio,ir->opts.ngQM);
-      if (bRead) {
-        snew(ir->opts.QMmethod,    ir->opts.ngQM);
-        snew(ir->opts.QMbasis,     ir->opts.ngQM);
-        snew(ir->opts.QMcharge,    ir->opts.ngQM);
-        snew(ir->opts.QMmult,      ir->opts.ngQM);
-        snew(ir->opts.bSH,         ir->opts.ngQM);
-        snew(ir->opts.CASorbitals, ir->opts.ngQM);
-        snew(ir->opts.CASelectrons,ir->opts.ngQM);
-        snew(ir->opts.SAon,        ir->opts.ngQM);
-        snew(ir->opts.SAoff,       ir->opts.ngQM);
-        snew(ir->opts.SAsteps,     ir->opts.ngQM);
-        snew(ir->opts.bOPT,        ir->opts.ngQM);
-        snew(ir->opts.bTS,         ir->opts.ngQM);
-      }
-      if (ir->opts.ngQM > 0) {
-        bDum=gmx_fio_ndo_int(fio,ir->opts.QMmethod,ir->opts.ngQM);
-        bDum=gmx_fio_ndo_int(fio,ir->opts.QMbasis,ir->opts.ngQM);
-        bDum=gmx_fio_ndo_int(fio,ir->opts.QMcharge,ir->opts.ngQM);
-        bDum=gmx_fio_ndo_int(fio,ir->opts.QMmult,ir->opts.ngQM);
-        bDum=gmx_fio_ndo_gmx_bool(fio,ir->opts.bSH,ir->opts.ngQM);
-        bDum=gmx_fio_ndo_int(fio,ir->opts.CASorbitals,ir->opts.ngQM);
-        bDum=gmx_fio_ndo_int(fio,ir->opts.CASelectrons,ir->opts.ngQM);
-        bDum=gmx_fio_ndo_real(fio,ir->opts.SAon,ir->opts.ngQM);
-        bDum=gmx_fio_ndo_real(fio,ir->opts.SAoff,ir->opts.ngQM);
-        bDum=gmx_fio_ndo_int(fio,ir->opts.SAsteps,ir->opts.ngQM);
-        bDum=gmx_fio_ndo_gmx_bool(fio,ir->opts.bOPT,ir->opts.ngQM);
-        bDum=gmx_fio_ndo_gmx_bool(fio,ir->opts.bTS,ir->opts.ngQM);
-      }
-      /* end of QMMM stuff */
-    }    
-}
-
-
-static void do_harm(t_fileio *fio, t_iparams *iparams,gmx_bool bRead)
-{
-  gmx_fio_do_real(fio,iparams->harmonic.rA);
-  gmx_fio_do_real(fio,iparams->harmonic.krA);
-  gmx_fio_do_real(fio,iparams->harmonic.rB);
-  gmx_fio_do_real(fio,iparams->harmonic.krB);
-}
-
-void do_iparams(t_fileio *fio, t_functype ftype,t_iparams *iparams,
-                gmx_bool bRead, int file_version)
-{
-  int i;
-  gmx_bool bDum;
-  real rdum;
-  
-  if (!bRead)
-    gmx_fio_set_comment(fio, interaction_function[ftype].name);
-  switch (ftype) {
-  case F_ANGLES:
-  case F_G96ANGLES:
-  case F_BONDS:
-  case F_G96BONDS:
-  case F_HARMONIC:
-  case F_IDIHS:
-    do_harm(fio, iparams,bRead);
-    if ((ftype == F_ANGRES || ftype == F_ANGRESZ) && bRead) {
-      /* Correct incorrect storage of parameters */
-      iparams->pdihs.phiB = iparams->pdihs.phiA;
-      iparams->pdihs.cpB  = iparams->pdihs.cpA;
-    }
-    break;
-  case F_FENEBONDS:
-    gmx_fio_do_real(fio,iparams->fene.bm);
-    gmx_fio_do_real(fio,iparams->fene.kb);
-    break;
-  case F_RESTRBONDS:
-    gmx_fio_do_real(fio,iparams->restraint.lowA);
-    gmx_fio_do_real(fio,iparams->restraint.up1A);
-    gmx_fio_do_real(fio,iparams->restraint.up2A);
-    gmx_fio_do_real(fio,iparams->restraint.kA);
-    gmx_fio_do_real(fio,iparams->restraint.lowB);
-    gmx_fio_do_real(fio,iparams->restraint.up1B);
-    gmx_fio_do_real(fio,iparams->restraint.up2B);
-    gmx_fio_do_real(fio,iparams->restraint.kB);
-    break;
-  case F_TABBONDS:
-  case F_TABBONDSNC:
-  case F_TABANGLES:
-  case F_TABDIHS:
-    gmx_fio_do_real(fio,iparams->tab.kA);
-    gmx_fio_do_int(fio,iparams->tab.table);
-    gmx_fio_do_real(fio,iparams->tab.kB);
-    break;
-  case F_CROSS_BOND_BONDS:
-    gmx_fio_do_real(fio,iparams->cross_bb.r1e);
-    gmx_fio_do_real(fio,iparams->cross_bb.r2e);
-    gmx_fio_do_real(fio,iparams->cross_bb.krr);
-    break;
-  case F_CROSS_BOND_ANGLES:
-    gmx_fio_do_real(fio,iparams->cross_ba.r1e);
-    gmx_fio_do_real(fio,iparams->cross_ba.r2e);
-    gmx_fio_do_real(fio,iparams->cross_ba.r3e);
-    gmx_fio_do_real(fio,iparams->cross_ba.krt);
-    break;
-  case F_UREY_BRADLEY:
-    gmx_fio_do_real(fio,iparams->u_b.theta);
-    gmx_fio_do_real(fio,iparams->u_b.ktheta);
-    gmx_fio_do_real(fio,iparams->u_b.r13);
-    gmx_fio_do_real(fio,iparams->u_b.kUB);
-    break;
-  case F_QUARTIC_ANGLES:
-    gmx_fio_do_real(fio,iparams->qangle.theta);
-    bDum=gmx_fio_ndo_real(fio,iparams->qangle.c,5);
-    break;
-  case F_BHAM:
-    gmx_fio_do_real(fio,iparams->bham.a);
-    gmx_fio_do_real(fio,iparams->bham.b);
-    gmx_fio_do_real(fio,iparams->bham.c);
-    break;
-  case F_MORSE:
-    gmx_fio_do_real(fio,iparams->morse.b0);
-    gmx_fio_do_real(fio,iparams->morse.cb);
-    gmx_fio_do_real(fio,iparams->morse.beta);
-    break;
-  case F_CUBICBONDS:
-    gmx_fio_do_real(fio,iparams->cubic.b0);
-    gmx_fio_do_real(fio,iparams->cubic.kb);
-    gmx_fio_do_real(fio,iparams->cubic.kcub);
-    break;
-  case F_CONNBONDS:
-    break;
-  case F_POLARIZATION:
-    gmx_fio_do_real(fio,iparams->polarize.alpha);
-    break;
-  case F_WATER_POL:
-    if (file_version < 31) 
-      gmx_fatal(FARGS,"Old tpr files with water_polarization not supported. Make a new.");
-    gmx_fio_do_real(fio,iparams->wpol.al_x);
-    gmx_fio_do_real(fio,iparams->wpol.al_y);
-    gmx_fio_do_real(fio,iparams->wpol.al_z);
-    gmx_fio_do_real(fio,iparams->wpol.rOH);
-    gmx_fio_do_real(fio,iparams->wpol.rHH);
-    gmx_fio_do_real(fio,iparams->wpol.rOD);
-    break;
-  case F_THOLE_POL:
-    gmx_fio_do_real(fio,iparams->thole.a);
-    gmx_fio_do_real(fio,iparams->thole.alpha1);
-    gmx_fio_do_real(fio,iparams->thole.alpha2);
-    gmx_fio_do_real(fio,iparams->thole.rfac);
-    break;
-  case F_LJ:
-    gmx_fio_do_real(fio,iparams->lj.c6);
-    gmx_fio_do_real(fio,iparams->lj.c12);
-    break;
-  case F_LJ14:
-    gmx_fio_do_real(fio,iparams->lj14.c6A);
-    gmx_fio_do_real(fio,iparams->lj14.c12A);
-    gmx_fio_do_real(fio,iparams->lj14.c6B);
-    gmx_fio_do_real(fio,iparams->lj14.c12B);
-    break;
-  case F_LJC14_Q:
-    gmx_fio_do_real(fio,iparams->ljc14.fqq);
-    gmx_fio_do_real(fio,iparams->ljc14.qi);
-    gmx_fio_do_real(fio,iparams->ljc14.qj);
-    gmx_fio_do_real(fio,iparams->ljc14.c6);
-    gmx_fio_do_real(fio,iparams->ljc14.c12);
-    break;
-  case F_LJC_PAIRS_NB:
-    gmx_fio_do_real(fio,iparams->ljcnb.qi);
-    gmx_fio_do_real(fio,iparams->ljcnb.qj);
-    gmx_fio_do_real(fio,iparams->ljcnb.c6);
-    gmx_fio_do_real(fio,iparams->ljcnb.c12);
-    break;
-  case F_PDIHS:
-  case F_PIDIHS:
-  case F_ANGRES:
-  case F_ANGRESZ:
-    gmx_fio_do_real(fio,iparams->pdihs.phiA);
-    gmx_fio_do_real(fio,iparams->pdihs.cpA);
-    if ((ftype == F_ANGRES || ftype == F_ANGRESZ) && file_version < 42) {
-      /* Read the incorrectly stored multiplicity */
-      gmx_fio_do_real(fio,iparams->harmonic.rB);
-      gmx_fio_do_real(fio,iparams->harmonic.krB);
-      iparams->pdihs.phiB = iparams->pdihs.phiA;
-      iparams->pdihs.cpB  = iparams->pdihs.cpA;
-    } else {
-      gmx_fio_do_real(fio,iparams->pdihs.phiB);
-      gmx_fio_do_real(fio,iparams->pdihs.cpB);
-      gmx_fio_do_int(fio,iparams->pdihs.mult);
-    }
-    break;
-  case F_DISRES:
-    gmx_fio_do_int(fio,iparams->disres.label);
-    gmx_fio_do_int(fio,iparams->disres.type);
-    gmx_fio_do_real(fio,iparams->disres.low);
-    gmx_fio_do_real(fio,iparams->disres.up1);
-    gmx_fio_do_real(fio,iparams->disres.up2);
-    gmx_fio_do_real(fio,iparams->disres.kfac);
-    break;
-  case F_ORIRES:
-    gmx_fio_do_int(fio,iparams->orires.ex);
-    gmx_fio_do_int(fio,iparams->orires.label);
-    gmx_fio_do_int(fio,iparams->orires.power);
-    gmx_fio_do_real(fio,iparams->orires.c);
-    gmx_fio_do_real(fio,iparams->orires.obs);
-    gmx_fio_do_real(fio,iparams->orires.kfac);
-    break;
-  case F_DIHRES:
-    gmx_fio_do_int(fio,iparams->dihres.power);
-    gmx_fio_do_int(fio,iparams->dihres.label);
-    gmx_fio_do_real(fio,iparams->dihres.phi);
-    gmx_fio_do_real(fio,iparams->dihres.dphi);
-    gmx_fio_do_real(fio,iparams->dihres.kfac);
-    break;
-  case F_POSRES:
-    gmx_fio_do_rvec(fio,iparams->posres.pos0A);
-    gmx_fio_do_rvec(fio,iparams->posres.fcA);
-    if (bRead && file_version < 27) {
-      copy_rvec(iparams->posres.pos0A,iparams->posres.pos0B);
-      copy_rvec(iparams->posres.fcA,iparams->posres.fcB);
-    } else {
-      gmx_fio_do_rvec(fio,iparams->posres.pos0B);
-      gmx_fio_do_rvec(fio,iparams->posres.fcB);
-    }
-    break;
-  case F_RBDIHS:
-    bDum=gmx_fio_ndo_real(fio,iparams->rbdihs.rbcA,NR_RBDIHS);
-    if(file_version>=25) 
-      bDum=gmx_fio_ndo_real(fio,iparams->rbdihs.rbcB,NR_RBDIHS);
-    break;
-  case F_FOURDIHS:
-    /* Fourier dihedrals are internally represented
-     * as Ryckaert-Bellemans since those are faster to compute.
-     */
-     bDum=gmx_fio_ndo_real(fio,iparams->rbdihs.rbcA, NR_RBDIHS);
-     bDum=gmx_fio_ndo_real(fio,iparams->rbdihs.rbcB, NR_RBDIHS);
-    break;
-  case F_CONSTR:
-  case F_CONSTRNC:
-    gmx_fio_do_real(fio,iparams->constr.dA);
-    gmx_fio_do_real(fio,iparams->constr.dB);
-    break;
-  case F_SETTLE:
-    gmx_fio_do_real(fio,iparams->settle.doh);
-    gmx_fio_do_real(fio,iparams->settle.dhh);
-    break;
-  case F_VSITE2:
-    gmx_fio_do_real(fio,iparams->vsite.a);
-    break;
-  case F_VSITE3:
-  case F_VSITE3FD:
-  case F_VSITE3FAD:
-    gmx_fio_do_real(fio,iparams->vsite.a);
-    gmx_fio_do_real(fio,iparams->vsite.b);
-    break;
-  case F_VSITE3OUT:
-  case F_VSITE4FD: 
-  case F_VSITE4FDN: 
-    gmx_fio_do_real(fio,iparams->vsite.a);
-    gmx_fio_do_real(fio,iparams->vsite.b);
-    gmx_fio_do_real(fio,iparams->vsite.c);
-    break;
-  case F_VSITEN:
-    gmx_fio_do_int(fio,iparams->vsiten.n);
-    gmx_fio_do_real(fio,iparams->vsiten.a);
-    break;
-  case F_GB12:
-  case F_GB13:
-  case F_GB14:
-    /* We got rid of some parameters in version 68 */
-    if(bRead && file_version<68)
-    {
-        gmx_fio_do_real(fio,rdum);     
-        gmx_fio_do_real(fio,rdum);     
-        gmx_fio_do_real(fio,rdum);     
-        gmx_fio_do_real(fio,rdum);     
-    }
-       gmx_fio_do_real(fio,iparams->gb.sar);   
-       gmx_fio_do_real(fio,iparams->gb.st);
-       gmx_fio_do_real(fio,iparams->gb.pi);
-       gmx_fio_do_real(fio,iparams->gb.gbr);
-       gmx_fio_do_real(fio,iparams->gb.bmlt);
-       break;
-  case F_CMAP:
-       gmx_fio_do_int(fio,iparams->cmap.cmapA);
-       gmx_fio_do_int(fio,iparams->cmap.cmapB);
-    break;
-  default:
-    gmx_fatal(FARGS,"unknown function type %d (%s) in %s line %d",
-               
-               ftype,interaction_function[ftype].name,__FILE__,__LINE__);
-  }
-  if (!bRead)
-    gmx_fio_unset_comment(fio);
-}
-
-static void do_ilist(t_fileio *fio, t_ilist *ilist,gmx_bool bRead,int file_version,
-                    int ftype)
-{
-  int  i,k,idum;
-  gmx_bool bDum=TRUE;
-  
-  if (!bRead) {
-    gmx_fio_set_comment(fio, interaction_function[ftype].name);
-  }
-  if (file_version < 44) {
-    for(i=0; i<MAXNODES; i++)
-      gmx_fio_do_int(fio,idum);
-  }
-  gmx_fio_do_int(fio,ilist->nr);
-  if (bRead)
-    snew(ilist->iatoms,ilist->nr);
-  bDum=gmx_fio_ndo_int(fio,ilist->iatoms,ilist->nr);
-  if (!bRead)
-    gmx_fio_unset_comment(fio);
-}
-
-static void do_ffparams(t_fileio *fio, gmx_ffparams_t *ffparams,
-                       gmx_bool bRead, int file_version)
-{
-  int  idum,i,j;
-  gmx_bool bDum=TRUE;
-  unsigned int k;
-
-  gmx_fio_do_int(fio,ffparams->atnr);
-  if (file_version < 57) {
-    gmx_fio_do_int(fio,idum);
-  }
-  gmx_fio_do_int(fio,ffparams->ntypes);
-  if (bRead && debug)
-    fprintf(debug,"ffparams->atnr = %d, ntypes = %d\n",
-           ffparams->atnr,ffparams->ntypes);
-  if (bRead) {
-    snew(ffparams->functype,ffparams->ntypes);
-    snew(ffparams->iparams,ffparams->ntypes);
-  }
-  /* Read/write all the function types */
-  bDum=gmx_fio_ndo_int(fio,ffparams->functype,ffparams->ntypes);
-  if (bRead && debug)
-    pr_ivec(debug,0,"functype",ffparams->functype,ffparams->ntypes,TRUE);
-
-  if (file_version >= 66) {
-    gmx_fio_do_double(fio,ffparams->reppow);
-  } else {
-    ffparams->reppow = 12.0;
-  }
-
-  if (file_version >= 57) {
-    gmx_fio_do_real(fio,ffparams->fudgeQQ);
-  }
-
-  /* Check whether all these function types are supported by the code.
-   * In practice the code is backwards compatible, which means that the
-   * numbering may have to be altered from old numbering to new numbering
-   */
-  for (i=0; (i<ffparams->ntypes); i++) {
-    if (bRead)
-      /* Loop over file versions */
-      for (k=0; (k<NFTUPD); k++)
-       /* Compare the read file_version to the update table */
-       if ((file_version < ftupd[k].fvnr) && 
-           (ffparams->functype[i] >= ftupd[k].ftype)) {
-         ffparams->functype[i] += 1;
-         if (debug) {
-           fprintf(debug,"Incrementing function type %d to %d (due to %s)\n",
-                   i,ffparams->functype[i],
-                   interaction_function[ftupd[k].ftype].longname);
-           fflush(debug);
-         }
-       }
-    
-    do_iparams(fio, ffparams->functype[i],&ffparams->iparams[i],bRead,
-               file_version);
-    if (bRead && debug)
-      pr_iparams(debug,ffparams->functype[i],&ffparams->iparams[i]);
-  }
-}
-
-static void do_ilists(t_fileio *fio, t_ilist *ilist,gmx_bool bRead, 
-                      int file_version)
-{
-  int i,j,renum[F_NRE];
-  gmx_bool bDum=TRUE,bClear;
-  unsigned int k;
-  
-  for(j=0; (j<F_NRE); j++) {
-    bClear = FALSE;
-    if (bRead)
-      for (k=0; k<NFTUPD; k++)
-       if ((file_version < ftupd[k].fvnr) && (j == ftupd[k].ftype))
-         bClear = TRUE;
-    if (bClear) {
-      ilist[j].nr = 0;
-      ilist[j].iatoms = NULL;
-    } else {
-      do_ilist(fio, &ilist[j],bRead,file_version,j);
-    }
-    /*
-    if (bRead && gmx_debug_at)
-      pr_ilist(debug,0,interaction_function[j].longname,
-              functype,&ilist[j],TRUE);
-    */
-  }
-}
-
-static void do_idef(t_fileio *fio, gmx_ffparams_t *ffparams,gmx_moltype_t *molt,
-                   gmx_bool bRead, int file_version)
-{
-  do_ffparams(fio, ffparams,bRead,file_version);
-    
-  if (file_version >= 54) {
-    gmx_fio_do_real(fio,ffparams->fudgeQQ);
-  }
-
-  do_ilists(fio, molt->ilist,bRead,file_version);
-}
-
-static void do_block(t_fileio *fio, t_block *block,gmx_bool bRead,int file_version)
-{
-  int  i,idum,dum_nra,*dum_a;
-  gmx_bool bDum=TRUE;
-
-  if (file_version < 44)
-    for(i=0; i<MAXNODES; i++)
-      gmx_fio_do_int(fio,idum);
-  gmx_fio_do_int(fio,block->nr);
-  if (file_version < 51)
-    gmx_fio_do_int(fio,dum_nra);
-  if (bRead) {
-    block->nalloc_index = block->nr+1;
-    snew(block->index,block->nalloc_index);
-  }
-  bDum=gmx_fio_ndo_int(fio,block->index,block->nr+1);
-
-  if (file_version < 51 && dum_nra > 0) {
-    snew(dum_a,dum_nra);
-    bDum=gmx_fio_ndo_int(fio,dum_a,dum_nra);
-    sfree(dum_a);
-  }
-}
-
-static void do_blocka(t_fileio *fio, t_blocka *block,gmx_bool bRead,
-                      int file_version)
-{
-  int  i,idum;
-  gmx_bool bDum=TRUE;
-
-  if (file_version < 44)
-    for(i=0; i<MAXNODES; i++)
-      gmx_fio_do_int(fio,idum);
-  gmx_fio_do_int(fio,block->nr);
-  gmx_fio_do_int(fio,block->nra);
-  if (bRead) {
-    block->nalloc_index = block->nr+1;
-    snew(block->index,block->nalloc_index);
-    block->nalloc_a = block->nra;
-    snew(block->a,block->nalloc_a);
-  }
-  bDum=gmx_fio_ndo_int(fio,block->index,block->nr+1);
-  bDum=gmx_fio_ndo_int(fio,block->a,block->nra);
-}
-
-static void do_atom(t_fileio *fio, t_atom *atom,int ngrp,gmx_bool bRead, 
-                    int file_version, gmx_groups_t *groups,int atnr)
-{ 
-  int i,myngrp;
-  
-  gmx_fio_do_real(fio,atom->m);
-  gmx_fio_do_real(fio,atom->q);
-  gmx_fio_do_real(fio,atom->mB);
-  gmx_fio_do_real(fio,atom->qB);
-  gmx_fio_do_ushort(fio, atom->type);
-  gmx_fio_do_ushort(fio, atom->typeB);
-  gmx_fio_do_int(fio,atom->ptype);
-  gmx_fio_do_int(fio,atom->resind);
-  if (file_version >= 52)
-    gmx_fio_do_int(fio,atom->atomnumber);
-  else if (bRead)
-    atom->atomnumber = NOTSET;
-  if (file_version < 23) 
-    myngrp = 8;
-  else if (file_version < 39) 
-    myngrp = 9;
-  else
-    myngrp = ngrp;
-
-  if (file_version < 57) {
-    unsigned char uchar[egcNR];
-    gmx_fio_ndo_uchar(fio,uchar,myngrp);
-    for(i=myngrp; (i<ngrp); i++) {
-      uchar[i] = 0;
-    }
-    /* Copy the old data format to the groups struct */
-    for(i=0; i<ngrp; i++) {
-      groups->grpnr[i][atnr] = uchar[i];
-    }
-  }
-}
-
-static void do_grps(t_fileio *fio, int ngrp,t_grps grps[],gmx_bool bRead, 
-                    int file_version)
-{
-  int i,j,myngrp;
-  gmx_bool bDum=TRUE;
-  
-  if (file_version < 23) 
-    myngrp = 8;
-  else if (file_version < 39) 
-    myngrp = 9;
-  else
-    myngrp = ngrp;
-
-  for(j=0; (j<ngrp); j++) {
-    if (j<myngrp) {
-      gmx_fio_do_int(fio,grps[j].nr);
-      if (bRead)
-       snew(grps[j].nm_ind,grps[j].nr);
-      bDum=gmx_fio_ndo_int(fio,grps[j].nm_ind,grps[j].nr);
-    }
-    else {
-      grps[j].nr = 1;
-      snew(grps[j].nm_ind,grps[j].nr);
-    }
-  }
-}
-
-static void do_symstr(t_fileio *fio, char ***nm,gmx_bool bRead,t_symtab *symtab)
-{
-  int ls;
-  
-  if (bRead) {
-    gmx_fio_do_int(fio,ls);
-    *nm = get_symtab_handle(symtab,ls);
-  }
-  else {
-    ls = lookup_symtab(symtab,*nm);
-    gmx_fio_do_int(fio,ls);
-  }
-}
-
-static void do_strstr(t_fileio *fio, int nstr,char ***nm,gmx_bool bRead,
-                      t_symtab *symtab)
-{
-  int  j;
-  
-  for (j=0; (j<nstr); j++) 
-    do_symstr(fio, &(nm[j]),bRead,symtab);
-}
-
-static void do_resinfo(t_fileio *fio, int n,t_resinfo *ri,gmx_bool bRead,
-                       t_symtab *symtab, int file_version)
-{
-  int  j;
-  
-  for (j=0; (j<n); j++) {
-    do_symstr(fio, &(ri[j].name),bRead,symtab);
-    if (file_version >= 63) {
-      gmx_fio_do_int(fio,ri[j].nr);
-      gmx_fio_do_uchar(fio, ri[j].ic);
-    } else {
-      ri[j].nr = j + 1;
-      ri[j].ic = ' ';
-    }
-  }
-}
-
-static void do_atoms(t_fileio *fio, t_atoms *atoms,gmx_bool bRead,t_symtab *symtab,
-                    int file_version,
-                    gmx_groups_t *groups)
-{
-  int i;
-  
-  gmx_fio_do_int(fio,atoms->nr);
-  gmx_fio_do_int(fio,atoms->nres);
-  if (file_version < 57) {
-    gmx_fio_do_int(fio,groups->ngrpname);
-    for(i=0; i<egcNR; i++) {
-      groups->ngrpnr[i] = atoms->nr;
-      snew(groups->grpnr[i],groups->ngrpnr[i]);
-    }
-  }
-  if (bRead) {
-    snew(atoms->atom,atoms->nr);
-    snew(atoms->atomname,atoms->nr);
-    snew(atoms->atomtype,atoms->nr);
-    snew(atoms->atomtypeB,atoms->nr);
-    snew(atoms->resinfo,atoms->nres);
-    if (file_version < 57) {
-      snew(groups->grpname,groups->ngrpname);
-    }
-    atoms->pdbinfo = NULL;
-  }
-  for(i=0; (i<atoms->nr); i++) {
-    do_atom(fio, &atoms->atom[i],egcNR,bRead, file_version,groups,i);
-  }
-  do_strstr(fio, atoms->nr,atoms->atomname,bRead,symtab);
-  if (bRead && (file_version <= 20)) {
-    for(i=0; i<atoms->nr; i++) {
-      atoms->atomtype[i]  = put_symtab(symtab,"?");
-      atoms->atomtypeB[i] = put_symtab(symtab,"?");
-    }
-  } else {
-    do_strstr(fio, atoms->nr,atoms->atomtype,bRead,symtab);
-    do_strstr(fio, atoms->nr,atoms->atomtypeB,bRead,symtab);
-  }
-  do_resinfo(fio, atoms->nres,atoms->resinfo,bRead,symtab,file_version);
-
-  if (file_version < 57) {
-    do_strstr(fio, groups->ngrpname,groups->grpname,bRead,symtab);
-  
-    do_grps(fio, egcNR,groups->grps,bRead,file_version);
-  }
-}
-
-static void do_groups(t_fileio *fio, gmx_groups_t *groups,
-                     gmx_bool bRead,t_symtab *symtab,
-                     int file_version)
-{
-  int  g,n,i;
-  gmx_bool bDum=TRUE;
-
-  do_grps(fio, egcNR,groups->grps,bRead,file_version);
-  gmx_fio_do_int(fio,groups->ngrpname);
-  if (bRead) {
-    snew(groups->grpname,groups->ngrpname);
-  }
-  do_strstr(fio, groups->ngrpname,groups->grpname,bRead,symtab);
-  for(g=0; g<egcNR; g++) {
-    gmx_fio_do_int(fio,groups->ngrpnr[g]);
-    if (groups->ngrpnr[g] == 0) {
-      if (bRead) {
-       groups->grpnr[g] = NULL;
-      }
-    } else {
-      if (bRead) {
-       snew(groups->grpnr[g],groups->ngrpnr[g]);
-      }
-      bDum=gmx_fio_ndo_uchar(fio, groups->grpnr[g],groups->ngrpnr[g]);
-    }
-  }
-}
-
-static void do_atomtypes(t_fileio *fio, t_atomtypes *atomtypes,gmx_bool bRead,
-                        t_symtab *symtab,int file_version)
-{
-  int i,j;
-  gmx_bool bDum = TRUE;
-  
-  if (file_version > 25) {
-    gmx_fio_do_int(fio,atomtypes->nr);
-    j=atomtypes->nr;
-    if (bRead) {
-      snew(atomtypes->radius,j);
-      snew(atomtypes->vol,j);
-      snew(atomtypes->surftens,j);
-      snew(atomtypes->atomnumber,j);
-      snew(atomtypes->gb_radius,j);
-      snew(atomtypes->S_hct,j);
-    }
-    bDum=gmx_fio_ndo_real(fio,atomtypes->radius,j);
-    bDum=gmx_fio_ndo_real(fio,atomtypes->vol,j);
-    bDum=gmx_fio_ndo_real(fio,atomtypes->surftens,j);
-    if(file_version >= 40)
-    {
-        bDum=gmx_fio_ndo_int(fio,atomtypes->atomnumber,j);
-    }
-       if(file_version >= 60)
-       {
-               bDum=gmx_fio_ndo_real(fio,atomtypes->gb_radius,j);
-               bDum=gmx_fio_ndo_real(fio,atomtypes->S_hct,j);
-       }
-  } else {
-    /* File versions prior to 26 cannot do GBSA, 
-     * so they dont use this structure 
-     */
-    atomtypes->nr = 0;
-    atomtypes->radius = NULL;
-    atomtypes->vol = NULL;
-    atomtypes->surftens = NULL;
-    atomtypes->atomnumber = NULL;
-    atomtypes->gb_radius = NULL;
-    atomtypes->S_hct = NULL;
-  }  
-}
-
-static void do_symtab(t_fileio *fio, t_symtab *symtab,gmx_bool bRead)
-{
-  int i,nr;
-  t_symbuf *symbuf;
-  char buf[STRLEN];
-  
-  gmx_fio_do_int(fio,symtab->nr);
-  nr     = symtab->nr;
-  if (bRead) {
-    snew(symtab->symbuf,1);
-    symbuf = symtab->symbuf;
-    symbuf->bufsize = nr;
-    snew(symbuf->buf,nr);
-    for (i=0; (i<nr); i++) {
-      gmx_fio_do_string(fio,buf);
-      symbuf->buf[i]=strdup(buf);
-    }
-  }
-  else {
-    symbuf = symtab->symbuf;
-    while (symbuf!=NULL) {
-      for (i=0; (i<symbuf->bufsize) && (i<nr); i++) 
-       gmx_fio_do_string(fio,symbuf->buf[i]);
-      nr-=i;
-      symbuf=symbuf->next;
-    }
-    if (nr != 0)
-      gmx_fatal(FARGS,"nr of symtab strings left: %d",nr);
-  }
-}
-
-static void do_cmap(t_fileio *fio, gmx_cmap_t *cmap_grid, gmx_bool bRead)
-{
-       int i,j,ngrid,gs,nelem;
-       
-       gmx_fio_do_int(fio,cmap_grid->ngrid);
-       gmx_fio_do_int(fio,cmap_grid->grid_spacing);
-       
-       ngrid = cmap_grid->ngrid;
-       gs    = cmap_grid->grid_spacing;
-       nelem = gs * gs;
-       
-       if(bRead)
-       {
-               snew(cmap_grid->cmapdata,ngrid);
-               
-               for(i=0;i<cmap_grid->ngrid;i++)
-               {
-                       snew(cmap_grid->cmapdata[i].cmap,4*nelem);
-               }
-       }
-       
-       for(i=0;i<cmap_grid->ngrid;i++)
-       {
-               for(j=0;j<nelem;j++)
-               {
-                       gmx_fio_do_real(fio,cmap_grid->cmapdata[i].cmap[j*4]);
-                       gmx_fio_do_real(fio,cmap_grid->cmapdata[i].cmap[j*4+1]);
-                       gmx_fio_do_real(fio,cmap_grid->cmapdata[i].cmap[j*4+2]);
-                       gmx_fio_do_real(fio,cmap_grid->cmapdata[i].cmap[j*4+3]);
-               }
-       }       
-}
-
-
-void tpx_make_chain_identifiers(t_atoms *atoms,t_block *mols)
-{
-    int m,a,a0,a1,r;
-    char c,chainid;
-    int  chainnum;
-    
-    /* We always assign a new chain number, but save the chain id characters 
-     * for larger molecules.
-     */
-#define CHAIN_MIN_ATOMS 15
-    
-    chainnum=0;
-    chainid='A';
-    for(m=0; m<mols->nr; m++) 
-    {
-        a0=mols->index[m];
-        a1=mols->index[m+1];
-        if ((a1-a0 >= CHAIN_MIN_ATOMS) && (chainid <= 'Z')) 
-        {
-            c=chainid;
-            chainid++;
-        } 
-        else
-        {
-            c=' ';
-        }
-        for(a=a0; a<a1; a++) 
-        {
-            atoms->resinfo[atoms->atom[a].resind].chainnum = chainnum;
-            atoms->resinfo[atoms->atom[a].resind].chainid  = c;
-        }
-        chainnum++;
-    }
-    
-    /* Blank out the chain id if there was only one chain */
-    if (chainid == 'B') 
-    {
-        for(r=0; r<atoms->nres; r++) 
-        {
-            atoms->resinfo[r].chainid = ' ';
-        }
-    }
-}
-  
-static void do_moltype(t_fileio *fio, gmx_moltype_t *molt,gmx_bool bRead,
-                       t_symtab *symtab, int file_version,
-                      gmx_groups_t *groups)
-{
-  int i;
-
-  if (file_version >= 57) {
-    do_symstr(fio, &(molt->name),bRead,symtab);
-  }
-
-  do_atoms(fio, &molt->atoms, bRead, symtab, file_version, groups);
-
-  if (bRead && gmx_debug_at) {
-    pr_atoms(debug,0,"atoms",&molt->atoms,TRUE);
-  }
-  
-  if (file_version >= 57) {
-    do_ilists(fio, molt->ilist,bRead,file_version);
-
-    do_block(fio, &molt->cgs,bRead,file_version);
-    if (bRead && gmx_debug_at) {
-      pr_block(debug,0,"cgs",&molt->cgs,TRUE);
-    }
-  }
-
-  /* This used to be in the atoms struct */
-  do_blocka(fio, &molt->excls, bRead, file_version);
-}
-
-static void do_molblock(t_fileio *fio, gmx_molblock_t *molb,gmx_bool bRead,
-                        int file_version)
-{
-  int i;
-
-  gmx_fio_do_int(fio,molb->type);
-  gmx_fio_do_int(fio,molb->nmol);
-  gmx_fio_do_int(fio,molb->natoms_mol);
-  /* Position restraint coordinates */
-  gmx_fio_do_int(fio,molb->nposres_xA);
-  if (molb->nposres_xA > 0) {
-    if (bRead) {
-      snew(molb->posres_xA,molb->nposres_xA);
-    }
-    gmx_fio_ndo_rvec(fio,molb->posres_xA,molb->nposres_xA);
-  }
-  gmx_fio_do_int(fio,molb->nposres_xB);
-  if (molb->nposres_xB > 0) {
-    if (bRead) {
-      snew(molb->posres_xB,molb->nposres_xB);
-    }
-    gmx_fio_ndo_rvec(fio,molb->posres_xB,molb->nposres_xB);
-  }
-
-}
-
-static t_block mtop_mols(gmx_mtop_t *mtop)
-{
-  int mb,m,a,mol;
-  t_block mols;
-
-  mols.nr = 0;
-  for(mb=0; mb<mtop->nmolblock; mb++) {
-    mols.nr += mtop->molblock[mb].nmol;
-  }
-  mols.nalloc_index = mols.nr + 1;
-  snew(mols.index,mols.nalloc_index);
-
-  a = 0;
-  m = 0;
-  mols.index[m] = a;
-  for(mb=0; mb<mtop->nmolblock; mb++) {
-    for(mol=0; mol<mtop->molblock[mb].nmol; mol++) {
-      a += mtop->molblock[mb].natoms_mol;
-      m++;
-      mols.index[m] = a;
-    }
-  }
-  
-  return mols;
-}
-
-static void add_posres_molblock(gmx_mtop_t *mtop)
-{
-  t_ilist *il;
-  int am,i,mol,a;
-  gmx_bool bFE;
-  gmx_molblock_t *molb;
-  t_iparams *ip;
-
-  il = &mtop->moltype[0].ilist[F_POSRES];
-  if (il->nr == 0) {
-    return;
-  }
-  am = 0;
-  bFE = FALSE;
-  for(i=0; i<il->nr; i+=2) {
-    ip = &mtop->ffparams.iparams[il->iatoms[i]];
-    am = max(am,il->iatoms[i+1]);
-    if (ip->posres.pos0B[XX] != ip->posres.pos0A[XX] ||
-       ip->posres.pos0B[YY] != ip->posres.pos0A[YY] ||
-       ip->posres.pos0B[ZZ] != ip->posres.pos0A[ZZ]) {
-      bFE = TRUE;
-    }
-  }
-  /* Make the posres coordinate block end at a molecule end */
-  mol = 0;
-  while(am >= mtop->mols.index[mol+1]) {
-    mol++;
-  }
-  molb = &mtop->molblock[0];
-  molb->nposres_xA = mtop->mols.index[mol+1];
-  snew(molb->posres_xA,molb->nposres_xA);
-  if (bFE) {
-    molb->nposres_xB = molb->nposres_xA;
-    snew(molb->posres_xB,molb->nposres_xB);
-  } else {
-    molb->nposres_xB = 0;
-  }
-  for(i=0; i<il->nr; i+=2) {
-    ip = &mtop->ffparams.iparams[il->iatoms[i]];
-    a  = il->iatoms[i+1];
-    molb->posres_xA[a][XX] = ip->posres.pos0A[XX];
-    molb->posres_xA[a][YY] = ip->posres.pos0A[YY];
-    molb->posres_xA[a][ZZ] = ip->posres.pos0A[ZZ];
-    if (bFE) {
-      molb->posres_xB[a][XX] = ip->posres.pos0B[XX];
-      molb->posres_xB[a][YY] = ip->posres.pos0B[YY];
-      molb->posres_xB[a][ZZ] = ip->posres.pos0B[ZZ];
-    }
-  }
-}
-
-static void set_disres_npair(gmx_mtop_t *mtop)
-{
-  int mt,i,npair;
-  t_iparams *ip;
-  t_ilist *il;
-  t_iatom *a;
-
-  ip = mtop->ffparams.iparams;
-
-  for(mt=0; mt<mtop->nmoltype; mt++) {
-    il = &mtop->moltype[mt].ilist[F_DISRES];
-    if (il->nr > 0) {
-      a = il->iatoms;
-      npair = 0;
-      for(i=0; i<il->nr; i+=3) {
-       npair++;
-       if (i+3 == il->nr || ip[a[i]].disres.label != ip[a[i+3]].disres.label) {
-         ip[a[i]].disres.npair = npair;
-         npair = 0;
-       }
-      }
-    }
-  }
-}
-
-static void do_mtop(t_fileio *fio, gmx_mtop_t *mtop,gmx_bool bRead, 
-                    int file_version)
-{
-  int  mt,mb,i;
-  t_blocka dumb;
-
-  if (bRead)
-    init_mtop(mtop);
-  do_symtab(fio, &(mtop->symtab),bRead);
-  if (bRead && debug) 
-    pr_symtab(debug,0,"symtab",&mtop->symtab);
-  
-  do_symstr(fio, &(mtop->name),bRead,&(mtop->symtab));
-  
-  if (file_version >= 57) {
-    do_ffparams(fio, &mtop->ffparams,bRead,file_version);
-
-    gmx_fio_do_int(fio,mtop->nmoltype);
-  } else {
-    mtop->nmoltype = 1;
-  }
-  if (bRead) {
-    snew(mtop->moltype,mtop->nmoltype);
-    if (file_version < 57) {
-      mtop->moltype[0].name = mtop->name;
-    }
-  }
-  for(mt=0; mt<mtop->nmoltype; mt++) {
-    do_moltype(fio, &mtop->moltype[mt],bRead,&mtop->symtab,file_version,
-              &mtop->groups);
-  }
-
-  if (file_version >= 57) {
-    gmx_fio_do_int(fio,mtop->nmolblock);
-  } else {
-    mtop->nmolblock = 1;
-  }
-  if (bRead) {
-    snew(mtop->molblock,mtop->nmolblock);
-  }
-  if (file_version >= 57) {
-    for(mb=0; mb<mtop->nmolblock; mb++) {
-      do_molblock(fio, &mtop->molblock[mb],bRead,file_version);
-    }
-    gmx_fio_do_int(fio,mtop->natoms);
-  } else {
-    mtop->molblock[0].type = 0;
-    mtop->molblock[0].nmol = 1;
-    mtop->molblock[0].natoms_mol = mtop->moltype[0].atoms.nr;
-    mtop->molblock[0].nposres_xA = 0;
-    mtop->molblock[0].nposres_xB = 0;
-  }
-
-  do_atomtypes (fio, &(mtop->atomtypes),bRead,&(mtop->symtab), file_version);
-  if (bRead && debug) 
-    pr_atomtypes(debug,0,"atomtypes",&mtop->atomtypes,TRUE);
-
-  if (file_version < 57) {
-    /* Debug statements are inside do_idef */    
-    do_idef (fio, &mtop->ffparams,&mtop->moltype[0],bRead,file_version);
-    mtop->natoms = mtop->moltype[0].atoms.nr;
-  }
-       
-  if(file_version >= 65)
-  {
-      do_cmap(fio, &mtop->ffparams.cmap_grid,bRead);
-  }
-  else
-  {
-      mtop->ffparams.cmap_grid.ngrid        = 0;
-      mtop->ffparams.cmap_grid.grid_spacing = 0.1;
-      mtop->ffparams.cmap_grid.cmapdata     = NULL;
-  }
-         
-  if (file_version >= 57) {
-    do_groups(fio, &mtop->groups,bRead,&(mtop->symtab),file_version);
-  }
-
-  if (file_version < 57) {
-    do_block(fio, &mtop->moltype[0].cgs,bRead,file_version);
-    if (bRead && gmx_debug_at) {
-      pr_block(debug,0,"cgs",&mtop->moltype[0].cgs,TRUE);
-    }
-    do_block(fio, &mtop->mols,bRead,file_version);
-    /* Add the posres coordinates to the molblock */
-    add_posres_molblock(mtop);
-  }
-  if (bRead) {
-    if (file_version >= 57) {
-      mtop->mols = mtop_mols(mtop);
-    }
-    if (gmx_debug_at) { 
-      pr_block(debug,0,"mols",&mtop->mols,TRUE);
-    }
-  }
-
-  if (file_version < 51) {
-    /* Here used to be the shake blocks */
-    do_blocka(fio, &dumb,bRead,file_version);
-    if (dumb.nr > 0)
-      sfree(dumb.index);
-    if (dumb.nra > 0)
-      sfree(dumb.a);
-  }
-
-  if (bRead) {
-    close_symtab(&(mtop->symtab));
-  }
-}
-
-/* If TopOnlyOK is TRUE then we can read even future versions
- * of tpx files, provided the file_generation hasn't changed.
- * If it is FALSE, we need the inputrecord too, and bail out
- * if the file is newer than the program.
- * 
- * The version and generation if the topology (see top of this file)
- * are returned in the two last arguments.
- * 
- * If possible, we will read the inputrec even when TopOnlyOK is TRUE.
- */
-static void do_tpxheader(t_fileio *fio,gmx_bool bRead,t_tpxheader *tpx, 
-                         gmx_bool TopOnlyOK, int *file_version, 
-                         int *file_generation)
-{
-  char  buf[STRLEN];
-  gmx_bool  bDouble;
-  int   precision;
-  int   fver,fgen;
-  int   idum=0;
-  real  rdum=0;
-
-  gmx_fio_checktype(fio);
-  gmx_fio_setdebug(fio,bDebugMode());
-  
-  /* NEW! XDR tpb file */
-  precision = sizeof(real);
-  if (bRead) {
-    gmx_fio_do_string(fio,buf);
-    if (strncmp(buf,"VERSION",7))
-      gmx_fatal(FARGS,"Can not read file %s,\n"
-                 "             this file is from a Gromacs version which is older than 2.0\n"
-                 "             Make a new one with grompp or use a gro or pdb file, if possible",
-                 gmx_fio_getname(fio));
-    gmx_fio_do_int(fio,precision);
-    bDouble = (precision == sizeof(double));
-    if ((precision != sizeof(float)) && !bDouble)
-      gmx_fatal(FARGS,"Unknown precision in file %s: real is %d bytes "
-                 "instead of %d or %d",
-                 gmx_fio_getname(fio),precision,sizeof(float),sizeof(double));
-    gmx_fio_setprecision(fio,bDouble);
-    fprintf(stderr,"Reading file %s, %s (%s precision)\n",
-           gmx_fio_getname(fio),buf,bDouble ? "double" : "single");
-  }
-  else {
-    gmx_fio_write_string(fio,GromacsVersion());
-    bDouble = (precision == sizeof(double));
-    gmx_fio_setprecision(fio,bDouble);
-    gmx_fio_do_int(fio,precision);
-    fver = tpx_version;
-    fgen = tpx_generation;
-  }
-  
-  /* Check versions! */
-  gmx_fio_do_int(fio,fver);
-  
-  if(fver>=26)
-    gmx_fio_do_int(fio,fgen);
-  else
-    fgen=0;
-  if(file_version!=NULL)
-    *file_version = fver;
-  if(file_generation!=NULL)
-    *file_generation = fgen;
-   
-  
-  if ((fver <= tpx_incompatible_version) ||
-      ((fver > tpx_version) && !TopOnlyOK) ||
-      (fgen > tpx_generation))
-    gmx_fatal(FARGS,"reading tpx file (%s) version %d with version %d program",
-               gmx_fio_getname(fio),fver,tpx_version);
-  
-  do_section(fio,eitemHEADER,bRead);
-  gmx_fio_do_int(fio,tpx->natoms);
-  if (fver >= 28)
-    gmx_fio_do_int(fio,tpx->ngtc);
-  else
-    tpx->ngtc = 0;
-  if (fver < 62) {
-    gmx_fio_do_int(fio,idum);
-    gmx_fio_do_real(fio,rdum);
-  }
-  gmx_fio_do_real(fio,tpx->lambda);
-  gmx_fio_do_int(fio,tpx->bIr);
-  gmx_fio_do_int(fio,tpx->bTop);
-  gmx_fio_do_int(fio,tpx->bX);
-  gmx_fio_do_int(fio,tpx->bV);
-  gmx_fio_do_int(fio,tpx->bF);
-  gmx_fio_do_int(fio,tpx->bBox);
-
-  if((fgen > tpx_generation)) {
-    /* This can only happen if TopOnlyOK=TRUE */
-    tpx->bIr=FALSE;
-  }
-}
-
-static int do_tpx(t_fileio *fio, gmx_bool bRead,
-                 t_inputrec *ir,t_state *state,rvec *f,gmx_mtop_t *mtop,
-                 gmx_bool bXVallocated)
-{
-  t_tpxheader tpx;
-  t_inputrec  dum_ir;
-  gmx_mtop_t  dum_top;
-  gmx_bool        TopOnlyOK,bDum=TRUE;
-  int         file_version,file_generation;
-  int         i;
-  rvec        *xptr,*vptr;
-  int         ePBC;
-  gmx_bool        bPeriodicMols;
-
-  if (!bRead) {
-    tpx.natoms = state->natoms;
-    tpx.ngtc   = state->ngtc;
-    tpx.lambda = state->lambda;
-    tpx.bIr  = (ir       != NULL);
-    tpx.bTop = (mtop     != NULL);
-    tpx.bX   = (state->x != NULL);
-    tpx.bV   = (state->v != NULL);
-    tpx.bF   = (f        != NULL);
-    tpx.bBox = TRUE;
-  }
-  
-  TopOnlyOK = (ir==NULL);
-  
-  do_tpxheader(fio,bRead,&tpx,TopOnlyOK,&file_version,&file_generation);
-
-  if (bRead) {
-    state->flags  = 0;
-    state->lambda = tpx.lambda;
-    /* The init_state calls initialize the Nose-Hoover xi integrals to zero */
-    if (bXVallocated) {
-      xptr = state->x;
-      vptr = state->v;
-      init_state(state,0,tpx.ngtc,0,0);  /* nose-hoover chains */ /* eventually, need to add nnhpres here? */
-      state->natoms = tpx.natoms; 
-      state->nalloc = tpx.natoms; 
-      state->x = xptr;
-      state->v = vptr;
-    } else {
-      init_state(state,tpx.natoms,tpx.ngtc,0,0);  /* nose-hoover chains */
-    }
-  }
-
-#define do_test(fio,b,p) if (bRead && (p!=NULL) && !b) gmx_fatal(FARGS,"No %s in %s",#p,gmx_fio_getname(fio)) 
-
-  do_test(fio,tpx.bBox,state->box);
-  do_section(fio,eitemBOX,bRead);
-  if (tpx.bBox) {
-    gmx_fio_ndo_rvec(fio,state->box,DIM);
-    if (file_version >= 51) {
-      gmx_fio_ndo_rvec(fio,state->box_rel,DIM);
-    } else {
-      /* We initialize box_rel after reading the inputrec */
-      clear_mat(state->box_rel);
-    }
-    if (file_version >= 28) {
-      gmx_fio_ndo_rvec(fio,state->boxv,DIM);
-      if (file_version < 56) {
-       matrix mdum;
-       gmx_fio_ndo_rvec(fio,mdum,DIM);
-      }
-    }
-  }
-  
-  if (state->ngtc > 0 && file_version >= 28) {
-    real *dumv;
-    /*ndo_double(state->nosehoover_xi,state->ngtc,bDum);*/
-    /*ndo_double(state->nosehoover_vxi,state->ngtc,bDum);*/
-    /*ndo_double(state->therm_integral,state->ngtc,bDum);*/
-    snew(dumv,state->ngtc);
-    if (file_version < 69) {
-      bDum=gmx_fio_ndo_real(fio,dumv,state->ngtc);
-    }
-    /* These used to be the Berendsen tcoupl_lambda's */
-    bDum=gmx_fio_ndo_real(fio,dumv,state->ngtc);
-    sfree(dumv);
-  }
-
-  /* Prior to tpx version 26, the inputrec was here.
-   * I moved it to enable partial forward-compatibility
-   * for analysis/viewer programs.
-   */
-  if(file_version<26) {
-    do_test(fio,tpx.bIr,ir);
-    do_section(fio,eitemIR,bRead);
-    if (tpx.bIr) {
-      if (ir) {
-       do_inputrec(fio, ir,bRead,file_version,
-                    mtop ? &mtop->ffparams.fudgeQQ : NULL);
-       if (bRead && debug) 
-         pr_inputrec(debug,0,"inputrec",ir,FALSE);
-      }
-      else {
-       do_inputrec(fio, &dum_ir,bRead,file_version,
-                    mtop ? &mtop->ffparams.fudgeQQ :NULL);
-       if (bRead && debug) 
-         pr_inputrec(debug,0,"inputrec",&dum_ir,FALSE);
-       done_inputrec(&dum_ir);
-      }
-      
-    }
-  }
-  
-  do_test(fio,tpx.bTop,mtop);
-  do_section(fio,eitemTOP,bRead);
-  if (tpx.bTop) {
-    if (mtop) {
-      do_mtop(fio,mtop,bRead, file_version);
-    } else {
-      do_mtop(fio,&dum_top,bRead,file_version);
-      done_mtop(&dum_top,TRUE);
-    }
-  }
-  do_test(fio,tpx.bX,state->x);  
-  do_section(fio,eitemX,bRead);
-  if (tpx.bX) {
-    if (bRead) {
-      state->flags |= (1<<estX);
-    }
-    gmx_fio_ndo_rvec(fio,state->x,state->natoms);
-  }
-  
-  do_test(fio,tpx.bV,state->v);
-  do_section(fio,eitemV,bRead);
-  if (tpx.bV) {
-    if (bRead) {
-      state->flags |= (1<<estV);
-    }
-    gmx_fio_ndo_rvec(fio,state->v,state->natoms);
-  }
-
-  do_test(fio,tpx.bF,f);
-  do_section(fio,eitemF,bRead);
-  if (tpx.bF) gmx_fio_ndo_rvec(fio,f,state->natoms);
-
-  /* Starting with tpx version 26, we have the inputrec
-   * at the end of the file, so we can ignore it 
-   * if the file is never than the software (but still the
-   * same generation - see comments at the top of this file.
-   *
-   * 
-   */
-  ePBC = -1;
-  bPeriodicMols = FALSE;
-  if (file_version >= 26) {
-    do_test(fio,tpx.bIr,ir);
-    do_section(fio,eitemIR,bRead);
-    if (tpx.bIr) {
-      if (file_version >= 53) {
-       /* Removed the pbc info from do_inputrec, since we always want it */
-       if (!bRead) {
-         ePBC          = ir->ePBC;
-         bPeriodicMols = ir->bPeriodicMols;
-       }
-       gmx_fio_do_int(fio,ePBC);
-       gmx_fio_do_gmx_bool(fio,bPeriodicMols);
-      }
-      if (file_generation <= tpx_generation && ir) {
-       do_inputrec(fio, ir,bRead,file_version,mtop ? &mtop->ffparams.fudgeQQ : NULL);
-       if (bRead && debug) 
-         pr_inputrec(debug,0,"inputrec",ir,FALSE);
-       if (file_version < 51)
-         set_box_rel(ir,state);
-       if (file_version < 53) {
-         ePBC          = ir->ePBC;
-         bPeriodicMols = ir->bPeriodicMols;
-       }
-      }
-      if (bRead && ir && file_version >= 53) {
-       /* We need to do this after do_inputrec, since that initializes ir */
-       ir->ePBC          = ePBC;
-       ir->bPeriodicMols = bPeriodicMols;
-      }
-    }
-  }
-
-    if (bRead)
-    {
-        if (tpx.bIr && ir)
-        {
-            if (state->ngtc == 0)
-            {
-                /* Reading old version without tcoupl state data: set it */
-                init_gtc_state(state,ir->opts.ngtc,0,ir->opts.nhchainlength);
-            }
-            if (tpx.bTop && mtop)
-            {
-                if (file_version < 57)
-                {
-                    if (mtop->moltype[0].ilist[F_DISRES].nr > 0)
-                    {
-                        ir->eDisre = edrSimple;
-                    }
-                    else
-                    {
-                        ir->eDisre = edrNone;
-                    }
-                }
-                set_disres_npair(mtop);
-            }
-        }
-
-        if (tpx.bTop && mtop)
-        {
-            gmx_mtop_finalize(mtop);
-        }
-
-        if (file_version >= 57)
-        {
-            char *env;
-            int  ienv;
-            env = getenv("GMX_NOCHARGEGROUPS");
-            if (env != NULL)
-            {
-                sscanf(env,"%d",&ienv);
-                fprintf(stderr,"\nFound env.var. GMX_NOCHARGEGROUPS = %d\n",
-                        ienv);
-                if (ienv > 0)
-                {
-                    fprintf(stderr,
-                            "Will make single atomic charge groups in non-solvent%s\n",
-                            ienv > 1 ? " and solvent" : "");
-                    gmx_mtop_make_atomic_charge_groups(mtop,ienv==1);
-                }
-                fprintf(stderr,"\n");
-            }
-        }
-    }
-
-    return ePBC;
-}
-
-/************************************************************
- *
- *  The following routines are the exported ones
- *
- ************************************************************/
-
-t_fileio *open_tpx(const char *fn,const char *mode)
-{
-  return gmx_fio_open(fn,mode);
-}    
-void close_tpx(t_fileio *fio)
-{
-  gmx_fio_close(fio);
-}
-
-void read_tpxheader(const char *fn, t_tpxheader *tpx, gmx_bool TopOnlyOK,
-                    int *file_version, int *file_generation)
-{
-  t_fileio *fio;
-
-  fio = open_tpx(fn,"r");
-  do_tpxheader(fio,TRUE,tpx,TopOnlyOK,file_version,file_generation);
-  close_tpx(fio);
-}
-
-void write_tpx_state(const char *fn,
-                    t_inputrec *ir,t_state *state,gmx_mtop_t *mtop)
-{
-  t_fileio *fio;
-
-  fio = open_tpx(fn,"w");
-  do_tpx(fio,FALSE,ir,state,NULL,mtop,FALSE);
-  close_tpx(fio);
-}
-
-void read_tpx_state(const char *fn,
-                   t_inputrec *ir,t_state *state,rvec *f,gmx_mtop_t *mtop)
-{
-  t_fileio *fio;
-       
-  fio = open_tpx(fn,"r");
-  do_tpx(fio,TRUE,ir,state,f,mtop,FALSE);
-  close_tpx(fio);
-}
-
-int read_tpx(const char *fn,
-            t_inputrec *ir, matrix box,int *natoms,
-            rvec *x,rvec *v,rvec *f,gmx_mtop_t *mtop)
-{
-  t_fileio *fio;
-  t_state state;
-  int ePBC;
-
-  state.x = x;
-  state.v = v;
-  fio = open_tpx(fn,"r");
-  ePBC = do_tpx(fio,TRUE,ir,&state,f,mtop,TRUE);
-  close_tpx(fio);
-  *natoms = state.natoms;
-  if (box) 
-    copy_mat(state.box,box);
-  state.x = NULL;
-  state.v = NULL;
-  done_state(&state);
-
-  return ePBC;
-}
-
-int read_tpx_top(const char *fn,
-                t_inputrec *ir, matrix box,int *natoms,
-                rvec *x,rvec *v,rvec *f,t_topology *top)
-{
-  gmx_mtop_t mtop;
-  t_topology *ltop;
-  int ePBC;
-
-  ePBC = read_tpx(fn,ir,box,natoms,x,v,f,&mtop);
-  
-  *top = gmx_mtop_t_to_t_topology(&mtop);
-
-  return ePBC;
-}
-
-gmx_bool fn2bTPX(const char *file)
-{
-  switch (fn2ftp(file)) {
-  case efTPR:
-  case efTPB:
-  case efTPA:
-    return TRUE;
-  default:
-    return FALSE;
-  }
-}
-
-gmx_bool read_tps_conf(const char *infile,char *title,t_topology *top,int *ePBC,
-                  rvec **x,rvec **v,matrix box,gmx_bool bMass)
-{
-  t_tpxheader  header;
-  int          natoms,i,version,generation;
-  gmx_bool         bTop,bXNULL;
-  gmx_mtop_t   *mtop;
-  t_topology   *topconv;
-  gmx_atomprop_t aps;
-  
-  bTop = fn2bTPX(infile);
-  *ePBC = -1;
-  if (bTop) {
-    read_tpxheader(infile,&header,TRUE,&version,&generation);
-    if (x)
-      snew(*x,header.natoms);
-    if (v)
-      snew(*v,header.natoms);
-    snew(mtop,1);
-    *ePBC = read_tpx(infile,NULL,box,&natoms,
-                    (x==NULL) ? NULL : *x,(v==NULL) ? NULL : *v,NULL,mtop);
-    *top = gmx_mtop_t_to_t_topology(mtop);
-    sfree(mtop);
-    strcpy(title,*top->name);
-    tpx_make_chain_identifiers(&top->atoms,&top->mols);
-  }
-  else {
-    get_stx_coordnum(infile,&natoms);
-    init_t_atoms(&top->atoms,natoms,FALSE);
-    bXNULL = (x == NULL);
-    snew(*x,natoms);
-    if (v)
-      snew(*v,natoms);
-    read_stx_conf(infile,title,&top->atoms,*x,(v==NULL) ? NULL : *v,ePBC,box);
-    if (bXNULL) {
-      sfree(*x);
-      x = NULL;
-    }
-    if (bMass) {
-      aps = gmx_atomprop_init();
-      for(i=0; (i<natoms); i++)
-       if (!gmx_atomprop_query(aps,epropMass,
-                               *top->atoms.resinfo[top->atoms.atom[i].resind].name,
-                               *top->atoms.atomname[i],
-                               &(top->atoms.atom[i].m))) {
-         if (debug) 
-           fprintf(debug,"Can not find mass for atom %s %d %s, setting to 1\n",
-                   *top->atoms.resinfo[top->atoms.atom[i].resind].name,
-                   top->atoms.resinfo[top->atoms.atom[i].resind].nr,
-                   *top->atoms.atomname[i]);
-       }
-      gmx_atomprop_destroy(aps);
-    }
-    top->idef.ntypes=-1;
-  }
-
-  return bTop;
-}
diff --git a/src/gmxlib/trajana/.cvsignore b/src/gmxlib/trajana/.cvsignore
deleted file mode 100644 (file)
index e9407c9..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-Makefile
-Makefile.in
-.libs
-.deps
diff --git a/src/gmxlib/trajana/.gitignore b/src/gmxlib/trajana/.gitignore
deleted file mode 100644 (file)
index c8b0843..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-.deps
-.libs
diff --git a/src/gmxlib/trajana/Makefile.am b/src/gmxlib/trajana/Makefile.am
deleted file mode 100644 (file)
index ce7b199..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-# Convenience library for common trajectory analysis routines - not installed
-
-AM_CPPFLAGS= -I$(top_srcdir)/include 
-
-noinst_LTLIBRARIES = libtrajana.la
-
-libtrajana_la_SOURCES =        \
-       centerofmass.c  displacement.c  indexutil.c     nbsearch.c \
-       poscalc.c       position.c      trajana.c
-
-CLEANFILES     = *.la *~ \\\#* 
diff --git a/src/gmxlib/trajana/centerofmass.c b/src/gmxlib/trajana/centerofmass.c
deleted file mode 100644 (file)
index bc46cfd..0000000
+++ /dev/null
@@ -1,577 +0,0 @@
-/*
- *
- *                This source code is part of
- *
- *                 G   R   O   M   A   C   S
- *
- *          GROningen MAchine for Chemical Simulations
- *
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
- * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
- * Copyright (c) 2001-2009, The GROMACS development team,
- * check out http://www.gromacs.org for more information.
-
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * If you want to redistribute modifications, please consider that
- * scientific software is very special. Version control is crucial -
- * bugs must be traceable. We will be happy to consider code for
- * inclusion in the official distribution, but derived work must not
- * be called official GROMACS. Details are found in the README & COPYING
- * files - if they are missing, get the official version at www.gromacs.org.
- *
- * To help us fund GROMACS development, we humbly ask that you cite
- * the papers on the package - you can find them in the top README file.
- *
- * For more info, check our website at http://www.gromacs.org
- */
-/*! \internal \file
- * \brief Implementation of functions in centerofmass.h.
- */
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <typedefs.h>
-#include <pbc.h>
-#include <vec.h>
-
-#include <centerofmass.h>
-
-/*!
- * \param[in]  top    Topology structure (unused, can be NULL).
- * \param[in]  x      Position vectors of all atoms.
- * \param[in]  nrefat Number of atoms in the index.
- * \param[in]  index  Indices of atoms.
- * \param[out] xout   COG position for the indexed atoms.
- * \returns    0 on success.
- */
-int
-gmx_calc_cog(t_topology *top, rvec x[], int nrefat, atom_id index[], rvec xout)
-{
-    int                 m, j, ai;
-
-    clear_rvec(xout);
-    for (m = 0; m < nrefat; ++m)
-    {
-        ai = index[m];
-        rvec_inc(xout, x[ai]);
-    }
-    svmul(1.0/nrefat, xout, xout);
-    return 0;
-}
-
-/*!
- * \param[in]  top    Topology structure with masses.
- * \param[in]  x      Position vectors of all atoms.
- * \param[in]  nrefat Number of atoms in the index.
- * \param[in]  index  Indices of atoms.
- * \param[out] xout   COM position for the indexed atoms.
- * \returns    0 on success, EINVAL if \p top is NULL.
- *
- * Works exactly as gmx_calc_cog() with the exception that a center of
- * mass are calculated, and hence a topology with masses is required.
- */
-int
-gmx_calc_com(t_topology *top, rvec x[], int nrefat, atom_id index[], rvec xout)
-{
-    int                 m, j, ai;
-    real                mass, mtot;
-
-    if (!top)
-    {
-        gmx_incons("no masses available while mass weighting was requested");
-        return EINVAL;
-    }
-    clear_rvec(xout);
-    mtot = 0;
-    for (m = 0; m < nrefat; ++m)
-    {
-        ai = index[m];
-        mass = top->atoms.atom[ai].m;
-        for (j = 0; j < DIM; ++j)
-        {
-            xout[j] += mass * x[ai][j];
-        }
-        mtot += mass;
-    }
-    svmul(1.0/mtot, xout, xout);
-    return 0;
-}
-
-/*!
- * \param[in]  top    Topology structure with masses.
- * \param[in]  f      Forces on all atoms.
- * \param[in]  nrefat Number of atoms in the index.
- * \param[in]  index  Indices of atoms.
- * \param[out] fout   Force on the COG position for the indexed atoms.
- * \returns    0 on success, EINVAL if \p top is NULL.
- *
- * No special function is provided for calculating the force on the center of
- * mass, because this can be achieved with gmx_calc_cog().
- */
-int
-gmx_calc_cog_f(t_topology *top, rvec f[], int nrefat, atom_id index[], rvec fout)
-{
-    int                 m, j, ai;
-    real                mass, mtot;
-
-    if (!top)
-    {
-        gmx_incons("no masses available while mass weighting was needed");
-        return EINVAL;
-    }
-    clear_rvec(fout);
-    mtot = 0;
-    for (m = 0; m < nrefat; ++m)
-    {
-        ai = index[m];
-        mass = top->atoms.atom[ai].m;
-        for (j = 0; j < DIM; ++j)
-        {
-            fout[j] += f[ai][j] / mass;
-        }
-        mtot += mass;
-    }
-    svmul(mtot, fout, fout);
-    return 0;
-}
-
-/*!
- * \param[in]  top   Topology structure with masses
- *   (can be NULL if \p bMASS==FALSE).
- * \param[in]  x     Position vectors of all atoms.
- * \param[in]  nrefat Number of atoms in the index.
- * \param[in]  index Indices of atoms.
- * \param[in]  bMass If TRUE, mass weighting is used.
- * \param[out] xout  COM/COG position for the indexed atoms.
- * \returns    0 on success, EINVAL if \p top is NULL and \p bMass is TRUE.
- *
- * Calls either gmx_calc_com() or gmx_calc_cog() depending on the value of
- * \p bMass.
- * Other parameters are passed unmodified to these functions.
- */
-int
-gmx_calc_comg(t_topology *top, rvec x[], int nrefat, atom_id index[],
-              gmx_bool bMass, rvec xout)
-{
-    if (bMass)
-    {
-        return gmx_calc_com(top, x, nrefat, index, xout);
-    }
-    else
-    {
-        return gmx_calc_cog(top, x, nrefat, index, xout);
-    }
-}
-
-/*!
- * \param[in]  top   Topology structure with masses
- *   (can be NULL if \p bMASS==TRUE).
- * \param[in]  x     Forces on all atoms.
- * \param[in]  nrefat Number of atoms in the index.
- * \param[in]  index Indices of atoms.
- * \param[in]  bMass If TRUE, force on COM is calculated.
- * \param[out] xout  Force on the COM/COG position for the indexed atoms.
- * \returns    0 on success, EINVAL if \p top is NULL and \p bMass is FALSE.
- *
- * Calls either gmx_calc_cog() or gmx_calc_cog_f() depending on the value of
- * \p bMass.
- * Other parameters are passed unmodified to these functions.
- */
-int
-gmx_calc_comg_f(t_topology *top, rvec f[], int nrefat, atom_id index[],
-                gmx_bool bMass, rvec fout)
-{
-    if (bMass)
-    {
-        return gmx_calc_cog(top, f, nrefat, index, fout);
-    }
-    else
-    {
-        return gmx_calc_cog_f(top, f, nrefat, index, fout);
-    }
-}
-
-
-/*!
- * \param[in]  top    Topology structure (unused, can be NULL).
- * \param[in]  x      Position vectors of all atoms.
- * \param[in]  pbc    Periodic boundary conditions structure.
- * \param[in]  nrefat Number of atoms in the index.
- * \param[in]  index  Indices of atoms.
- * \param[out] xout   COG position for the indexed atoms.
- * \returns    0 on success.
- *
- * Works exactly as gmx_calc_com_pbc(), but calculates the center of geometry.
- */
-int
-gmx_calc_cog_pbc(t_topology *top, rvec x[], t_pbc *pbc,
-                 int nrefat, atom_id index[], rvec xout)
-{
-    const real          tol = 1e-4;
-    gmx_bool                bChanged;
-    int                 m, j, ai, iter;
-    rvec                dx, xtest;
-
-    /* First simple calculation */
-    gmx_calc_cog(top, x, nrefat, index, xout);
-    /* Now check if any atom is more than half the box from the COM */
-    if (pbc)
-    {
-        iter = 0;
-        do
-        {
-            bChanged = FALSE;
-            for (m = 0; m < nrefat; ++m)
-            {
-                ai = index[m];
-                pbc_dx(pbc, x[ai], xout, dx);
-                rvec_add(xout, dx, xtest);
-                for (j = 0; j < DIM; ++j)
-                {
-                    if (fabs(xtest[j] - x[ai][j]) > tol)
-                    {
-                        /* Here we have used the wrong image for contributing to the COM */
-                        xout[j] += (xtest[j] - x[ai][j]) / nrefat;
-                        x[ai][j] = xtest[j];
-                        bChanged = TRUE;
-                    }
-                }
-            }
-            iter++;
-        }
-        while (bChanged);
-    }
-    return 0;
-}
-
-/*!
- * \param[in]  top    Topology structure with masses.
- * \param[in]  x      Position vectors of all atoms.
- * \param[in]  pbc    Periodic boundary conditions structure.
- * \param[in]  nrefat Number of atoms in the index.
- * \param[in]  index  Indices of atoms.
- * \param[out] xout   COM position for the indexed atoms.
- * \returns    0 on success, EINVAL if \p top is NULL.
- *
- * Works as gmx_calc_com(), but takes into account periodic boundary
- * conditions: If any atom is more than half the box from the COM,
- * it is wrapped around and a new COM is calculated. This is repeated
- * until no atoms violate the condition.
- *
- * Modified from src/tools/gmx_sorient.c in Gromacs distribution.
- */
-int
-gmx_calc_com_pbc(t_topology *top, rvec x[], t_pbc *pbc,
-                 int nrefat, atom_id index[], rvec xout)
-{
-    const real          tol = 1e-4;
-    gmx_bool                bChanged;
-    int                 m, j, ai, iter;
-    real                mass, mtot;
-    rvec                dx, xtest;
-
-    if (!top)
-    {
-        gmx_incons("no masses available while mass weighting was requested");
-        return EINVAL;
-    }
-    /* First simple calculation */
-    clear_rvec(xout);
-    mtot = 0;
-    for (m = 0; m < nrefat; ++m)
-    {
-        ai = index[m];
-        mass = top->atoms.atom[ai].m;
-        for (j = 0; j < DIM; ++j)
-        {
-            xout[j] += mass * x[ai][j];
-        }
-        mtot += mass;
-    }
-    svmul(1.0/mtot, xout, xout);
-    /* Now check if any atom is more than half the box from the COM */
-    if (pbc)
-    {
-        iter = 0;
-        do
-        {
-            bChanged = FALSE;
-            for (m = 0; m < nrefat; ++m)
-            {
-                ai = index[m];
-                mass = top->atoms.atom[ai].m / mtot;
-                pbc_dx(pbc, x[ai], xout, dx);
-                rvec_add(xout, dx, xtest);
-                for (j = 0; j < DIM; ++j)
-                {
-                    if (fabs(xtest[j] - x[ai][j]) > tol)
-                    {
-                        /* Here we have used the wrong image for contributing to the COM */
-                        xout[j] += mass * (xtest[j] - x[ai][j]);
-                        x[ai][j] = xtest[j];
-                        bChanged = TRUE;
-                    }
-                }
-            }
-            iter++;
-        }
-        while (bChanged);
-    }
-    return 0;
-}
-
-/*!
- * \param[in]  top   Topology structure with masses
- *   (can be NULL if \p bMASS==FALSE).
- * \param[in]  x     Position vectors of all atoms.
- * \param[in]  pbc    Periodic boundary conditions structure.
- * \param[in]  nrefat Number of atoms in the index.
- * \param[in]  index Indices of atoms.
- * \param[in]  bMass If TRUE, mass weighting is used.
- * \param[out] xout  COM/COG position for the indexed atoms.
- * \returns    0 on success, EINVAL if \p top is NULL and \p bMass is TRUE.
- *
- * Calls either gmx_calc_com() or gmx_calc_cog() depending on the value of
- * \p bMass.
- * Other parameters are passed unmodified to these functions.
- */
-int
-gmx_calc_comg_pbc(t_topology *top, rvec x[], t_pbc *pbc,
-                  int nrefat, atom_id index[], gmx_bool bMass, rvec xout)
-{
-    if (bMass)
-    {
-        return gmx_calc_com_pbc(top, x, pbc, nrefat, index, xout);
-    }
-    else
-    {
-        return gmx_calc_cog_pbc(top, x, pbc, nrefat, index, xout);
-    }
-}
-
-
-/*!
- * \param[in]  top   Topology structure (unused, can be NULL).
- * \param[in]  x     Position vectors of all atoms.
- * \param[in]  block t_block structure that divides \p index into blocks.
- * \param[in]  index Indices of atoms.
- * \param[out] xout  \p block->nr COG positions.
- * \returns    0 on success.
- */
-int
-gmx_calc_cog_block(t_topology *top, rvec x[], t_block *block, atom_id index[],
-                   rvec xout[])
-{
-    int                 b, i, ai;
-    rvec                xb;
-
-    for (b = 0; b < block->nr; ++b)
-    {
-        clear_rvec(xb);
-        for (i = block->index[b]; i < block->index[b+1]; ++i)
-        {
-            ai = index[i];
-            rvec_inc(xb, x[ai]);
-        }
-        svmul(1.0/(block->index[b+1] - block->index[b]), xb, xout[b]);
-    }
-    return 0;
-}
-
-/*!
- * \param[in]  top   Topology structure with masses.
- * \param[in]  x     Position vectors of all atoms.
- * \param[in]  block t_block structure that divides \p index into blocks.
- * \param[in]  index Indices of atoms.
- * \param[out] xout  \p block->nr COM positions.
- * \returns    0 on success, EINVAL if \p top is NULL.
- *
- * Works exactly as gmx_calc_cog_block() with the exception that centers of
- * mass are calculated, and hence a topology with masses is required.
- */
-int
-gmx_calc_com_block(t_topology *top, rvec x[], t_block *block, atom_id index[],
-                   rvec xout[])
-{
-    int                 b, i, ai, d;
-    rvec                xb;
-    real                mass, mtot;
-
-    if (!top)
-    {
-        gmx_incons("no masses available while mass weighting was requested");
-        return EINVAL;
-    }
-    for (b = 0; b < block->nr; ++b)
-    {
-        clear_rvec(xb);
-        mtot = 0;
-        for (i = block->index[b]; i < block->index[b+1]; ++i)
-        {
-            ai = index[i];
-            mass = top->atoms.atom[ai].m;
-            for (d = 0; d < DIM; ++d)
-            {
-                xb[d] += mass * x[ai][d];
-            }
-            mtot += mass;
-        }
-        svmul(1.0/mtot, xb, xout[b]);
-    }
-    return 0;
-}
-
-/*!
- * \param[in]  top   Topology structure with masses.
- * \param[in]  f     Forces on all atoms.
- * \param[in]  block t_block structure that divides \p index into blocks.
- * \param[in]  index Indices of atoms.
- * \param[out] xout  \p block->nr Forces on COG positions.
- * \returns    0 on success, EINVAL if \p top is NULL.
- */
-int
-gmx_calc_cog_f_block(t_topology *top, rvec f[], t_block *block, atom_id index[],
-                     rvec fout[])
-{
-    int                 b, i, ai, d;
-    rvec                fb;
-    real                mass, mtot;
-
-    if (!top)
-    {
-        gmx_incons("no masses available while mass weighting was needed");
-        return EINVAL;
-    }
-    for (b = 0; b < block->nr; ++b)
-    {
-        clear_rvec(fb);
-        mtot = 0;
-        for (i = block->index[b]; i < block->index[b+1]; ++i)
-        {
-            ai = index[i];
-            mass = top->atoms.atom[ai].m;
-            for (d = 0; d < DIM; ++d)
-            {
-                fb[d] += f[ai][d] / mass;
-            }
-            mtot += mass;
-        }
-        svmul(mtot, fb, fout[b]);
-    }
-    return 0;
-}
-
-/*!
- * \param[in]  top   Topology structure with masses
- *   (can be NULL if \p bMASS==FALSE).
- * \param[in]  x     Position vectors of all atoms.
- * \param[in]  block t_block structure that divides \p index into blocks.
- * \param[in]  index Indices of atoms.
- * \param[in]  bMass If TRUE, mass weighting is used.
- * \param[out] xout  \p block->nr COM/COG positions.
- * \returns    0 on success, EINVAL if \p top is NULL and \p bMass is TRUE.
- *
- * Calls either gmx_calc_com_block() or gmx_calc_cog_block() depending on the
- * value of \p bMass.
- * Other parameters are passed unmodified to these functions.
- */
-int
-gmx_calc_comg_block(t_topology *top, rvec x[], t_block *block, atom_id index[],
-                    gmx_bool bMass, rvec xout[])
-{
-    if (bMass)
-    {
-        return gmx_calc_com_block(top, x, block, index, xout);
-    }
-    else
-    {
-        return gmx_calc_cog_block(top, x, block, index, xout);
-    }
-}
-
-/*!
- * \param[in]  top   Topology structure with masses
- *   (can be NULL if \p bMASS==FALSE).
- * \param[in]  f     Forces on all atoms.
- * \param[in]  block t_block structure that divides \p index into blocks.
- * \param[in]  index Indices of atoms.
- * \param[in]  bMass If TRUE, force on COM is calculated.
- * \param[out] xout  \p block->nr forces on the COM/COG positions.
- * \returns    0 on success, EINVAL if \p top is NULL and \p bMass is TRUE.
- *
- * Calls either gmx_calc_com_block() or gmx_calc_cog_block() depending on the
- * value of \p bMass.
- * Other parameters are passed unmodified to these functions.
- */
-int
-gmx_calc_comg_f_block(t_topology *top, rvec f[], t_block *block, atom_id index[],
-                      gmx_bool bMass, rvec fout[])
-{
-    if (bMass)
-    {
-        return gmx_calc_cog_block(top, f, block, index, fout);
-    }
-    else
-    {
-        return gmx_calc_cog_f_block(top, f, block, index, fout);
-    }
-}
-
-/*!
- * \param[in]  top   Topology structure with masses
- *   (can be NULL if \p bMASS==FALSE).
- * \param[in]  x     Position vectors of all atoms.
- * \param[in]  block Blocks for calculation.
- * \param[in]  bMass If TRUE, mass weighting is used.
- * \param[out] xout  \p block->nr COM/COG positions.
- * \returns    0 on success, EINVAL if \p top is NULL and \p bMass is TRUE.
- *
- * Calls gmx_calc_comg_block(), converting the \p t_blocka structure into
- * a \p t_block and an index. Other parameters are passed unmodified.
- *
- * \attention
- * This function assumes that a pointer to \c t_blocka can be safely typecast
- * into \c t_block such that the index fields can still be referenced.
- * With the present Gromacs defitions of these types, this is the case,
- * but if the layout of these structures is changed, this may lead to strange
- * crashes.
- */
-int
-gmx_calc_comg_blocka(t_topology *top, rvec x[], t_blocka *block,
-                     gmx_bool bMass, rvec xout[])
-{
-    /* TODO: It would probably be better to do this without the type cast */
-    return gmx_calc_comg_block(top, x, (t_block *)block, block->a, bMass, xout);
-}
-
-/*!
- * \param[in]  top   Topology structure with masses
- *   (can be NULL if \p bMASS==TRUE).
- * \param[in]  f     Forces on all atoms.
- * \param[in]  block Blocks for calculation.
- * \param[in]  bMass If TRUE, force on COM is calculated.
- * \param[out] fout  \p block->nr forces on the COM/COG positions.
- * \returns    0 on success, EINVAL if \p top is NULL and \p bMass is FALSE.
- *
- * Calls gmx_calc_comg_f_block(), converting the \p t_blocka structure into
- * a \p t_block and an index. Other parameters are passed unmodified.
- *
- * \attention
- * This function assumes that a pointer to \c t_blocka can be safely typecast
- * into \c t_block such that the index fields can still be referenced.
- * With the present Gromacs defitions of these types, this is the case,
- * but if the layout of these structures is changed, this may lead to strange
- * crashes.
- */
-int
-gmx_calc_comg_f_blocka(t_topology *top, rvec f[], t_blocka *block,
-                       gmx_bool bMass, rvec fout[])
-{
-    /* TODO: It would probably be better to do this without the type cast */
-    return gmx_calc_comg_f_block(top, f, (t_block *)block, block->a, bMass, fout);
-}
diff --git a/src/gmxlib/trajana/indexutil.c b/src/gmxlib/trajana/indexutil.c
deleted file mode 100644 (file)
index ab5c131..0000000
+++ /dev/null
@@ -1,1453 +0,0 @@
-/*
- *
- *                This source code is part of
- *
- *                 G   R   O   M   A   C   S
- *
- *          GROningen MAchine for Chemical Simulations
- *
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
- * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
- * Copyright (c) 2001-2009, The GROMACS development team,
- * check out http://www.gromacs.org for more information.
-
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * If you want to redistribute modifications, please consider that
- * scientific software is very special. Version control is crucial -
- * bugs must be traceable. We will be happy to consider code for
- * inclusion in the official distribution, but derived work must not
- * be called official GROMACS. Details are found in the README & COPYING
- * files - if they are missing, get the official version at www.gromacs.org.
- *
- * To help us fund GROMACS development, we humbly ask that you cite
- * the papers on the package - you can find them in the top README file.
- *
- * For more info, check our website at http://www.gromacs.org
- */
-/*! \internal \file
- * \brief Implementation of functions in indexutil.h.
- */
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <index.h>
-#include <smalloc.h>
-#include <string2.h>
-#include <typedefs.h>
-#include <gmx_fatal.h>
-
-#include <indexutil.h>
-
-/********************************************************************
- * gmx_ana_indexgrps_t functions
- ********************************************************************/
-
-/*! \internal \brief
- * Stores a set of index groups.
- */
-struct gmx_ana_indexgrps_t
-{
-    /** Number of index groups. */
-    int                 nr;
-    /** Array of index groups. */
-    gmx_ana_index_t    *g;
-};
-
-/*!
- * \param[out] g     Index group structure.
- * \param[in]  ngrps Number of groups for which memory is allocated.
- */
-void
-gmx_ana_indexgrps_alloc(gmx_ana_indexgrps_t **g, int ngrps)
-{
-    snew(*g, 1);
-    (*g)->nr = ngrps;
-    snew((*g)->g,    ngrps);
-}
-
-/*!
- * \param[out] g     Index group structure.
- * \param[in]  ngrps Number of index groups.
- * \param[in]  isize Array of index group sizes.
- * \param[in]  index Array of pointers to indices of each group.
- * \param[in]  name  Array of names of the groups.
- * \param[in]  bFree If TRUE, the \p isize, \p index and \p name arrays
- *   are freed after they have been copied.
- */
-void
-gmx_ana_indexgrps_set(gmx_ana_indexgrps_t **g, int ngrps, int *isize,
-                      atom_id **index, char **name, gmx_bool bFree)
-{
-    int  i;
-
-    gmx_ana_indexgrps_alloc(g, ngrps);
-    for (i = 0; i < ngrps; ++i)
-    {
-        gmx_ana_index_set(&(*g)->g[i], isize[i], index[i], name[i], isize[i]);
-    }
-    if (bFree)
-    {
-        sfree(isize);
-        sfree(index);
-        sfree(name);
-    }
-}
-
-/*!
- * \param[out] g     Index group structure.
- * \param[in]  top   Topology structure.
- * \param[in]  fnm   File name for the index file.
- *   Memory is automatically allocated.
- *
- * One or both of \p top or \p fnm can be NULL.
- * If \p top is NULL, an index file is required and the groups are read
- * from the file (uses Gromacs routine init_index()).
- * If \p fnm is NULL, default groups are constructed based on the
- * topology (uses Gromacs routine analyse()).
- * If both are null, the index group structure is initialized empty.
- */
-void
-gmx_ana_indexgrps_init(gmx_ana_indexgrps_t **g, t_topology *top, 
-                       const char *fnm)
-{
-    t_blocka *block = NULL;
-    char    **names = NULL;
-    int       i, j;
-
-    if (fnm)
-    {
-        block = init_index(fnm, &names);
-    }
-    else if (top)
-    {
-        block = new_blocka();
-        analyse(&top->atoms, block, &names, FALSE, FALSE);
-    }
-    else
-    {
-        snew(*g, 1);
-        (*g)->nr    = 0;
-        (*g)->g     = NULL;
-        return;
-    }
-
-    gmx_ana_indexgrps_alloc(g, block->nr);
-    for (i = 0; i < block->nr; ++i)
-    {
-        gmx_ana_index_t *grp = &(*g)->g[i];
-
-        grp->isize = block->index[i+1] - block->index[i];
-        snew(grp->index, grp->isize);
-        for (j = 0; j < grp->isize; ++j)
-        {
-            grp->index[j] = block->a[block->index[i]+j];
-        }
-        grp->name = names[i];
-        grp->nalloc_index = grp->isize;
-    }
-
-    done_blocka(block);
-    sfree(block);
-    sfree(names);
-}
-
-/*!
- * \param[out] g     Index group structure.
- * \param[in]  top   Topology structure.
- * \param[in]  fnm   File name for the index file.
- * \param[in]  ngrps Number of required groups.
- *   Memory is automatically allocated.
- *
- * One of \p top or \p fnm can be NULL, but not both.
- * If \p top is NULL, an index file is required and the groups are read
- * from the file (uses Gromacs routine rd_index()).
- * If \p fnm is NULL, default groups are constructed based on the
- * topology (uses Gromacs routine get_index()).
- */
-void
-gmx_ana_indexgrps_get(gmx_ana_indexgrps_t **g, t_topology *top, 
-                      const char *fnm, int ngrps)
-{
-    int      *isize;
-    atom_id **index;
-    char    **name;
-
-    snew(isize, ngrps);
-    snew(index, ngrps);
-    snew(name,  ngrps);
-    if (!top)
-    {
-        rd_index(fnm, ngrps, isize, index, name);
-    }
-    else
-    {
-        get_index(&(top->atoms), fnm, ngrps, isize, index, name);
-    }
-    gmx_ana_indexgrps_set(g, ngrps, isize, index, name, TRUE);
-}
-
-/*!
- * \param[out] g     Index group structure.
- * \param[in]  fnm   File name for the index file.
- * \param[in]  ngrps Number of required groups.
- *   Memory is automatically allocated.
- *
- * This is a convenience function for calling the Gromacs routine
- * rd_index().
- */
-void
-gmx_ana_indexgrps_rd(gmx_ana_indexgrps_t **g, const char *fnm, int ngrps)
-{
-    gmx_ana_indexgrps_get(g, NULL, fnm, ngrps);
-}
-
-/*!
- * \param[in] g  Index groups structure.
- *
- * The pointer \p g is invalid after the call.
- */
-void
-gmx_ana_indexgrps_free(gmx_ana_indexgrps_t *g)
-{
-    int  i;
-
-    if (g->nr == 0)
-    {
-        sfree(g);
-        return;
-    }
-    for (i = 0; i < g->nr; ++i)
-    {
-        gmx_ana_index_deinit(&g->g[i]);
-    }
-    sfree(g->g);
-    g->nr    = 0;
-    g->g     = NULL;
-    sfree(g);
-}
-
-/*!
- * \param[out] dest Destination index groups.
- * \param[in]  src  Source index groups.
- *
- * A deep copy is made for all fields, including the group names.
- */
-void
-gmx_ana_indexgrps_clone(gmx_ana_indexgrps_t **dest, gmx_ana_indexgrps_t *src)
-{
-    int g;
-
-    gmx_ana_indexgrps_alloc(dest, src->nr);
-    for (g = 0; g < src->nr; ++g)
-    {
-        gmx_ana_index_copy(&(*dest)->g[g], &src->g[g], TRUE);
-    }
-}
-
-/*!
- * \param[out] g     Index group structure.
- * \returns    TRUE if \p g is empty, i.e., has 0 index groups.
- */
-gmx_bool
-gmx_ana_indexgrps_is_empty(gmx_ana_indexgrps_t *g)
-{
-    return g->nr == 0;
-}
-
-/*!
- * \param[in]  g     Index groups structure.
- * \param[in]  n     Index group number to get.
- * \returns    Pointer to the \p n'th index group in \p g.
- *
- * The returned pointer should not be freed.
- */
-gmx_ana_index_t *
-gmx_ana_indexgrps_get_grp(gmx_ana_indexgrps_t *g, int n)
-{
-    if (n < 0 || n >= g->nr)
-    {
-        return NULL;
-    }
-    return &g->g[n];
-}
-
-/*!
- * \param[out] dest Output structure.
- * \param[in]  src  Input index groups.
- * \param[in]  n    Number of the group to extract.
- * \returns TRUE if \p n is a valid group in \p src, FALSE otherwise.
- */
-gmx_bool
-gmx_ana_indexgrps_extract(gmx_ana_index_t *dest, gmx_ana_indexgrps_t *src, int n)
-{
-    if (n < 0 || n >= src->nr)
-    {
-        dest->isize = 0;
-        return FALSE;
-    }
-
-    gmx_ana_index_copy(dest, &src->g[n], TRUE);
-    return TRUE;
-}
-
-/*!
- * \param[out] dest Output structure.
- * \param[in]  src  Input index groups.
- * \param[in]  name Name (or part of the name) of the group to extract.
- * \returns TRUE if \p name is a valid group in \p src, FALSE otherwise.
- *
- * Uses the Gromacs routine find_group() to find the actual group;
- * the comparison is case-insensitive.
- */
-gmx_bool
-gmx_ana_indexgrps_find(gmx_ana_index_t *dest, gmx_ana_indexgrps_t *src, char *name)
-{
-    int    i;
-    char **names;
-
-    snew(names, src->nr);
-    for (i = 0; i < src->nr; ++i)
-    {
-        names[i] = src->g[i].name;
-    }
-    i = find_group(name, src->nr, names);
-    sfree(names);
-    if (i == NOTSET)
-    {
-        dest->isize = 0;
-        return FALSE;
-    }
-
-    return gmx_ana_indexgrps_extract(dest, src, i);
-}
-
-/*!
- * \param[in]  g      Index groups to print.
- * \param[in]  maxn   Maximum number of indices to print
- *      (-1 = print all, 0 = print only names).
- */
-void
-gmx_ana_indexgrps_print(gmx_ana_indexgrps_t *g, int maxn)
-{
-    int  i;
-
-    for (i = 0; i < g->nr; ++i)
-    {
-        fprintf(stderr, " %2d: ", i);
-        gmx_ana_index_dump(&g->g[i], i, maxn);
-    }
-}
-
-/********************************************************************
- * gmx_ana_index_t functions
- ********************************************************************/
-
-/*!
- * \param[in,out] g      Index group structure.
- * \param[in]     isize  Maximum number of atoms to reserve space for.
- */
-void
-gmx_ana_index_reserve(gmx_ana_index_t *g, int isize)
-{
-    if (g->nalloc_index < isize)
-    {
-        srenew(g->index, isize);
-        g->nalloc_index = isize;
-    }
-}
-
-/*!
- * \param[in,out] g      Index group structure.
- *
- * Resizes the memory allocated for holding the indices such that the
- * current contents fit.
- */
-void
-gmx_ana_index_squeeze(gmx_ana_index_t *g)
-{
-    srenew(g->index, g->isize);
-    g->nalloc_index = g->isize;
-}
-
-/*!
- * \param[out] g      Output structure.
- *
- * Any contents of \p g are discarded without freeing.
- */
-void
-gmx_ana_index_clear(gmx_ana_index_t *g)
-{
-    g->isize        = 0;
-    g->index        = NULL;
-    g->name         = NULL;
-    g->nalloc_index = 0;
-}
-
-/*!
- * \param[out] g      Output structure.
- * \param[in]  isize  Number of atoms in the new group.
- * \param[in]  index  Array of \p isize atoms (can be NULL if \p isize is 0).
- * \param[in]  name   Name for the new group (can be NULL).
- * \param[in]  nalloc Number of elements allocated for \p index
- *   (if 0, \p index is not freed in gmx_ana_index_deinit())
- *
- * No copy if \p index is made.
- */
-void
-gmx_ana_index_set(gmx_ana_index_t *g, int isize, atom_id *index, char *name,
-                  int nalloc)
-{
-    g->isize        = isize;
-    g->index        = index;
-    g->name         = name;
-    g->nalloc_index = nalloc;
-}
-
-/*!
- * \param[out] g      Output structure.
- * \param[in]  natoms Number of atoms.
- * \param[in]  name   Name for the new group (can be NULL).
- */
-void
-gmx_ana_index_init_simple(gmx_ana_index_t *g, int natoms, char *name)
-{
-    int  i;
-
-    g->isize = natoms;
-    snew(g->index, natoms);
-    for (i = 0; i < natoms; ++i)
-    {
-        g->index[i] = i;
-    }
-    g->name = name;
-    g->nalloc_index = natoms;
-}
-
-/*!
- * \param[in] g  Index group structure.
- *
- * The pointer \p g is not freed.
- */
-void
-gmx_ana_index_deinit(gmx_ana_index_t *g)
-{
-    if (g->nalloc_index > 0)
-    {
-        sfree(g->index);
-    }
-    sfree(g->name);
-    gmx_ana_index_clear(g);
-}
-
-/*!
- * \param[out] dest   Destination index group.
- * \param[in]  src    Source index group.
- * \param[in]  bAlloc If TRUE, memory is allocated at \p dest; otherwise,
- *   it is assumed that enough memory has been allocated for index.
- *
- * A deep copy of the name is only made if \p bAlloc is TRUE.
- */
-void
-gmx_ana_index_copy(gmx_ana_index_t *dest, gmx_ana_index_t *src, gmx_bool bAlloc)
-{
-    dest->isize = src->isize;
-    if (dest->isize > 0)
-    {
-        if (bAlloc)
-        {
-            snew(dest->index, dest->isize);
-            dest->nalloc_index = dest->isize;
-        }
-        memcpy(dest->index, src->index, dest->isize*sizeof(*dest->index));
-    }
-    if (bAlloc && src->name)
-    {
-        dest->name = strdup(src->name);
-    }
-    else if (bAlloc || src->name)
-    {
-        dest->name = src->name;
-    }
-}
-
-/*!
- * \param[in]  g      Index group to print.
- * \param[in]  i      Group number to use if the name is NULL.
- * \param[in]  maxn   Maximum number of indices to print (-1 = print all).
- */
-void
-gmx_ana_index_dump(gmx_ana_index_t *g, int i, int maxn)
-{
-    int  j, n;
-
-    if (g->name)
-    {
-        fprintf(stderr, "\"%s\"", g->name);
-    }
-    else
-    {
-        fprintf(stderr, "Group %d", i+1);
-    }
-    fprintf(stderr, " (%d atoms)", g->isize);
-    if (maxn != 0)
-    {
-        fprintf(stderr, ":");
-        n = g->isize;
-        if (maxn >= 0 && n > maxn)
-        {
-            n = maxn;
-        }
-        for (j = 0; j < n; ++j)
-        {
-            fprintf(stderr, " %d", g->index[j]+1);
-        }
-        if (n < g->isize)
-        {
-            fprintf(stderr, " ...");
-        }
-    }
-    fprintf(stderr, "\n");
-}
-
-/*!
- * \param[in]  g      Input index group.
- * \param[in]  natoms Number of atoms to check against.
- *
- * If any atom index in the index group is less than zero or >= \p natoms,
- * gmx_fatal() is called.
- */
-void
-gmx_ana_index_check(gmx_ana_index_t *g, int natoms)
-{
-    int  j;
-
-    for (j = 0; j < g->isize; ++j)
-    {
-        if (g->index[j] >= natoms)
-        {
-            gmx_fatal(FARGS,"Atom index (%d) in index group %s (%d atoms) "
-              "larger than number of atoms in trajectory (%d atoms)",
-              g->index[j], g->name, g->isize, natoms);
-        }
-        else if (g->index[j] < 0)
-        {
-            gmx_fatal(FARGS,"Atom index (%d) in index group %s (%d atoms) "
-              "is less than zero",
-              g->index[j], g->name, g->isize);
-        }
-    }
-}
-
-/*!
- * \param[in]  g      Index group to check.
- * \returns    TRUE if the index group is sorted and has no duplicates,
- *   FALSE otherwise.
- */
-gmx_bool
-gmx_ana_index_check_sorted(gmx_ana_index_t *g)
-{
-    int  i;
-
-    for (i = 0; i < g->isize-1; ++i)
-    {
-        if (g->index[i+1] <= g->index[i])
-        {
-            return FALSE;
-        }
-    }
-    return TRUE;
-}
-
-/********************************************************************
- * Set operations
- ********************************************************************/
-
-/** Helper function for gmx_ana_index_sort(). */
-static int
-cmp_atomid(const void *a, const void *b)
-{
-    if (*(atom_id *)a < *(atom_id *)b) return -1;
-    if (*(atom_id *)a > *(atom_id *)b) return 1;
-    return 0;
-}
-
-/*!
- * \param[in,out] g  Index group to be sorted.
- */
-void
-gmx_ana_index_sort(gmx_ana_index_t *g)
-{
-    qsort(g->index, g->isize, sizeof(*g->index), cmp_atomid);
-}
-
-/*!
- * \param[in]  a      Index group to check.
- * \param[in]  b      Index group to check.
- * \returns    TRUE if \p a and \p b are equal, FALSE otherwise.
- */
-gmx_bool
-gmx_ana_index_equals(gmx_ana_index_t *a, gmx_ana_index_t *b)
-{
-    int  i;
-
-    if (a->isize != b->isize)
-    {
-        return FALSE;
-    }
-    for (i = 0; i < a->isize; ++i)
-    {
-        if (a->index[i] != b->index[i])
-        {
-            return FALSE;
-        }
-    }
-    return TRUE;
-}
-
-/*!
- * \param[in]  a      Index group to check against.
- * \param[in]  b      Index group to check.
- * \returns    TRUE if \p b is contained in \p a,
- *   FALSE otherwise.
- *
- * If the elements are not in the same order in both groups, the function
- * fails. However, the groups do not need to be sorted.
- */
-gmx_bool
-gmx_ana_index_contains(gmx_ana_index_t *a, gmx_ana_index_t *b)
-{
-    int  i, j;
-
-    for (i = j = 0; j < b->isize; ++i, ++j) {
-        while (i < a->isize && a->index[i] != b->index[j])
-        {
-            ++i;
-        }
-        if (i == a->isize)
-        {
-            return FALSE;
-        }
-    }
-    return TRUE;
-}
-
-/*!
- * \param[out] dest Output index group (the intersection of \p a and \p b).
- * \param[in]  a    First index group.
- * \param[in]  b    Second index group.
- *
- * \p dest can be the same as \p a or \p b.
- */
-void
-gmx_ana_index_intersection(gmx_ana_index_t *dest,
-                           gmx_ana_index_t *a, gmx_ana_index_t *b)
-{
-    int i, j, k;
-
-    for (i = j = k = 0; i < a->isize && j < b->isize; ++i) {
-        while (j < b->isize && b->index[j] < a->index[i])
-        {
-            ++j;
-        }
-        if (j < b->isize && b->index[j] == a->index[i])
-        {
-            dest->index[k++] = b->index[j++];
-        }
-    }
-    dest->isize = k;
-}
-
-/*!
- * \param[out] dest Output index group (the difference \p a - \p b).
- * \param[in]  a    First index group.
- * \param[in]  b    Second index group.
- *
- * \p dest can equal \p a, but not \p b.
- */
-void
-gmx_ana_index_difference(gmx_ana_index_t *dest,
-                         gmx_ana_index_t *a, gmx_ana_index_t *b)
-{
-    int i, j, k;
-
-    for (i = j = k = 0; i < a->isize; ++i)
-    {
-        while (j < b->isize && b->index[j] < a->index[i])
-        {
-            ++j;
-        }
-        if (j == b->isize || b->index[j] != a->index[i])
-        {
-            dest->index[k++] = a->index[i];
-        }
-    }
-    dest->isize = k;
-}
-
-/*!
- * \param[in]  a    First index group.
- * \param[in]  b    Second index group.
- * \returns    Size of the difference \p a - \p b.
- */
-int
-gmx_ana_index_difference_size(gmx_ana_index_t *a, gmx_ana_index_t *b)
-{
-    int i, j, k;
-
-    for (i = j = k = 0; i < a->isize; ++i)
-    {
-        while (j < b->isize && b->index[j] < a->index[i])
-        {
-            ++j;
-        }
-        if (j == b->isize || b->index[j] != a->index[i])
-        {
-            ++k;
-        }
-    }
-    return k;
-}
-
-/*!
- * \param[out] dest1 Output group 1 (will equal \p g).
- * \param[out] dest2 Output group 2 (will equal \p src - \p g).
- * \param[in]  src   Group to be partitioned.
- * \param[in]  g     One partition.
- *
- * \pre \p g is a subset of \p src and both sets are sorted
- * \pre \p dest1 has allocated storage to store \p src
- * \post \p dest1 == \p g
- * \post \p dest2 == \p src - \p g
- *
- * No storage should be allocated for \p dest2; after the call,
- * \p dest2->index points to the memory allocated for \p dest1
- * (to a part that is not used by \p dest1).
- *
- * The calculation can be performed in-place by setting \p dest1 equal to
- * \p src.
- */
-void
-gmx_ana_index_partition(gmx_ana_index_t *dest1, gmx_ana_index_t *dest2,
-                        gmx_ana_index_t *src, gmx_ana_index_t *g)
-                     
-{
-    int i, j, k;
-
-    dest2->index = dest1->index + g->isize;
-    dest2->isize = src->isize - g->isize;
-    for (i = g->isize-1, j = src->isize-1, k = dest2->isize-1; i >= 0; --i, --j)
-    {
-        while (j >= 0 && src->index[j] != g->index[i])
-        {
-            dest2->index[k--] = src->index[j--];
-        }
-    }
-    while (j >= 0)
-    {
-        dest2->index[k--] = src->index[j--];
-    }
-    gmx_ana_index_copy(dest1, g, FALSE);
-}
-
-/*!
- * \param[out] dest Output index group (the union of \p a and \p b).
- * \param[in]  a    First index group.
- * \param[in]  b    Second index group.
- *
- * \p a and \p b can have common items.
- * \p dest can equal \p a or \p b.
- *
- * \see gmx_ana_index_merge()
- */
-void
-gmx_ana_index_union(gmx_ana_index_t *dest,
-                    gmx_ana_index_t *a, gmx_ana_index_t *b)
-{
-    int dsize;
-    int i, j, k;
-
-    dsize = gmx_ana_index_difference_size(b, a);
-    i = a->isize - 1;
-    j = b->isize - 1;
-    dest->isize = a->isize + dsize;
-    for (k = dest->isize - 1; k >= 0; k--)
-    {
-        if (i < 0 || (j >= 0 && a->index[i] < b->index[j]))
-        {
-            dest->index[k] = b->index[j--];
-        }
-        else
-        {
-            if (j >= 0 && a->index[i] == b->index[j])
-            {
-                --j;
-            }
-            dest->index[k] = a->index[i--];
-        }
-    }
-}
-
-/*!
- * \param[out] dest Output index group (the union of \p a and \p b).
- * \param[in]  a    First index group.
- * \param[in]  b    Second index group.
- *
- * \p a and \p b should not have common items.
- * \p dest can equal \p a or \p b.
- *
- * \see gmx_ana_index_union()
- */
-void
-gmx_ana_index_merge(gmx_ana_index_t *dest,
-                    gmx_ana_index_t *a, gmx_ana_index_t *b)
-{
-    int i, j, k;
-
-    i = a->isize - 1;
-    j = b->isize - 1;
-    dest->isize = a->isize + b->isize;
-    for (k = dest->isize - 1; k >= 0; k--)
-    {
-        if (i < 0 || (j >= 0 && a->index[i] < b->index[j]))
-        {
-            dest->index[k] = b->index[j--];
-        }
-        else
-        {
-            dest->index[k] = a->index[i--];
-        }
-    }
-}
-
-/********************************************************************
- * gmx_ana_indexmap_t and related things
- ********************************************************************/
-
-/*!
- * \param[in,out] t    Output block.
- * \param[in]  top  Topology structure
- *   (only used if \p type is \ref INDEX_RES or \ref INDEX_MOL, can be NULL
- *   otherwise).
- * \param[in]  g    Index group
- *   (can be NULL if \p type is \ref INDEX_UNKNOWN).
- * \param[in]  type Type of partitioning to make.
- * \param[in]  bComplete
- *   If TRUE, the index group is expanded to include any residue/molecule
- *   (depending on \p type) that is partially contained in the group.
- *   If \p type is not INDEX_RES or INDEX_MOL, this has no effect.
- *
- * \p m should have been initialized somehow (calloc() is enough) unless
- * \p type is INDEX_UNKNOWN.
- * \p g should be sorted.
- */
-void
-gmx_ana_index_make_block(t_blocka *t, t_topology *top, gmx_ana_index_t *g,
-                         e_index_t type, gmx_bool bComplete)
-{
-    int      i, j, ai;
-    int      id, cur;
-
-    if (type == INDEX_UNKNOWN)
-    {
-        t->nr           = 1;
-        snew(t->index, 2);
-        t->nalloc_index = 2;
-        t->index[0]     = 0;
-        t->index[1]     = 0;
-        t->nra          = 0;
-        t->a            = NULL;
-        t->nalloc_a     = 0;
-        return;
-    }
-
-    /* bComplete only does something for INDEX_RES or INDEX_MOL, so turn it
-     * off otherwise. */
-    if (type != INDEX_RES && type != INDEX_MOL)
-    {
-        bComplete = FALSE;
-    }
-    /* Allocate memory for the atom array and fill it unless we are using
-     * completion. */
-    if (bComplete)
-    {
-        t->nra = 0;
-        /* We may allocate some extra memory here because we don't know in
-         * advance how much will be needed. */
-        if (t->nalloc_a < top->atoms.nr)
-        {
-            srenew(t->a, top->atoms.nr);
-            t->nalloc_a = top->atoms.nr;
-        }
-    }
-    else
-    {
-        t->nra      = g->isize;
-        if (t->nalloc_a < g->isize)
-        {
-            srenew(t->a, g->isize);
-            t->nalloc_a = g->isize;
-        }
-        memcpy(t->a, g->index, g->isize*sizeof(*(t->a)));
-    }
-
-    /* Allocate memory for the block index. We don't know in advance
-     * how much will be needed, so we allocate some extra and free it in the
-     * end. */
-    if (t->nalloc_index < g->isize + 1)
-    {
-        srenew(t->index, g->isize + 1);
-        t->nalloc_index = g->isize + 1;
-    }
-    /* Clear counters */
-    t->nr = 0;
-    j = 0; /* j is used by residue completion for the first atom not stored */
-    id = cur = -1;
-    for (i = 0; i < g->isize; ++i)
-    {
-        ai = g->index[i];
-        /* Find the ID number of the atom/residue/molecule corresponding to
-         * atom ai. */
-        switch (type)
-        {
-            case INDEX_ATOM:
-                id = ai;
-                break;
-            case INDEX_RES:
-                id = top->atoms.atom[ai].resind;
-                break;
-            case INDEX_MOL:
-                while (ai >= top->mols.index[id+1])
-                {
-                    id++;
-                }
-                break;
-            case INDEX_UNKNOWN: /* Should not occur */
-            case INDEX_ALL:
-                id = 0;
-                break;
-        }
-        /* If this is the first atom in a new block, initialize the block. */
-        if (id != cur)
-        {
-            if (bComplete)
-            {
-                /* For completion, we first set the start of the block. */
-                t->index[t->nr++] = t->nra;
-                /* And then we find all the atoms that should be included. */
-                switch (type)
-                {
-                    case INDEX_RES:
-                        while (top->atoms.atom[j].resind != id)
-                        {
-                            ++j;
-                        }
-                        while (j < top->atoms.nr && top->atoms.atom[j].resind == id)
-                        {
-                            t->a[t->nra++] = j;
-                            ++j;
-                        }
-                        break;
-
-                    case INDEX_MOL:
-                        for (j = top->mols.index[id]; j < top->mols.index[id+1]; ++j)
-                        {
-                            t->a[t->nra++] = j;
-                        }
-                        break;
-
-                    default: /* Should not be reached */
-                        gmx_bug("internal error");
-                        break;
-                }
-            }
-            else
-            {
-                /* If not using completion, simply store the start of the block. */
-                t->index[t->nr++] = i;
-            }
-            cur = id;
-        }
-    }
-    /* Set the end of the last block */
-    t->index[t->nr] = t->nra;
-    /* Free any unnecessary memory */
-    srenew(t->index, t->nr+1);
-    t->nalloc_index = t->nr+1;
-    if (bComplete)
-    {
-        srenew(t->a, t->nra);
-        t->nalloc_a = t->nra;
-    }
-}
-
-/*!
- * \param[in] g   Index group to check.
- * \param[in] b   Block data to check against.
- * \returns   TRUE if \p g consists of one or more complete blocks from \p b,
- *   FALSE otherwise.
- *
- * The atoms in \p g are assumed to be sorted.
- */
-gmx_bool
-gmx_ana_index_has_full_blocks(gmx_ana_index_t *g, t_block *b)
-{
-    int  i, j, bi;
-
-    i = bi = 0;
-    /* Each round in the loop matches one block */
-    while (i < g->isize)
-    {
-        /* Find the block that begins with the first unmatched atom */
-        while (bi < b->nr && b->index[bi] != g->index[i])
-        {
-            ++bi;
-        }
-        /* If not found, or if too large, return */
-        if (bi == b->nr || i + b->index[bi+1] -  b->index[bi] > g->isize)
-        {
-            return FALSE;
-        }
-        /* Check that the block matches the index */
-        for (j = b->index[bi]; j < b->index[bi+1]; ++j, ++i)
-        {
-            if (g->index[i] != j)
-            {
-                return FALSE;
-            }
-        }
-        /* Move the search to the next block */
-        ++bi;
-    }
-    return TRUE;
-}
-
-/*!
- * \param[in] g   Index group to check.
- * \param[in] b   Block data to check against.
- * \returns   TRUE if \p g consists of one or more complete blocks from \p b,
- *   FALSE otherwise.
- *
- * The atoms in \p g and \p b->a are assumed to be in the same order.
- */
-gmx_bool
-gmx_ana_index_has_full_ablocks(gmx_ana_index_t *g, t_blocka *b)
-{
-    int  i, j, bi;
-
-    i = bi = 0;
-    /* Each round in the loop matches one block */
-    while (i < g->isize)
-    {
-        /* Find the block that begins with the first unmatched atom */
-        while (bi < b->nr && b->a[b->index[bi]] != g->index[i])
-        {
-            ++bi;
-        }
-        /* If not found, or if too large, return */
-        if (bi == b->nr || i + b->index[bi+1] -  b->index[bi] > g->isize)
-        {
-            return FALSE;
-        }
-        /* Check that the block matches the index */
-        for (j = b->index[bi]; j < b->index[bi+1]; ++j, ++i)
-        {
-            if (b->a[j] != g->index[i])
-            {
-                return FALSE;
-            }
-        }
-        /* Move the search to the next block */
-        ++bi;
-    }
-    return TRUE;
-}
-
-/*!
- * \param[in] g     Index group to check.
- * \param[in] type  Block data to check against.
- * \param[in] top   Topology data.
- * \returns   TRUE if \p g consists of one or more complete elements of type
- *   \p type, FALSE otherwise.
- *
- * If \p type is \ref INDEX_ATOM, the return value is always TRUE.
- * If \p type is \ref INDEX_UNKNOWN or \ref INDEX_ALL, the return value is
- * always FALSE.
- */
-gmx_bool
-gmx_ana_index_has_complete_elems(gmx_ana_index_t *g, e_index_t type,
-                                 t_topology *top)
-{
-    switch (type)
-    {
-        case INDEX_UNKNOWN:
-        case INDEX_ALL:
-            return FALSE;
-
-        case INDEX_ATOM:
-            return TRUE;
-
-        case INDEX_RES:
-        {
-            int      i, ai;
-            int      id, prev;
-
-            prev = -1;
-            for (i = 0; i < g->isize; ++i)
-            {
-                ai = g->index[i];
-                id = top->atoms.atom[ai].resind;
-                if (id != prev)
-                {
-                    if (ai > 0 && top->atoms.atom[ai-1].resind == id)
-                    {
-                        return FALSE;
-                    }
-                    if (i > 0 && g->index[i-1] < top->atoms.nr - 1
-                        && top->atoms.atom[g->index[i-1]+1].resind == prev)
-                    {
-                        return FALSE;
-                    }
-                }
-                prev = id;
-            }
-            if (g->index[i-1] < top->atoms.nr - 1
-                && top->atoms.atom[g->index[i-1]+1].resind == prev)
-            {
-                return FALSE;
-            }
-            break;
-        }
-
-        case INDEX_MOL:
-            return gmx_ana_index_has_full_blocks(g, &top->mols);
-    }
-    return TRUE;
-}
-
-/*!
- * \param[out] m      Output structure.
- *
- * Any contents of \p m are discarded without freeing.
- */
-void
-gmx_ana_indexmap_clear(gmx_ana_indexmap_t *m)
-{
-    m->type              = INDEX_UNKNOWN;
-    m->nr                = 0;
-    m->refid             = NULL;
-    m->mapid             = NULL;
-    m->mapb.nr           = 0;
-    m->mapb.index        = NULL;
-    m->mapb.nalloc_index = 0;
-    m->orgid             = NULL;
-    m->b.nr              = 0;
-    m->b.index           = NULL;
-    m->b.nra             = 0;
-    m->b.a               = NULL;
-    m->b.nalloc_index    = 0;
-    m->b.nalloc_a        = 0;
-    m->bStatic           = TRUE;
-    m->bMapStatic        = TRUE;
-}
-
-/*!
- * \param[in,out] m      Mapping structure.
- * \param[in]     nr     Maximum number of blocks to reserve space for.
- * \param[in]     isize  Maximum number of atoms to reserve space for.
- */
-void
-gmx_ana_indexmap_reserve(gmx_ana_indexmap_t *m, int nr, int isize)
-{
-    if (m->mapb.nalloc_index < nr + 1)
-    {
-        srenew(m->refid,      nr);
-        srenew(m->mapid,      nr);
-        srenew(m->orgid,      nr);
-        srenew(m->mapb.index, nr + 1);
-        srenew(m->b.index,    nr + 1);
-        m->mapb.nalloc_index = nr + 1;
-        m->b.nalloc_index    = nr + 1;
-    }
-    if (m->b.nalloc_a < isize)
-    {
-        srenew(m->b.a,        isize);
-        m->b.nalloc_a = isize;
-    }
-}
-
-/*!
- * \param[in,out] m    Mapping structure to initialize.
- * \param[in]     g    Index group to map
- *   (can be NULL if \p type is \ref INDEX_UNKNOWN).
- * \param[in]     top  Topology structure
- *   (can be NULL if \p type is not \ref INDEX_RES or \ref INDEX_MOL).
- * \param[in]     type Type of mapping to construct.
- *
- * Initializes a new index group mapping.
- * The index group provided to gmx_ana_indexmap_update() should always be a
- * subset of the \p g given here.
- *
- * \p m should have been initialized somehow (calloc() is enough).
- */
-void
-gmx_ana_indexmap_init(gmx_ana_indexmap_t *m, gmx_ana_index_t *g,
-                      t_topology *top, e_index_t type)
-{
-    int      i, ii, mi;
-
-    m->type   = type;
-    gmx_ana_index_make_block(&m->b, top, g, type, FALSE);
-    gmx_ana_indexmap_reserve(m, m->b.nr, m->b.nra);
-    m->nr = m->b.nr;
-    for (i = mi = 0; i < m->nr; ++i)
-    {
-        ii = (type == INDEX_UNKNOWN ? 0 : m->b.a[m->b.index[i]]);
-        switch (type)
-        {
-            case INDEX_ATOM:
-                m->orgid[i] = ii;
-                break;
-            case INDEX_RES:
-                m->orgid[i] = top->atoms.atom[ii].resind;
-                break;
-            case INDEX_MOL:
-                while (top->mols.index[mi+1] <= ii)
-                {
-                    ++mi;
-                }
-                m->orgid[i] = mi;
-                break;
-            case INDEX_ALL:
-            case INDEX_UNKNOWN:
-                m->orgid[i] = 0;
-                break;
-        }
-    }
-    for (i = 0; i < m->nr; ++i)
-    {
-        m->refid[i] = i;
-        m->mapid[i] = m->orgid[i];
-    }
-    m->mapb.nr = m->nr;
-    memcpy(m->mapb.index, m->b.index, (m->nr+1)*sizeof(*(m->mapb.index)));
-    m->bStatic    = TRUE;
-    m->bMapStatic = TRUE;
-}
-
-/*!
- * \param[in,out] m    Mapping structure to initialize.
- * \param[in]     b    Block information to use for data.
- *
- * Frees some memory that is not necessary for static index group mappings.
- * Internal pointers are set to point to data in \p b; it is the responsibility
- * of the caller to ensure that the block information matches the contents of
- * the mapping.
- * After this function has been called, the index group provided to
- * gmx_ana_indexmap_update() should always be the same as \p g given here.
- *
- * This function breaks modularity of the index group mapping interface in an
- * ugly way, but allows reducing memory usage of static selections by a
- * significant amount.
- */
-void
-gmx_ana_indexmap_set_static(gmx_ana_indexmap_t *m, t_blocka *b)
-{
-    sfree(m->mapid);
-    m->mapid = m->orgid;
-    sfree(m->b.index);
-    m->b.nalloc_index = 0;
-    m->b.index = b->index;
-    sfree(m->mapb.index);
-    m->mapb.nalloc_index = 0;
-    m->mapb.index = m->b.index;
-    sfree(m->b.a);
-    m->b.nalloc_a = 0;
-    m->b.a = b->a;
-}
-
-/*!
- * \param[in,out] dest Destination data structure.
- * \param[in]     src  Source mapping.
- * \param[in]     bFirst If TRUE, memory is allocated for \p dest and a full
- *   copy is made; otherwise, only variable parts are copied, and no memory
- *   is allocated.
- *
- * \p dest should have been initialized somehow (calloc() is enough).
- */
-void
-gmx_ana_indexmap_copy(gmx_ana_indexmap_t *dest, gmx_ana_indexmap_t *src, gmx_bool bFirst)
-{
-    if (bFirst)
-    {
-        gmx_ana_indexmap_reserve(dest, src->b.nr, src->b.nra);
-        dest->type       = src->type;
-        dest->b.nr       = src->b.nr;
-        dest->b.nra      = src->b.nra;
-        memcpy(dest->orgid,      src->orgid,      dest->b.nr*sizeof(*dest->orgid));
-        memcpy(dest->b.index,    src->b.index,   (dest->b.nr+1)*sizeof(*dest->b.index));
-        memcpy(dest->b.a,        src->b.a,        dest->b.nra*sizeof(*dest->b.a));
-    }
-    dest->nr         = src->nr;
-    dest->mapb.nr    = src->mapb.nr;
-    memcpy(dest->refid,      src->refid,      dest->nr*sizeof(*dest->refid));
-    memcpy(dest->mapid,      src->mapid,      dest->nr*sizeof(*dest->mapid));
-    memcpy(dest->mapb.index, src->mapb.index,(dest->mapb.nr+1)*sizeof(*dest->mapb.index));
-    dest->bStatic    = src->bStatic;
-    dest->bMapStatic = src->bMapStatic;
-}
-
-/*!
- * \param[in,out] m         Mapping structure.
- * \param[in]     g         Current index group.
- * \param[in]     bMaskOnly TRUE if the unused blocks should be masked with
- *   -1 instead of removing them.
- *
- * Updates the index group mapping with the new index group \p g.
- *
- * \see gmx_ana_indexmap_t
- */
-void
-gmx_ana_indexmap_update(gmx_ana_indexmap_t *m, gmx_ana_index_t *g,
-                        gmx_bool bMaskOnly)
-{
-    int i, j, bi, bj;
-    gmx_bool bStatic;
-
-    /* Process the simple cases first */
-    if (m->type == INDEX_UNKNOWN && m->b.nra == 0)
-    {
-        return;
-    }
-    if (m->type == INDEX_ALL)
-    {
-        if (m->b.nr > 0)
-        {
-            m->mapb.index[1] = g->isize;
-        }
-        return;
-    }
-    /* Reset the reference IDs and mapping if necessary */
-    bStatic = (g->isize == m->b.nra && m->nr == m->b.nr);
-    if (bStatic || bMaskOnly)
-    {
-        if (!m->bStatic)
-        {
-            for (bj = 0; bj < m->b.nr; ++bj)
-            {
-                m->refid[bj] = bj;
-            }
-        }
-        if (!m->bMapStatic)
-        {
-            for (bj = 0; bj < m->b.nr; ++bj)
-            {
-                m->mapid[bj] = m->orgid[bj];
-            }
-            for (bj = 0; bj <= m->b.nr; ++bj)
-            {
-                m->mapb.index[bj] = m->b.index[bj];
-            }
-            m->bMapStatic = TRUE;
-        }
-    }
-    /* Exit immediately if the group is static */
-    if (bStatic)
-    {
-        m->bStatic = TRUE;
-        return;
-    }
-
-    if (bMaskOnly)
-    {
-        m->nr = m->b.nr;
-        for (i = j = bj = 0; i < g->isize; ++i, ++j)
-        {
-            /* Find the next atom in the block */
-            while (m->b.a[j] != g->index[i])
-            {
-                ++j;
-            }
-            /* Mark blocks that did not contain any atoms */
-            while (bj < m->b.nr && m->b.index[bj+1] <= j)
-            {
-                m->refid[bj++] = -1;
-            }
-            /* Advance the block index if we have reached the next block */
-            if (m->b.index[bj] <= j)
-            {
-                ++bj;
-            }
-        }
-        /* Mark the last blocks as not accessible */
-        while (bj < m->b.nr)
-        {
-            m->refid[bj++] = -1;
-        }
-    }
-    else
-    {
-        for (i = j = bi = 0, bj = -1; i < g->isize; ++i)
-        {
-            /* Find the next atom in the block */
-            while (m->b.a[j] != g->index[i])
-            {
-                ++j;
-            }
-            /* If we have reached a new block, add it */
-            if (m->b.index[bj+1] <= j)
-            {
-                /* Skip any blocks in between */
-                while (bj < m->b.nr && m->b.index[bj+1] <= j)
-                {
-                    ++bj;
-                }
-                m->refid[bi] = bj;
-                m->mapid[bi] = m->orgid[bj];
-                m->mapb.index[bi] = i;
-                bi++;
-            }
-        }
-        /* Update the number of blocks */
-        m->mapb.index[bi] = g->isize;
-        m->nr             = bi;
-        m->bMapStatic     = FALSE;
-    }
-    m->mapb.nr = m->nr;
-    m->bStatic = FALSE;
-}
-
-/*!
- * \param[in,out] m         Mapping structure to free.
- *
- * All the memory allocated for the mapping structure is freed, and
- * the pointers set to NULL.
- * The pointer \p m is not freed.
- */
-void
-gmx_ana_indexmap_deinit(gmx_ana_indexmap_t *m)
-{
-    sfree(m->refid);
-    if (m->mapid != m->orgid)
-    {
-        sfree(m->mapid);
-    }
-    if (m->mapb.nalloc_index > 0)
-    {
-        sfree(m->mapb.index);
-    }
-    sfree(m->orgid);
-    if (m->b.nalloc_index > 0)
-    {
-        sfree(m->b.index);
-    }
-    if (m->b.nalloc_a > 0)
-    {
-        sfree(m->b.a);
-    }
-    gmx_ana_indexmap_clear(m);
-}
diff --git a/src/gmxlib/trajana/nbsearch.c b/src/gmxlib/trajana/nbsearch.c
deleted file mode 100644 (file)
index e991cbc..0000000
+++ /dev/null
@@ -1,793 +0,0 @@
-/*
- *
- *                This source code is part of
- *
- *                 G   R   O   M   A   C   S
- *
- *          GROningen MAchine for Chemical Simulations
- *
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
- * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
- * Copyright (c) 2001-2009, The GROMACS development team,
- * check out http://www.gromacs.org for more information.
-
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * If you want to redistribute modifications, please consider that
- * scientific software is very special. Version control is crucial -
- * bugs must be traceable. We will be happy to consider code for
- * inclusion in the official distribution, but derived work must not
- * be called official GROMACS. Details are found in the README & COPYING
- * files - if they are missing, get the official version at www.gromacs.org.
- *
- * To help us fund GROMACS development, we humbly ask that you cite
- * the papers on the package - you can find them in the top README file.
- *
- * For more info, check our website at http://www.gromacs.org
- */
-/*! \page nbsearch Neighborhood search routines
- *
- * Functions to find particles within a neighborhood of a set of particles
- * are defined in nbsearch.h.
- * The usage is simple: a data structure is allocated with
- * gmx_ana_nbsearch_create(), and the box shape and reference positions for a
- * frame are set using gmx_ana_nbsearch_init() or gmx_ana_nbsearch_pos_init().
- * Searches can then be performed with gmx_ana_nbsearch_is_within() and
- * gmx_ana_nbsearch_mindist(), or with versions that take the \c gmx_ana_pos_t
- * data structure.
- * When the data structure is no longer required, it can be freed with
- * gmx_ana_nbsearch_free().
- *
- * \internal
- *
- * \todo
- * The grid implementation could still be optimized in several different ways:
- *   - Triclinic grid cells are not the most efficient shape, but make PBC
- *     handling easier.
- *   - Precalculating the required PBC shift for a pair of cells outside the
- *     inner loop. After this is done, it should be quite straightforward to
- *     move to rectangular cells.
- *   - Pruning grid cells from the search list if they are completely outside
- *     the sphere that is being considered.
- *   - A better heuristic could be added for falling back to simple loops for a
- *     small number of reference particles.
- *   - A better heuristic for selecting the grid size.
- *   - A multi-level grid implementation could be used to be able to use small
- *     grids for short cutoffs with very inhomogeneous particle distributions
- *     without a memory cost.
- */
-/*! \internal \file
- * \brief Implementation of functions in nbsearch.h.
- */
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <math.h>
-
-#include <smalloc.h>
-#include <typedefs.h>
-#include <pbc.h>
-#include <vec.h>
-
-#include <nbsearch.h>
-#include <position.h>
-
-/*! \internal \brief
- * Data structure for neighborhood searches.
- */
-struct gmx_ana_nbsearch_t
-{
-    /** The cutoff. */
-    real           cutoff;
-    /** The cutoff squared. */
-    real           cutoff2;
-    /** Maximum number of reference points. */
-    int            maxnref;
-
-    /** Number of reference points for the current frame. */
-    int            nref;
-    /** Reference point positions. */
-    rvec          *xref;
-    /** Reference position ids (NULL if not available). */
-    int           *refid;
-    /** PBC data. */
-    t_pbc         *pbc;
-
-    /** Number of excluded reference positions for current test particle. */
-    int            nexcl;
-    /** Exclusions for current test particle. */
-    int           *excl;
-
-    /** Whether to try grid searching. */
-    gmx_bool           bTryGrid;
-    /** Whether grid searching is actually used for the current positions. */
-    gmx_bool           bGrid;
-    /** Array allocated for storing in-unit-cell reference positions. */
-    rvec          *xref_alloc;
-    /** FALSE if the box is rectangular. */
-    gmx_bool           bTric;
-    /** Box vectors of a single grid cell. */
-    matrix         cellbox;
-    /** The reciprocal cell vectors as columns; the inverse of \p cellbox. */
-    matrix         recipcell;
-    /** Number of cells along each dimension. */
-    ivec           ncelldim;
-    /** Total number of cells. */
-    int            ncells;
-    /** Number of reference positions in each cell. */
-    int           *ncatoms;
-    /** List of reference positions in each cell. */
-    atom_id      **catom;
-    /** Allocation counts for each \p catom[i]. */
-    int           *catom_nalloc;
-    /** Allocation count for the per-cell arrays. */
-    int            cells_nalloc;
-    /** Number of neighboring cells to consider. */
-    int            ngridnb;
-    /** Offsets of the neighboring cells to consider. */
-    ivec          *gnboffs;
-    /** Allocation count for \p gnboffs. */
-    int            gnboffs_nalloc;
-
-    /** Stores test position during a pair loop. */
-    rvec           xtest;
-    /** Stores the previous returned position during a pair loop. */
-    int            previ;
-    /** Stores the current exclusion index during loops. */
-    int            exclind;
-    /** Stores the test particle cell index during loops. */
-    ivec           testcell;
-    /** Stores the current cell neighbor index during pair loops. */
-    int            prevnbi;
-    /** Stores the index within the current cell during pair loops. */
-    int            prevcai;
-};
-
-/*!
- * \param[out] data   Neighborhood search data structure pointer to initialize.
- * \param[in]  cutoff Cutoff distance for the search
- *   (<=0 stands for no cutoff).
- * \param[in]  maxn   Maximum number of reference particles.
- * \returns    0 on success.
- */
-int
-gmx_ana_nbsearch_create(gmx_ana_nbsearch_t **data, real cutoff, int maxn)
-{
-    gmx_ana_nbsearch_t *d;
-    
-    snew(d, 1);
-    d->bTryGrid = TRUE;
-    if (cutoff <= 0)
-    {
-        cutoff = HUGE_VAL;
-        d->bTryGrid = FALSE;
-    }
-    d->cutoff = cutoff;
-    d->cutoff2 = sqr(cutoff);
-    d->maxnref = maxn;
-
-    d->xref = NULL;
-    d->nexcl = 0;
-    d->exclind = 0;
-
-    d->xref_alloc = NULL;
-    d->ncells = 0;
-    d->ncatoms = NULL;
-    d->catom = NULL;
-    d->catom_nalloc = 0;
-    d->cells_nalloc = 0;
-
-    d->ngridnb = 0;
-    d->gnboffs = NULL;
-    d->gnboffs_nalloc = 0;
-
-    *data = d;
-    return 0;
-}
-
-/*!
- * \param     d Data structure to free.
- *
- * After the call, the pointer \p d is no longer valid.
- */
-void
-gmx_ana_nbsearch_free(gmx_ana_nbsearch_t *d)
-{
-    sfree(d->xref_alloc);
-    sfree(d->ncatoms);
-    if (d->catom)
-    {
-        int ci;
-
-        for (ci = 0; ci < d->ncells; ++ci)
-        {
-            sfree(d->catom[ci]);
-        }
-        sfree(d->catom);
-    }
-    sfree(d->catom_nalloc);
-    sfree(d->gnboffs);
-    sfree(d);
-}
-
-/*! \brief
- * Calculates offsets to neighboring grid cells that should be considered.
- *
- * \param[in,out] d    Grid information.
- * \param[in]     pbc  Information about the box.
- */
-static void
-grid_init_cell_nblist(gmx_ana_nbsearch_t *d, t_pbc *pbc)
-{
-    int   maxx, maxy, maxz;
-    int   x, y, z, i;
-    real  rvnorm;
-
-    /* Find the extent of the sphere in triclinic coordinates */
-    maxz = (int)(d->cutoff * d->recipcell[ZZ][ZZ]) + 1;
-    rvnorm = sqrt(sqr(d->recipcell[YY][YY]) + sqr(d->recipcell[ZZ][YY]));
-    maxy = (int)(d->cutoff * rvnorm) + 1;
-    rvnorm = sqrt(sqr(d->recipcell[XX][XX]) + sqr(d->recipcell[YY][XX])
-                  + sqr(d->recipcell[ZZ][XX]));
-    maxx = (int)(d->cutoff * rvnorm) + 1;
-
-    /* Calculate the number of cells and reallocate if necessary */
-    d->ngridnb = (2 * maxx + 1) * (2 * maxy + 1) * (2 * maxz + 1);
-    if (d->gnboffs_nalloc < d->ngridnb)
-    {
-        d->gnboffs_nalloc = d->ngridnb;
-        srenew(d->gnboffs, d->gnboffs_nalloc);
-    }
-
-    /* Store the whole cube */
-    /* TODO: Prune off corners that are not needed */
-    i = 0;
-    for (x = -maxx; x <= maxx; ++x)
-    {
-        for (y = -maxy; y <= maxy; ++y)
-        {
-            for (z = -maxz; z <= maxz; ++z)
-            {
-                d->gnboffs[i][XX] = x;
-                d->gnboffs[i][YY] = y;
-                d->gnboffs[i][ZZ] = z;
-                ++i;
-            }
-        }
-    }
-}
-
-/*! \brief
- * Determines a suitable grid size.
- *
- * \param[in,out] d    Grid information.
- * \param[in]     pbc  Information about the box.
- * \returns  FALSE if grid search is not suitable.
- */
-static gmx_bool
-grid_setup_cells(gmx_ana_nbsearch_t *d, t_pbc *pbc)
-{
-    real targetsize;
-    int  dd;
-
-#ifdef HAVE_CBRT
-    targetsize = cbrt(pbc->box[XX][XX] * pbc->box[YY][YY] * pbc->box[ZZ][ZZ]
-                      * 10 / d->nref);
-#else
-    targetsize = pow(pbc->box[XX][XX] * pbc->box[YY][YY] * pbc->box[ZZ][ZZ]
-                      * 10 / d->nref, 1./3.);
-#endif
-
-    d->ncells = 1;
-    for (dd = 0; dd < DIM; ++dd)
-    {
-        d->ncelldim[dd] = (int)(pbc->box[dd][dd] / targetsize);
-        d->ncells *= d->ncelldim[dd];
-        if (d->ncelldim[dd] < 3)
-        {
-            return FALSE;
-        }
-    }
-    /* Reallocate if necessary */
-    if (d->cells_nalloc < d->ncells)
-    {
-        int  i;
-
-        srenew(d->ncatoms, d->ncells);
-        srenew(d->catom, d->ncells);
-        srenew(d->catom_nalloc, d->ncells);
-        for (i = d->cells_nalloc; i < d->ncells; ++i)
-        {
-            d->catom[i] = NULL;
-            d->catom_nalloc[i] = 0;
-        }
-        d->cells_nalloc = d->ncells;
-    }
-    return TRUE;
-}
-
-/*! \brief
- * Sets ua a search grid for a given box.
- *
- * \param[in,out] d    Grid information.
- * \param[in]     pbc  Information about the box.
- * \returns  FALSE if grid search is not suitable.
- */
-static gmx_bool
-grid_set_box(gmx_ana_nbsearch_t *d, t_pbc *pbc)
-{
-    int dd;
-
-    /* TODO: This check could be improved. */
-    if (0.5*pbc->max_cutoff2 < d->cutoff2)
-    {
-        return FALSE;
-    }
-
-    if (!grid_setup_cells(d, pbc))
-    {
-        return FALSE;
-    }
-
-    d->bTric = TRICLINIC(pbc->box);
-    if (d->bTric)
-    {
-        for (dd = 0; dd < DIM; ++dd)
-        {
-            svmul(1.0 / d->ncelldim[dd], pbc->box[dd], d->cellbox[dd]);
-        }
-        m_inv_ur0(d->cellbox, d->recipcell);
-    }
-    else
-    {
-        for (dd = 0; dd < DIM; ++dd)
-        {
-            d->cellbox[dd][dd] = pbc->box[dd][dd] / d->ncelldim[dd];
-            d->recipcell[dd][dd] = 1 / d->cellbox[dd][dd];
-        }
-    }
-    grid_init_cell_nblist(d, pbc);
-    return TRUE;
-}
-
-/*! \brief
- * Maps a point into a grid cell.
- *
- * \param[in]  d    Grid information.
- * \param[in]  x    Point to map.
- * \param[out] cell Indices of the grid cell in which \p x lies.
- *
- * \p x should be in the triclinic unit cell.
- */
-static void
-grid_map_onto(gmx_ana_nbsearch_t *d, const rvec x, ivec cell)
-{
-    int dd;
-
-    if (d->bTric)
-    {
-        rvec tx;
-
-        tmvmul_ur0(d->recipcell, x, tx);
-        for (dd = 0; dd < DIM; ++dd)
-        {
-            cell[dd] = (int)tx[dd];
-        }
-    }
-    else
-    {
-        for (dd = 0; dd < DIM; ++dd)
-        {
-            cell[dd] = (int)(x[dd] * d->recipcell[dd][dd]);
-        }
-    }
-}
-
-/*! \brief
- * Calculates linear index of a grid cell.
- *
- * \param[in]  d    Grid information.
- * \param[in]  cell Cell indices.
- * \returns    Linear index of \p cell.
- */
-static int
-grid_index(gmx_ana_nbsearch_t *d, const ivec cell)
-{
-    return cell[XX] + cell[YY] * d->ncelldim[XX]
-        + cell[ZZ] * d->ncelldim[XX] * d->ncelldim[YY];
-}
-
-/*! \brief
- * Clears all grid cells.
- *
- * \param[in,out] d    Grid information.
- */
-static void
-grid_clear_cells(gmx_ana_nbsearch_t *d)
-{
-    int  ci;
-
-    for (ci = 0; ci < d->ncells; ++ci)
-    {
-        d->ncatoms[ci] = 0;
-    }
-}
-
-/*! \brief
- * Adds an index into a grid cell.
- *
- * \param[in,out] d    Grid information.
- * \param[in]     cell Cell into which \p i should be added.
- * \param[in]     i    Index to add.
- */
-static void
-grid_add_to_cell(gmx_ana_nbsearch_t *d, const ivec cell, int i)
-{
-    int ci = grid_index(d, cell);
-
-    if (d->ncatoms[ci] == d->catom_nalloc[ci])
-    {
-        d->catom_nalloc[ci] += 10;
-        srenew(d->catom[ci], d->catom_nalloc[ci]);
-    }
-    d->catom[ci][d->ncatoms[ci]++] = i;
-}
-
-/*!
- * \param[in,out] d   Neighborhood search data structure.
- * \param[in]     pbc PBC information for the frame.
- * \param[in]     n   Number of reference positions for the frame.
- * \param[in]     x   \p n reference positions for the frame.
- * \returns       0 on success.
- *
- * Initializes the data structure \p d such that it can be used to search
- * for the neighbors of \p x.
- */
-int
-gmx_ana_nbsearch_init(gmx_ana_nbsearch_t *d, t_pbc *pbc, int n, rvec x[])
-{
-    d->pbc  = pbc;
-    d->nref = n;
-    if (!pbc)
-    {
-        d->bGrid = FALSE;
-    }
-    else if (d->bTryGrid)
-    {
-        d->bGrid = grid_set_box(d, pbc);
-    }
-    if (d->bGrid)
-    {
-        int  i;
-
-        if (!d->xref_alloc)
-        {
-            snew(d->xref_alloc, d->maxnref);
-        }
-        d->xref = d->xref_alloc;
-        grid_clear_cells(d);
-
-        for (i = 0; i < n; ++i)
-        {
-            copy_rvec(x[i], d->xref[i]);
-        }
-        put_atoms_in_triclinic_unitcell(ecenterTRIC, pbc->box, n, d->xref);
-        for (i = 0; i < n; ++i)
-        {
-            ivec refcell;
-
-            grid_map_onto(d, d->xref[i], refcell);
-            grid_add_to_cell(d, refcell, i);
-        }
-    }
-    else
-    {
-        d->xref = x;
-    }
-    d->refid = NULL;
-    return 0;
-}
-
-/*!
- * \param[in,out] d   Neighborhood search data structure.
- * \param[in]     pbc PBC information for the frame.
- * \param[in]     p   Reference positions for the frame.
- * \returns       0 on success.
- *
- * A convenience wrapper for gmx_ana_nbsearch_init().
- */
-int
-gmx_ana_nbsearch_pos_init(gmx_ana_nbsearch_t *d, t_pbc *pbc, gmx_ana_pos_t *p)
-{
-    int rc;
-
-    rc = gmx_ana_nbsearch_init(d, pbc, p->nr, p->x);
-    d->refid = (p->nr < d->maxnref ? p->m.refid : NULL);
-    return rc;
-}
-
-/*!
- * \param[in,out] d     Neighborhood search data structure.
- * \param[in]     nexcl Number of reference positions to exclude from next
- *      search.
- * \param[in]     excl  Indices of reference positions to exclude.
- * \returns       0 on success.
- *
- * The set exclusions remain in effect until the next call of this function.
- */
-int
-gmx_ana_nbsearch_set_excl(gmx_ana_nbsearch_t *d, int nexcl, int excl[])
-{
-
-    d->nexcl = nexcl;
-    d->excl = excl;
-    return 0;
-}
-
-/*! \brief
- * Helper function to check whether a reference point should be excluded.
- */
-static gmx_bool
-is_excluded(gmx_ana_nbsearch_t *d, int j)
-{
-    if (d->exclind < d->nexcl)
-    {
-        if (d->refid)
-        {
-            while (d->exclind < d->nexcl && d->refid[j] > d->excl[d->exclind])
-            {
-                ++d->exclind;
-            }
-            if (d->exclind < d->nexcl && d->refid[j] == d->excl[d->exclind])
-            {
-                ++d->exclind;
-                return TRUE;
-            }
-        }
-        else
-        {
-            while (d->bGrid && d->exclind < d->nexcl && d->excl[d->exclind] < j)
-            {
-                ++d->exclind;
-            }
-            if (d->excl[d->exclind] == j)
-            {
-                ++d->exclind;
-                return TRUE;
-            }
-        }
-    }
-    return FALSE;
-}
-
-/*! \brief
- * Initializes a grid search to find reference positions neighboring \p x.
- */
-static void
-grid_search_start(gmx_ana_nbsearch_t *d, rvec x)
-{
-    copy_rvec(x, d->xtest);
-    if (d->bGrid)
-    {
-        put_atoms_in_triclinic_unitcell(ecenterTRIC, d->pbc->box, 1, &d->xtest);
-        grid_map_onto(d, d->xtest, d->testcell);
-        d->prevnbi = 0;
-        d->prevcai = -1;
-    }
-    else
-    {
-        d->previ = -1;
-    }
-    d->exclind = 0;
-}
-
-/*! \brief
- * Does a grid search.
- */
-static gmx_bool
-grid_search(gmx_ana_nbsearch_t *d,
-            gmx_bool (*action)(gmx_ana_nbsearch_t *d, int i, real r2))
-{
-    int  i;
-    rvec dx;
-    real r2;
-
-    if (d->bGrid)
-    {
-        int  nbi, ci, cai;
-
-        nbi = d->prevnbi;
-        cai = d->prevcai + 1;
-
-        for ( ; nbi < d->ngridnb; ++nbi)
-        {
-            ivec cell;
-
-            ivec_add(d->testcell, d->gnboffs[nbi], cell);
-            /* TODO: Support for 2D and screw PBC */
-            cell[XX] = (cell[XX] + d->ncelldim[XX]) % d->ncelldim[XX];
-            cell[YY] = (cell[YY] + d->ncelldim[YY]) % d->ncelldim[YY];
-            cell[ZZ] = (cell[ZZ] + d->ncelldim[ZZ]) % d->ncelldim[ZZ];
-            ci = grid_index(d, cell);
-            /* TODO: Calculate the required PBC shift outside the inner loop */
-            for ( ; cai < d->ncatoms[ci]; ++cai)
-            {
-                i = d->catom[ci][cai];
-                if (is_excluded(d, i))
-                {
-                    continue;
-                }
-                pbc_dx_aiuc(d->pbc, d->xtest, d->xref[i], dx);
-                r2 = norm2(dx);
-                if (r2 <= d->cutoff2)
-                {
-                    if (action(d, i, r2))
-                    {
-                        d->prevnbi = nbi;
-                        d->prevcai = cai;
-                        d->previ   = i;
-                        return TRUE;
-                    }
-                }
-            }
-            d->exclind = 0;
-            cai = 0;
-        }
-    }
-    else
-    {
-        i = d->previ + 1;
-        for ( ; i < d->nref; ++i)
-        {
-            if (is_excluded(d, i))
-            {
-                continue;
-            }
-            if (d->pbc)
-            {
-                pbc_dx(d->pbc, d->xtest, d->xref[i], dx);
-            }
-            else
-            {
-                rvec_sub(d->xtest, d->xref[i], dx);
-            }
-            r2 = norm2(dx);
-            if (r2 <= d->cutoff2)
-            {
-                if (action(d, i, r2))
-                {
-                    d->previ = i;
-                    return TRUE;
-                }
-            }
-        }
-    }
-    return FALSE;
-}
-
-/*! \brief
- * Helper function to use with grid_search() to find the next neighbor.
- *
- * Simply breaks the loop on the first found neighbor.
- */
-static gmx_bool
-within_action(gmx_ana_nbsearch_t *d, int i, real r2)
-{
-    return TRUE;
-}
-
-/*! \brief
- * Helper function to use with grid_search() to find the minimum distance.
- */
-static gmx_bool
-mindist_action(gmx_ana_nbsearch_t *d, int i, real r2)
-{
-    d->cutoff2 = r2;
-    return FALSE;
-}
-
-/*!
- * \param[in] d   Neighborhood search data structure.
- * \param[in] x   Test position.
- * \returns   TRUE if \p x is within the cutoff of any reference position,
- *   FALSE otherwise.
- */
-gmx_bool
-gmx_ana_nbsearch_is_within(gmx_ana_nbsearch_t *d, rvec x)
-{
-    grid_search_start(d, x);
-    return grid_search(d, &within_action);
-}
-
-/*!
- * \param[in] d   Neighborhood search data structure.
- * \param[in] p   Test positions.
- * \param[in] i   Use the i'th position in \p p for testing.
- * \returns   TRUE if the test position is within the cutoff of any reference
- *   position, FALSE otherwise.
- */
-gmx_bool
-gmx_ana_nbsearch_pos_is_within(gmx_ana_nbsearch_t *d, gmx_ana_pos_t *p, int i)
-{
-    return gmx_ana_nbsearch_is_within(d, p->x[i]);
-}
-
-/*!
- * \param[in] d   Neighborhood search data structure.
- * \param[in] x   Test position.
- * \returns   The distance to the nearest reference position, or the cutoff
- *   value if there are no reference positions within the cutoff.
- */
-real
-gmx_ana_nbsearch_mindist(gmx_ana_nbsearch_t *d, rvec x)
-{
-    real mind;
-
-    grid_search_start(d, x);
-    grid_search(d, &mindist_action);
-    mind = sqrt(d->cutoff2);
-    d->cutoff2 = sqr(d->cutoff);
-    return mind;
-}
-
-/*!
- * \param[in] d   Neighborhood search data structure.
- * \param[in] p   Test positions.
- * \param[in] i   Use the i'th position in \p p for testing.
- * \returns   The distance to the nearest reference position, or the cutoff
- *   value if there are no reference positions within the cutoff.
- */
-real
-gmx_ana_nbsearch_pos_mindist(gmx_ana_nbsearch_t *d, gmx_ana_pos_t *p, int i)
-{
-    return gmx_ana_nbsearch_mindist(d, p->x[i]);
-}
-
-/*!
- * \param[in]  d   Neighborhood search data structure.
- * \param[in]  n   Number of test positions in \p x.
- * \param[in]  x   Test positions.
- * \param[out] jp  Index of the reference position in the first pair.
- * \returns    TRUE if there are positions within the cutoff.
- */
-gmx_bool
-gmx_ana_nbsearch_first_within(gmx_ana_nbsearch_t *d, rvec x, int *jp)
-{
-    grid_search_start(d, x);
-    return gmx_ana_nbsearch_next_within(d, jp);
-}
-
-/*!
- * \param[in]  d   Neighborhood search data structure.
- * \param[in]  p   Test positions.
- * \param[in]  i   Use the i'th position in \p p.
- * \param[out] jp  Index of the reference position in the first pair.
- * \returns    TRUE if there are positions within the cutoff.
- */
-gmx_bool
-gmx_ana_nbsearch_pos_first_within(gmx_ana_nbsearch_t *d, gmx_ana_pos_t *p,
-                                  int i, int *jp)
-{
-    return gmx_ana_nbsearch_first_within(d, p->x[i], jp);
-}
-
-/*!
- * \param[in]  d   Neighborhood search data structure.
- * \param[out] jp  Index of the test position in the next pair.
- * \returns    TRUE if there are positions within the cutoff.
- */
-gmx_bool
-gmx_ana_nbsearch_next_within(gmx_ana_nbsearch_t *d, int *jp)
-{
-    if (grid_search(d, &within_action))
-    {
-        *jp = d->previ;
-        return TRUE;
-    }
-    *jp = -1;
-    return FALSE;
-}
diff --git a/src/gmxlib/trajana/poscalc.c b/src/gmxlib/trajana/poscalc.c
deleted file mode 100644 (file)
index 9a319e6..0000000
+++ /dev/null
@@ -1,1463 +0,0 @@
-/*
- *
- *                This source code is part of
- *
- *                 G   R   O   M   A   C   S
- *
- *          GROningen MAchine for Chemical Simulations
- *
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
- * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
- * Copyright (c) 2001-2009, The GROMACS development team,
- * check out http://www.gromacs.org for more information.
-
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * If you want to redistribute modifications, please consider that
- * scientific software is very special. Version control is crucial -
- * bugs must be traceable. We will be happy to consider code for
- * inclusion in the official distribution, but derived work must not
- * be called official GROMACS. Details are found in the README & COPYING
- * files - if they are missing, get the official version at www.gromacs.org.
- *
- * To help us fund GROMACS development, we humbly ask that you cite
- * the papers on the package - you can find them in the top README file.
- *
- * For more info, check our website at http://www.gromacs.org
- */
-/*! \internal
- * \page poscalcengine Position calculation engine
- *
- * The header file \ref poscalc.h defines an API for calculating positions
- * in an automated way. This is useful mostly in the selection engine, in
- * particular with dynamic selections, because the same COM/COG positions
- * may be needed in several contexts. The API makes it possible to
- * optimize the evaluation such that any heavy calculation is only done once,
- * and the results just copied if needed more than once.
- * The functions also provide a convenient interface for keeping the whole
- * \c gmx_ana_pos_t structure up-to-date.
- *
- * A new collection of position calculations is allocated with
- * gmx_ana_poscalc_coll_create().
- * Calculations within one collection should share the same topology, and
- * they are optimized. Calculations in different collections do not interact.
- * The topology for a collection can be set with
- * gmx_ana_poscalc_coll_set_topology().
- * This needs to be done before calling gmx_ana_poscalc_set_maxindex() for
- * any calculation in the collection, unless that calculation does not
- * require topology information.
- * All memory allocated for a collection and the calculations in it can be
- * freed with gmx_ana_poscalc_coll_free().
- *
- * A new calculation is created with gmx_ana_poscalc_create().
- * If flags need to be adjusted later, gmx_ana_poscalc_set_flags() can be
- * used.
- * After the flags are final, the largest possible index group for which the
- * positions are needed has to be set with gmx_ana_poscalc_set_maxindex().
- * gmx_ana_poscalc_coll_set_topology() should have been called before this
- * function is called.
- * After the above calls, gmx_ana_poscalc_init_pos() can be used to initialize
- * output to a \c gmx_ana_pos_t structure. Several different structures can be
- * initialized for the same calculation; the only requirement is that the
- * structure passed later to gmx_ana_poscalc_update() has been initialized
- * properly.
- * The memory allocated for a calculation can be freed with
- * gmx_ana_poscalc_free().
- *
- * The position evaluation is simple: gmx_ana_poscalc_init_frame() should be
- * called once for each frame, and gmx_ana_poscalc_update() can then be called
- * for each calculation that is needed for that frame.
- *
- * It is also possible to initialize the calculations based on a type provided
- * as a string.
- * The possible strings are returned by gmx_ana_poscalc_create_type_enum(),
- * and the string can be converted to the parameters for
- * gmx_ana_poscalc_create() using gmx_ana_poscalc_type_from_enum().
- * gmx_ana_poscalc_create_enum() is also provided for convenience.
- */
-/*! \internal \file
- * \brief Implementation of functions in poscalc.h.
- *
- * \todo
- * There is probably some room for optimization in the calculation of
- * positions with bases.
- * In particular, the current implementation may do a lot of unnecessary
- * copying.
- * The interface would need to be changed to make it possible to use the
- * same output positions for several calculations.
- *
- * \todo
- * The current algorithm for setting up base calculations could be improved
- * in cases when there are calculations that cannot use a common base but
- * still overlap partially (e.g., with three calculations A, B, and C
- * such that A could use both B and C as a base, but B and C cannot use the
- * same base).
- * Setting up the bases in an optimal manner in every possible situation can
- * be quite difficult unless several bases are allowed for one calculation,
- * but better heuristics could probably be implemented.
- * For best results, the setup should probably be postponed (at least
- * partially) to gmx_ana_poscalc_init_eval().
- */
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <string.h>
-
-#include <macros.h>
-#include <smalloc.h>
-#include <typedefs.h>
-#include <pbc.h>
-#include <vec.h>
-
-#include <centerofmass.h>
-#include <indexutil.h>
-#include <poscalc.h>
-#include <position.h>
-
-/*! \internal \brief
- * Collection of \c gmx_ana_poscalc_t structures for the same topology.
- *
- * Calculations within the same structure are optimized to eliminate duplicate
- * calculations.
- */
-struct gmx_ana_poscalc_coll_t
-{
-    /*! \brief
-     * Topology data.
-     *
-     * Can be NULL if none of the calculations require topology data or if
-     * gmx_ana_poscalc_coll_set_topology() has not been called.
-     */
-    t_topology               *top;
-    /** Pointer to the first data structure. */
-    gmx_ana_poscalc_t        *first;
-    /** Pointer to the last data structure. */
-    gmx_ana_poscalc_t        *last;
-    /** Whether the collection has been initialized for evaluation. */
-    gmx_bool                      bInit;
-};
-
-/*! \internal \brief
- * Data structure for position calculation.
- */
-struct gmx_ana_poscalc_t
-{
-    /*! \brief
-     * Type of calculation.
-     *
-     * This field may differ from the type requested by the user, because
-     * it is changed internally to the most effective calculation.
-     * For example, if the user requests a COM calculation for residues
-     * consisting of single atoms, it is simply set to POS_ATOM.
-     * To provide a consistent interface to the user, the field \p itype
-     * should be used when information should be given out.
-     */
-    e_poscalc_t               type;
-    /*! \brief
-     * Flags for calculation options.
-     *
-     * See \ref poscalc_flags "documentation of the flags".
-     */
-    int                       flags;
-
-    /*! \brief
-     * Type for the created indices.
-     *
-     * This field always agrees with the type that the user requested, but
-     * may differ from \p type.
-     */
-    e_index_t                 itype;
-    /*! \brief
-     * Block data for the calculation.
-     */
-    t_blocka                  b;
-    /*! \brief
-     * Mapping from the blocks to the blocks of \p sbase.
-     *
-     * If \p sbase is NULL, this field is also.
-     */
-    int                      *baseid;
-    /*! \brief
-     * Maximum evaluation group.
-     */
-    gmx_ana_index_t           gmax;
-
-    /** Position storage for calculations that are used as a base. */
-    gmx_ana_pos_t            *p;
-
-    /** TRUE if the positions have been evaluated for the current frame. */
-    gmx_bool                      bEval;
-    /*! \brief
-     * Base position data for this calculation.
-     *
-     * If not NULL, the centers required by this calculation have
-     * already been calculated in \p sbase.
-     * The structure pointed by \p sbase is always a static calculation.
-     */
-    struct gmx_ana_poscalc_t *sbase;
-    /** Next structure in the linked list of calculations. */
-    struct gmx_ana_poscalc_t *next;
-    /** Previous structure in the linked list of calculations. */
-    struct gmx_ana_poscalc_t *prev;
-    /** Number of references to this structure. */
-    int                       refcount;
-    /** Collection this calculation belongs to. */
-    gmx_ana_poscalc_coll_t   *coll;
-};
-    
-static const char *const poscalc_enum_strings[] = {
-    "atom",
-    "res_com",       "res_cog",
-    "mol_com",       "mol_cog",
-    "whole_res_com", "whole_res_cog",
-    "whole_mol_com", "whole_mol_cog",
-    "part_res_com",  "part_res_cog",
-    "part_mol_com",  "part_mol_cog",
-    "dyn_res_com",   "dyn_res_cog",
-    "dyn_mol_com",   "dyn_mol_cog",
-    NULL,
-};
-#define NENUM asize(poscalc_enum_strings)
-
-/*! \brief
- * Returns the partition type for a given position type.
- *
- * \param [in] type  \c e_poscalc_t value to convert.
- * \returns    Corresponding \c e_indet_t.
- */
-static e_index_t
-index_type_for_poscalc(e_poscalc_t type)
-{
-    switch(type)
-    {
-        case POS_ATOM:    return INDEX_ATOM;
-        case POS_RES:     return INDEX_RES;
-        case POS_MOL:     return INDEX_MOL;
-        case POS_ALL:     return INDEX_ALL;
-        case POS_ALL_PBC: return INDEX_ALL;
-    }
-    return INDEX_UNKNOWN;
-}
-
-/*!
- * \param[in]     post  String (typically an enum command-line argument).
- *   Allowed values: 'atom', 'res_com', 'res_cog', 'mol_com', 'mol_cog',
- *   or one of the last four prepended by 'whole_', 'part_', or 'dyn_'.
- * \param[out]    type  \c e_poscalc_t corresponding to \p post.
- * \param[in,out] flags Flags corresponding to \p post.
- *   On input, the flags should contain the default flags.
- *   On exit, the flags \ref POS_MASS, \ref POS_COMPLMAX and
- *   \ref POS_COMPLWHOLE have been set according to \p post
- *   (the completion flags are left at the default values if no completion
- *   prefix is given).
- * \returns       0 if \p post is one of the valid strings, EINVAL otherwise.
- *
- * \attention
- * Checking is not complete, and other values than those listed above
- * may be accepted for \p post, but the results are undefined.
- */
-int
-gmx_ana_poscalc_type_from_enum(const char *post, e_poscalc_t *type, int *flags)
-{
-    const char *ptr;
-
-    if (post[0] == 'a')
-    {
-        *type   = POS_ATOM;
-        *flags &= ~(POS_MASS | POS_COMPLMAX | POS_COMPLWHOLE);
-        return 0;
-    }
-
-    /* Process the prefix */
-    ptr = post;
-    if (post[0] == 'w')
-    {
-        *flags &= ~POS_COMPLMAX;
-        *flags |= POS_COMPLWHOLE;
-        ptr = post + 6;
-    }
-    else if (post[0] == 'p')
-    {
-        *flags &= ~POS_COMPLWHOLE;
-        *flags |= POS_COMPLMAX;
-        ptr = post + 5;
-    }
-    else if (post[0] == 'd')
-    {
-        *flags &= ~(POS_COMPLMAX | POS_COMPLWHOLE);
-        ptr = post + 4;
-    }
-
-    if (ptr[0] == 'r')
-    {
-        *type = POS_RES;
-    }
-    else if (ptr[0] == 'm')
-    {
-        *type = POS_MOL;
-    }
-    else
-    {
-        gmx_incons("unknown position calculation type");
-        return EINVAL;
-    }
-    if (ptr[6] == 'm')
-    {
-        *flags |= POS_MASS;
-    }
-    else if (ptr[6] == 'g')
-    {
-        *flags &= ~POS_MASS;
-    }
-    else
-    {
-        gmx_incons("unknown position calculation type");
-        return EINVAL;
-    }
-    return 0;
-}
-
-/*!
- * \param[in]  bAtom    If TRUE, the "atom" value is included.
- * \returns    NULL-terminated array of strings that contains the string
- *   values acceptable for gmx_ana_poscalc_type_from_enum().
- *
- * The first string in the returned list is always NULL to allow the list to
- * be used with Gromacs command-line parsing.
- */
-const char **
-gmx_ana_poscalc_create_type_enum(gmx_bool bAtom)
-{
-    const char **pcenum;
-    size_t       i;
-
-    if (bAtom)
-    {
-        snew(pcenum, NENUM+1);
-        for (i = 0; i < NENUM; ++i)
-        {
-            pcenum[i+1] = poscalc_enum_strings[i];
-        }
-    }
-    else
-    {
-        snew(pcenum, NENUM+1-1);
-        for (i = 1; i < NENUM; ++i)
-        {
-            pcenum[i] = poscalc_enum_strings[i];
-        }
-    }
-    pcenum[0] = NULL;
-    return pcenum;
-}
-
-/*!
- * \param[out] pccp   Allocated position calculation collection.
- * \returns    0 for success.
- */
-int
-gmx_ana_poscalc_coll_create(gmx_ana_poscalc_coll_t **pccp)
-{
-    gmx_ana_poscalc_coll_t *pcc;
-
-    snew(pcc, 1);
-    pcc->top   = NULL;
-    pcc->first = NULL;
-    pcc->last  = NULL;
-    pcc->bInit = FALSE;
-    *pccp = pcc;
-    return 0;
-}
-
-/*!
- * \param[in,out] pcc   Position calculation collection data structure.
- * \param[in]     top   Topology data structure.
- *
- * This function should be called to set the topology before using
- * gmx_ana_poscalc_set_maxindex() for any calculation that requires
- * topology information.
- */
-void
-gmx_ana_poscalc_coll_set_topology(gmx_ana_poscalc_coll_t *pcc, t_topology *top)
-{
-    pcc->top = top;
-}
-
-/*!
- * \param[in] pcc   Position calculation collection to free.
- *
- * The pointer \p pcc is invalid after the call.
- * Any calculations in the collection are also freed, no matter how many
- * references to them are left.
- */
-void
-gmx_ana_poscalc_coll_free(gmx_ana_poscalc_coll_t *pcc)
-{
-    while (pcc->first)
-    {
-        gmx_ana_poscalc_free(pcc->first);
-    }
-    sfree(pcc);
-}
-
-/*!
- * \param[in] fp    File handle to receive the output.
- * \param[in] pcc   Position calculation collection to print.
- *
- * The output is very technical, making this function mainly useful for
- * debugging purposes.
- */
-void
-gmx_ana_poscalc_coll_print_tree(FILE *fp, gmx_ana_poscalc_coll_t *pcc)
-{
-    gmx_ana_poscalc_t *pc;
-    int                i, j;
-
-    fprintf(fp, "Position calculations:\n");
-    i  = 1;
-    pc = pcc->first;
-    while (pc)
-    {
-        fprintf(fp, "%2d ", i);
-        switch (pc->type)
-        {
-            case POS_ATOM:    fprintf(fp, "ATOM");    break;
-            case POS_RES:     fprintf(fp, "RES");     break;
-            case POS_MOL:     fprintf(fp, "MOL");     break;
-            case POS_ALL:     fprintf(fp, "ALL");     break;
-            case POS_ALL_PBC: fprintf(fp, "ALL_PBC"); break;
-        }
-        if (pc->itype != index_type_for_poscalc(pc->type))
-        {
-            fprintf(fp, " (");
-            switch (pc->itype)
-            {
-                case INDEX_UNKNOWN: fprintf(fp, "???");  break;
-                case INDEX_ATOM:    fprintf(fp, "ATOM"); break;
-                case INDEX_RES:     fprintf(fp, "RES");  break;
-                case INDEX_MOL:     fprintf(fp, "MOL");  break;
-                case INDEX_ALL:     fprintf(fp, "ALL");  break;
-            }
-            fprintf(fp, ")");
-        }
-        fprintf(fp, " flg=");
-        if (pc->flags & POS_MASS)
-        {
-            fprintf(fp, "M");
-        }
-        if (pc->flags & POS_DYNAMIC)
-        {
-            fprintf(fp, "D");
-        }
-        if (pc->flags & POS_MASKONLY)
-        {
-            fprintf(fp, "A");
-        }
-        if (pc->flags & POS_COMPLMAX)
-        {
-            fprintf(fp, "Cm");
-        }
-        if (pc->flags & POS_COMPLWHOLE)
-        {
-            fprintf(fp, "Cw");
-        }
-        if (!pc->flags)
-        {
-            fprintf(fp, "0");
-        }
-        fprintf(fp, " nr=%d nra=%d", pc->b.nr, pc->b.nra);
-        fprintf(fp, " refc=%d", pc->refcount);
-        fprintf(fp, "\n");
-        if (pc->gmax.nalloc_index > 0)
-        {
-            fprintf(fp, "   Group: ");
-            if (pc->gmax.isize > 20)
-            {
-                fprintf(fp, " %d atoms", pc->gmax.isize);
-            }
-            else
-            {
-                for (j = 0; j < pc->gmax.isize; ++j)
-                {
-                    fprintf(fp, " %d", pc->gmax.index[j] + 1);
-                }
-            }
-            fprintf(fp, "\n");
-        }
-        if (pc->b.nalloc_a > 0)
-        {
-            fprintf(fp, "   Atoms: ");
-            if (pc->b.nra > 20)
-            {
-                fprintf(fp, " %d atoms", pc->b.nra);
-            }
-            else
-            {
-                for (j = 0; j < pc->b.nra; ++j)
-                {
-                    fprintf(fp, " %d", pc->b.a[j] + 1);
-                }
-            }
-            fprintf(fp, "\n");
-        }
-        if (pc->b.nalloc_index > 0)
-        {
-            fprintf(fp, "   Blocks:");
-            if (pc->b.nr > 20)
-            {
-                fprintf(fp, " %d pcs", pc->b.nr);
-            }
-            else
-            {
-                for (j = 0; j <= pc->b.nr; ++j)
-                {
-                    fprintf(fp, " %d", pc->b.index[j]);
-                }
-            }
-            fprintf(fp, "\n");
-        }
-        if (pc->sbase)
-        {
-            gmx_ana_poscalc_t *base;
-
-            fprintf(fp, "   Base: ");
-            j = 1;
-            base = pcc->first;
-            while (base && base != pc->sbase)
-            {
-                ++j;
-                base = base->next;
-            }
-            fprintf(fp, "%d", j);
-            if (pc->baseid && pc->b.nr <= 20)
-            {
-                fprintf(fp, " id:");
-                for (j = 0; j < pc->b.nr; ++j)
-                {
-                    fprintf(fp, " %d", pc->baseid[j]+1);
-                }
-            }
-            fprintf(fp, "\n");
-        }
-        ++i;
-        pc = pc->next;
-    }
-}
-
-/*! \brief
- * Inserts a position calculation structure into its collection.
- *
- * \param pc     Data structure to insert.
- * \param before Data structure before which to insert
- *   (NULL = insert at end).
- *
- * Inserts \p pc to its collection before \p before.
- * If \p before is NULL, \p pc is appended to the list.
- */
-static void
-insert_poscalc(gmx_ana_poscalc_t *pc, gmx_ana_poscalc_t *before)
-{
-    if (before == NULL)
-    {
-        pc->next = NULL;
-        pc->prev = pc->coll->last;
-        if (pc->coll->last)
-        {
-            pc->coll->last->next = pc;
-        }
-        pc->coll->last = pc;
-    }
-    else
-    {
-        pc->prev     = before->prev;
-        pc->next     = before;
-        if (before->prev)
-        {
-            before->prev->next = pc;
-        }
-        before->prev = pc;
-    }
-    if (!pc->prev)
-    {
-        pc->coll->first = pc;
-    }
-}
-
-/*! \brief
- * Removes a position calculation structure from its collection.
- *
- * \param pc    Data structure to remove.
- *
- * Removes \p pc from its collection.
- */
-static void
-remove_poscalc(gmx_ana_poscalc_t *pc)
-{
-    if (pc->prev)
-    {
-        pc->prev->next = pc->next;
-    }
-    else if (pc == pc->coll->first)
-    {
-        pc->coll->first = pc->next;
-    }
-    if (pc->next)
-    {
-        pc->next->prev = pc->prev;
-    }
-    else if (pc == pc->coll->last)
-    {
-        pc->coll->last = pc->prev;
-    }
-    pc->prev = pc->next = NULL;
-}
-
-/*! \brief
- * Initializes position calculation using the maximum possible input index.
- *
- * \param[in,out] pc  Position calculation data structure.
- * \param[in]     g   Maximum index group for the calculation.
- * \param[in]     bBase Whether \p pc will be used as a base or not.
- *
- * \p bBase affects on how the \p pc->gmax field is initialized.
- */
-static void
-set_poscalc_maxindex(gmx_ana_poscalc_t *pc, gmx_ana_index_t *g, gmx_bool bBase)
-{
-    gmx_ana_index_make_block(&pc->b, pc->coll->top, g, pc->itype, pc->flags & POS_COMPLWHOLE);
-    /* Set the type to POS_ATOM if the calculation in fact is such. */
-    if (pc->b.nr == pc->b.nra)
-    {
-        pc->type   = POS_ATOM; 
-        pc->flags &= ~(POS_MASS | POS_COMPLMAX | POS_COMPLWHOLE);
-    }
-    /* Set the POS_COMPLWHOLE flag if the calculation in fact always uses
-     * complete residues and molecules. */
-    if (!(pc->flags & POS_COMPLWHOLE)
-        && (!(pc->flags & POS_DYNAMIC) || (pc->flags & POS_COMPLMAX))
-        && (pc->type == POS_RES || pc->type == POS_MOL)
-        && gmx_ana_index_has_complete_elems(g, pc->itype, pc->coll->top))
-    {
-        pc->flags &= ~POS_COMPLMAX;
-        pc->flags |= POS_COMPLWHOLE;
-    }
-    /* Setup the gmax field */
-    if ((pc->flags & POS_COMPLWHOLE) && !bBase && pc->b.nra > g->isize)
-    {
-        gmx_ana_index_copy(&pc->gmax, g, TRUE);
-        sfree(pc->gmax.name);
-        pc->gmax.name  = NULL;
-    }
-    else
-    {
-        gmx_ana_index_set(&pc->gmax, pc->b.nra, pc->b.a, NULL, 0);
-    }
-}
-
-/*! \brief
- * Checks whether a position calculation should use a base at all.
- *
- * \param[in] pc   Position calculation data to check.
- * \returns   TRUE if \p pc can use a base and gets some benefit out of it,
- *   FALSE otherwise.
- */
-static gmx_bool
-can_use_base(gmx_ana_poscalc_t *pc)
-{
-    /* For atoms, it should be faster to do a simple copy, so don't use a
-     * base. */
-    if (pc->type == POS_ATOM)
-    {
-        return FALSE;
-    }
-    /* For dynamic selections that do not use completion, it is not possible
-     * to use a base. */
-    if ((pc->type == POS_RES || pc->type == POS_MOL)
-        && (pc->flags & POS_DYNAMIC) && !(pc->flags & (POS_COMPLMAX | POS_COMPLWHOLE)))
-    {
-        return FALSE;
-    }
-    /* Dynamic calculations for a single position cannot use a base. */
-    if ((pc->type == POS_ALL || pc->type == POS_ALL_PBC)
-        && (pc->flags & POS_DYNAMIC))
-    {
-        return FALSE;
-    }
-    return TRUE;
-}
-
-/*! \brief
- * Checks whether two position calculations should use a common base.
- *
- * \param[in]     pc1 Calculation 1 to check for.
- * \param[in]     pc2 Calculation 2 to check for.
- * \param[in]     g1  Index group structure that contains the atoms from
- *   \p pc1.
- * \param[in,out] g   Working space, should have enough allocated memory to
- *   contain the intersection of the atoms in \p pc1 and \p pc2.
- * \returns   TRUE if the two calculations should be merged to use a common
- *   base, FALSE otherwise.
- */
-static gmx_bool
-should_merge(gmx_ana_poscalc_t *pc1, gmx_ana_poscalc_t *pc2,
-             gmx_ana_index_t *g1, gmx_ana_index_t *g)
-{
-    gmx_ana_index_t  g2;
-
-    /* Do not merge calculations with different mass weighting. */
-    if ((pc1->flags & POS_MASS) != (pc2->flags & POS_MASS))
-    {
-        return FALSE;
-    }
-    /* Avoid messing up complete calculations. */
-    if ((pc1->flags & POS_COMPLWHOLE) != (pc2->flags & POS_COMPLWHOLE))
-    {
-        return FALSE;
-    }
-    /* Find the overlap between the calculations. */
-    gmx_ana_index_set(&g2, pc2->b.nra, pc2->b.a, NULL, 0);
-    gmx_ana_index_intersection(g, g1, &g2);
-    /* Do not merge if there is no overlap. */
-    if (g->isize == 0)
-    {
-        return FALSE;
-    }
-    /* Full completion calculations always match if the type is correct. */
-    if ((pc1->flags & POS_COMPLWHOLE) && (pc2->flags & POS_COMPLWHOLE)
-        && pc1->type == pc2->type)
-    {
-        return TRUE;
-    }
-    /* The calculations also match if the intersection consists of full
-     * blocks. */
-    if (gmx_ana_index_has_full_ablocks(g, &pc1->b)
-        && gmx_ana_index_has_full_ablocks(g, &pc2->b))
-    {
-        return TRUE;
-    }
-    return FALSE;
-}
-
-/*! \brief
- * Creates a static base for position calculation.
- *
- * \param     pc  Data structure to copy.
- * \returns   Pointer to a newly allocated base for \p pc.
- *
- * Creates and returns a deep copy of \p pc, but clears the
- * \ref POS_DYNAMIC and \ref POS_MASKONLY flags.
- * The newly created structure is set as the base (\c gmx_ana_poscalc_t::sbase)
- * of \p pc and inserted in the collection before \p pc.
- */
-static gmx_ana_poscalc_t *
-create_simple_base(gmx_ana_poscalc_t *pc)
-{
-    gmx_ana_poscalc_t *base;
-    int                flags;
-    int                rc;
-
-    flags = pc->flags & ~(POS_DYNAMIC | POS_MASKONLY);
-    rc = gmx_ana_poscalc_create(&base, pc->coll, pc->type, flags);
-    if (rc != 0)
-    {
-        gmx_fatal(FARGS, "position calculation base creation failed");
-    }
-    set_poscalc_maxindex(base, &pc->gmax, TRUE);
-
-    snew(base->p, 1);
-
-    pc->sbase = base;
-    remove_poscalc(base);
-    insert_poscalc(base, pc);
-
-    return base;
-}
-
-/*! \brief
- * Merges a calculation into another calculation such that the new calculation
- * can be used as a base.
- *
- * \param[in,out] base Base calculation to merge to.
- * \param[in,out] pc   Position calculation to merge to \p base.
- *
- * After the call, \p base can be used as a base for \p pc (or any calculation
- * that used it as a base).
- * It is assumed that any overlap between \p base and \p pc is in complete
- * blocks, i.e., that the merge is possible.
- */
-static void
-merge_to_base(gmx_ana_poscalc_t *base, gmx_ana_poscalc_t *pc)
-{
-    gmx_ana_index_t  gp, gb, g;
-    int              isize, bnr;
-    int              i, j, bi, bj, bo;
-
-    base->flags |= pc->flags & (POS_VELOCITIES | POS_FORCES);
-    gmx_ana_index_set(&gp, pc->b.nra, pc->b.a, NULL, 0);
-    gmx_ana_index_set(&gb, base->b.nra, base->b.a, NULL, 0);
-    isize = gmx_ana_index_difference_size(&gp, &gb);
-    if (isize > 0)
-    {
-        gmx_ana_index_clear(&g);
-        gmx_ana_index_reserve(&g, base->b.nra + isize);
-        /* Find the new blocks */
-        gmx_ana_index_difference(&g, &gp, &gb);
-        /* Count the blocks in g */
-        i = bi = bnr = 0;
-        while (i < g.isize)
-        {
-            while (pc->b.a[pc->b.index[bi]] != g.index[i])
-            {
-                ++bi;
-            }
-            i += pc->b.index[bi+1] - pc->b.index[bi];
-            ++bnr;
-            ++bi;
-        }
-        /* Merge the atoms into a temporary structure */
-        gmx_ana_index_merge(&g, &gb, &g);
-        /* Merge the blocks */
-        srenew(base->b.index, base->b.nr + bnr + 1);
-        i  = g.isize - 1;
-        bi = base->b.nr - 1;
-        bj = pc->b.nr - 1;
-        bo = base->b.nr + bnr - 1;
-        base->b.index[bo+1] = i + 1;
-        while (bo >= 0)
-        {
-            if (bi < 0 || base->b.a[base->b.index[bi+1]-1] != g.index[i])
-            {
-                i -= pc->b.index[bj+1] - pc->b.index[bj];
-                --bj;
-            }
-            else
-            {
-                if (bj >= 0 && pc->b.a[pc->b.index[bj+1]-1] == g.index[i])
-                {
-                    --bj;
-                }
-                i -= base->b.index[bi+1] - base->b.index[bi];
-                --bi;
-            }
-            base->b.index[bo] = i + 1;
-            --bo;
-        }
-        base->b.nr           += bnr;
-        base->b.nalloc_index += bnr;
-        sfree(base->b.a);
-        base->b.nra      = g.isize;
-        base->b.a        = g.index;
-        base->b.nalloc_a = g.isize;
-        /* Refresh the gmax field */
-        gmx_ana_index_set(&base->gmax, base->b.nra, base->b.a, NULL, 0);
-    }
-}
-
-/*! \brief
- * Merges two bases into one.
- *
- * \param[in,out] tbase Base calculation to merge to.
- * \param[in]     mbase Base calculation to merge to \p tbase.
- *
- * After the call, \p mbase has been freed and \p tbase is used as the base
- * for all calculations that previously had \p mbase as their base.
- * It is assumed that any overlap between \p tbase and \p mbase is in complete
- * blocks, i.e., that the merge is possible.
- */
-static void
-merge_bases(gmx_ana_poscalc_t *tbase, gmx_ana_poscalc_t *mbase)
-{
-    gmx_ana_poscalc_t *pc;
-
-    merge_to_base(tbase, mbase);
-    remove_poscalc(mbase);
-    /* Set tbase as the base for all calculations that had mbase */
-    pc = tbase->coll->first;
-    while (pc)
-    {
-        if (pc->sbase == mbase)
-        {
-            pc->sbase = tbase;
-            tbase->refcount++;
-        }
-        pc = pc->next;
-    }
-    /* Free mbase */
-    mbase->refcount = 0;
-    gmx_ana_poscalc_free(mbase);
-}
-
-/*! \brief
- * Setups the static base calculation for a position calculation.
- *
- * \param[in,out] pc   Position calculation to setup the base for.
- */
-static void
-setup_base(gmx_ana_poscalc_t *pc)
-{
-    gmx_ana_poscalc_t *base, *pbase, *next;
-    gmx_ana_index_t    gp, g;
-
-    /* Exit immediately if pc should not have a base. */
-    if (!can_use_base(pc))
-    {
-        return;
-    }
-
-    gmx_ana_index_set(&gp, pc->b.nra, pc->b.a, NULL, 0);
-    gmx_ana_index_clear(&g);
-    gmx_ana_index_reserve(&g, pc->b.nra);
-    pbase = pc;
-    base = pc->coll->first;
-    while (base)
-    {
-        /* Save the next calculation so that we can safely delete base */
-        next = base->next;
-        /* Skip pc, calculations that already have a base (we should match the
-         * base instead), as well as calculations that should not have a base.
-         * If the above conditions are met, check whether we should do a
-         * merge.
-         */
-        if (base != pc && !base->sbase && can_use_base(base)
-            && should_merge(pbase, base, &gp, &g))
-        {
-            /* Check whether this is the first base found */
-            if (pbase == pc)
-            {
-                /* Create a real base if one is not present */
-                if (!base->p)
-                {
-                    pbase = create_simple_base(base);
-                }
-                else
-                {
-                    pbase = base;
-                }
-                /* Make it a base for pc as well */
-                merge_to_base(pbase, pc);
-                pc->sbase = pbase;
-                pbase->refcount++;
-            }
-            else /* This was not the first base */
-            {
-                if (!base->p)
-                {
-                    /* If it is not a real base, just make the new base as
-                     * the base for it as well. */
-                    merge_to_base(pbase, base);
-                    base->sbase = pbase;
-                    pbase->refcount++;
-                }
-                else
-                {
-                    /* If base is a real base, merge it with the new base
-                     * and delete it. */
-                    merge_bases(pbase, base);
-                }
-            }
-            gmx_ana_index_set(&gp, pbase->b.nra, pbase->b.a, NULL, 0);
-            gmx_ana_index_reserve(&g, pc->b.nra);
-        }
-        /* Proceed to the next unchecked calculation */
-        base = next;
-    }
-
-    gmx_ana_index_deinit(&g);
-
-    /* If no base was found, create one if one is required */
-    if (!pc->sbase && (pc->flags & POS_DYNAMIC)
-        && (pc->flags & (POS_COMPLMAX | POS_COMPLWHOLE)))
-    {
-        create_simple_base(pc);
-    }
-}
-
-/*!
- * \param[out] pcp   Position calculation data structure pointer to initialize.
- * \param[in,out] pcc   Position calculation collection.
- * \param[in]  type  Type of calculation.
- * \param[in]  flags Flags for setting calculation options
- *   (see \ref poscalc_flags "documentation of the flags").
- * \returns    0 on success.
- */
-int
-gmx_ana_poscalc_create(gmx_ana_poscalc_t **pcp, gmx_ana_poscalc_coll_t *pcc,
-                       e_poscalc_t type, int flags)
-{
-    gmx_ana_poscalc_t *pc;
-
-    snew(pc, 1);
-    pc->type     = type;
-    pc->itype    = index_type_for_poscalc(type);
-    gmx_ana_poscalc_set_flags(pc, flags);
-    pc->refcount = 1;
-    pc->coll     = pcc;
-    insert_poscalc(pc, NULL);
-    *pcp = pc;
-    return 0;
-}
-
-/*!
- * \param[out] pcp   Position calculation data structure pointer to initialize.
- * \param[in,out] pcc   Position calculation collection.
- * \param[in]  post  One of the strings acceptable for
- *   gmx_ana_poscalc_type_from_enum().
- * \param[in]  flags Flags for setting calculation options
- *   (see \ref poscalc_flags "documentation of the flags").
- * \returns    0 on success, a non-zero error value on error.
- *
- * This is a convenience wrapper for gmx_ana_poscalc_create().
- * \p flags sets the default calculation options if not overridden by \p post;
- * see gmx_ana_poscalc_type_from_enum().
- *
- * \see gmx_ana_poscalc_create(), gmx_ana_poscalc_type_from_enum()
- */
-int
-gmx_ana_poscalc_create_enum(gmx_ana_poscalc_t **pcp, gmx_ana_poscalc_coll_t *pcc,
-                            const char *post, int flags)
-{
-    e_poscalc_t  type;
-    int          cflags;
-    int          rc;
-
-    cflags = flags;
-    rc = gmx_ana_poscalc_type_from_enum(post, &type, &cflags);
-    if (rc != 0)
-    {
-        *pcp = NULL;
-        return rc;
-    }
-    return gmx_ana_poscalc_create(pcp, pcc, type, cflags);
-}
-
-/*!
- * \param[in,out] pc    Position calculation data structure.
- * \param[in]     flags New flags.
- *
- * \p flags are added to the old flags.
- * If calculation type is \ref POS_ATOM, \ref POS_MASS is automatically
- * cleared.
- * If both \ref POS_DYNAMIC and \ref POS_MASKONLY are provided,
- * \ref POS_DYNAMIC is cleared.
- * If calculation type is not \ref POS_RES or \ref POS_MOL,
- * \ref POS_COMPLMAX and \ref POS_COMPLWHOLE are automatically cleared.
- */
-void
-gmx_ana_poscalc_set_flags(gmx_ana_poscalc_t *pc, int flags)
-{
-    if (pc->type == POS_ATOM)
-    {
-        flags &= ~POS_MASS;
-    }
-    if (flags & POS_MASKONLY)
-    {
-        flags &= ~POS_DYNAMIC;
-    }
-    if (pc->type != POS_RES && pc->type != POS_MOL)
-    {
-        flags &= ~(POS_COMPLMAX | POS_COMPLWHOLE);
-    }
-    pc->flags |= flags;
-}
-
-/*!
- * \param[in,out] pc  Position calculation data structure.
- * \param[in]     g   Maximum index group for the calculation.
- *
- * Subsequent calls to gmx_ana_poscalc_update() should use only subsets of
- * \p g for evaluation.
- *
- * The topology should have been set for the collection of which \p pc is
- * a member.
- */
-void
-gmx_ana_poscalc_set_maxindex(gmx_ana_poscalc_t *pc, gmx_ana_index_t *g)
-{
-    set_poscalc_maxindex(pc, g, FALSE);
-    setup_base(pc);
-}
-
-/*!
- * \param[in]  pc  Position calculation data structure.
- * \param[out] p   Output positions.
- *
- * Calls to gmx_ana_poscalc_update() using \p pc should use only positions
- * initialized with this function.
- * The \c p->g pointer is initialized to point to an internal group that
- * contains the maximum index group set with gmx_ana_poscalc_set_maxindex().
- */
-void
-gmx_ana_poscalc_init_pos(gmx_ana_poscalc_t *pc, gmx_ana_pos_t *p)
-{
-    gmx_ana_indexmap_init(&p->m, &pc->gmax, pc->coll->top, pc->itype);
-    if (!(pc->flags & POS_DYNAMIC))
-    {
-        gmx_ana_indexmap_set_static(&p->m, &pc->b);
-    }
-    gmx_ana_pos_reserve(p, p->m.nr, 0);
-    if (pc->flags & POS_VELOCITIES)
-    {
-        gmx_ana_pos_reserve_velocities(p);
-    }
-    if (pc->flags & POS_FORCES)
-    {
-        gmx_ana_pos_reserve_forces(p);
-    }
-    gmx_ana_pos_set_nr(p, p->m.nr);
-    gmx_ana_pos_set_evalgrp(p, &pc->gmax);
-}
-
-/*!
- * \param  pc  Position calculation data to be freed.
- *
- * The \p pc pointer is invalid after the call.
- */
-void
-gmx_ana_poscalc_free(gmx_ana_poscalc_t *pc)
-{
-    if (!pc)
-    {
-        return;
-    }
-
-    pc->refcount--;
-    if (pc->refcount > 0)
-    {
-        return;
-    }
-
-    remove_poscalc(pc);
-    if (pc->b.nalloc_index > 0)
-    {
-        sfree(pc->b.index);
-    }
-    if (pc->b.nalloc_a > 0)
-    {
-        sfree(pc->b.a);
-    }
-    if (pc->flags & POS_COMPLWHOLE)
-    {
-        gmx_ana_index_deinit(&pc->gmax);
-    }
-    if (pc->p)
-    {
-        gmx_ana_pos_free(pc->p);
-    }
-    if (pc->sbase)
-    {
-        gmx_ana_poscalc_free(pc->sbase);
-        sfree(pc->baseid);
-    }
-    sfree(pc);
-}
-
-/*!
- * \param[in] pc  Position calculation data to query.
- * \returns   TRUE if \p pc requires topology for initialization and/or
- *   evaluation, FALSE otherwise.
- */
-gmx_bool
-gmx_ana_poscalc_requires_top(gmx_ana_poscalc_t *pc)
-{
-    if ((pc->flags & POS_MASS) || pc->type == POS_RES || pc->type == POS_MOL)
-    {
-        return TRUE;
-    }
-    return FALSE;
-}
-
-/*!
- * \param[in,out] pcc Position calculation collection to initialize.
- *
- * This function does some final initialization of the data structures in the
- * collection to prepare them for evaluation.
- * After this function has been called, it is no longer possible to add new
- * calculations to the collection.
- *
- * This function is automatically called by gmx_ana_poscalc_init_frame() 
- * if not called by the user earlier.
- * Multiple calls to the function are ignored.
- */
-void
-gmx_ana_poscalc_init_eval(gmx_ana_poscalc_coll_t *pcc)
-{
-    gmx_ana_poscalc_t      *pc;
-    int                     bi, bj;
-
-    if (pcc->bInit)
-    {
-        return;
-    }
-    pc = pcc->first;
-    while (pc)
-    {
-        /* Initialize position storage for base calculations */
-        if (pc->p)
-        {
-            gmx_ana_poscalc_init_pos(pc, pc->p);
-        }
-        /* Construct the mapping of the base positions */
-        if (pc->sbase)
-        {
-            snew(pc->baseid, pc->b.nr);
-            for (bi = bj = 0; bi < pc->b.nr; ++bi, ++bj)
-            {
-                while (pc->sbase->b.a[pc->sbase->b.index[bj]] != pc->b.a[pc->b.index[bi]])
-                {
-                    ++bj;
-                }
-                pc->baseid[bi] = bj;
-            }
-        }
-        /* Free the block data for dynamic calculations */
-        if (pc->flags & POS_DYNAMIC)
-        {
-            if (pc->b.nalloc_index > 0)
-            {
-                sfree(pc->b.index);
-                pc->b.nalloc_index = 0;
-            }
-            if (pc->b.nalloc_a > 0)
-            {
-                sfree(pc->b.a);
-                pc->b.nalloc_a = 0;
-            }
-        }
-        pc = pc->next;
-    }
-    pcc->bInit = TRUE;
-}
-
-/*!
- * \param[in,out] pcc Position calculation collection to initialize.
- *
- * Clears the evaluation flag for all calculations.
- * Should be called for each frame before calling gmx_ana_poscalc_update().
- *
- * This function is automatically called by gmx_ana_do() for each
- * frame, and should not be called by the user unless gmx_ana_do() is
- * not being used.
- *
- * This function calls gmx_ana_poscalc_init_eval() automatically if it has
- * not been called earlier.
- */
-void
-gmx_ana_poscalc_init_frame(gmx_ana_poscalc_coll_t *pcc)
-{
-    gmx_ana_poscalc_t      *pc;
-
-    if (!pcc->bInit)
-    {
-        gmx_ana_poscalc_init_eval(pcc);
-    }
-    /* Clear the evaluation flags */
-    pc = pcc->first;
-    while (pc)
-    {
-        pc->bEval = FALSE;
-        pc = pc->next;
-    }
-}
-
-/*!
- * \param[in]     pc   Position calculation data.
- * \param[in,out] p    Output positions, initialized previously with
- *   gmx_ana_poscalc_init_pos() using \p pc.
- * \param[in]     g    Index group to use for the update.
- * \param[in]     fr   Current frame.
- * \param[in]     pbc  PBC data, or NULL if no PBC should be used.
- *
- * gmx_ana_poscalc_init_frame() should be called for each frame before calling
- * this function.
- */
-void
-gmx_ana_poscalc_update(gmx_ana_poscalc_t *pc, gmx_ana_pos_t *p,
-                       gmx_ana_index_t *g, t_trxframe *fr, t_pbc *pbc)
-{
-    int  i, j, bi, bj;
-    
-    if (pc->bEval == TRUE && !(pc->flags & POS_MASKONLY))
-    {
-        return;
-    }
-    if (pc->sbase)
-    {
-        gmx_ana_poscalc_update(pc->sbase, NULL, NULL, fr, pbc);
-    }
-    if (!p)
-    {
-        p = pc->p;
-    }
-    if (!g)
-    {
-        g = &pc->gmax;
-    }
-    gmx_ana_pos_set_evalgrp(p, g);
-
-    /* Update the index map */
-    if (pc->flags & POS_DYNAMIC)
-    {
-        gmx_ana_indexmap_update(&p->m, g, FALSE);
-        p->nr = p->m.nr;
-    }
-    else if (pc->flags & POS_MASKONLY)
-    {
-        gmx_ana_indexmap_update(&p->m, g, TRUE);
-        if (pc->bEval)
-            return;
-    }
-    if (!(pc->flags & POS_DYNAMIC))
-    {
-        pc->bEval = TRUE;
-    }
-
-    /* Evaluate the positions */
-    if (pc->sbase)
-    {
-        /* TODO: It might be faster to evaluate the positions within this
-         * loop instead of in the beginning. */
-        if (pc->flags & POS_DYNAMIC)
-        {
-            for (bi = 0; bi < p->nr; ++bi)
-            {
-                bj = pc->baseid[p->m.refid[bi]];
-                copy_rvec(pc->sbase->p->x[bj], p->x[bi]);
-            }
-            if (p->v)
-            {
-                for (bi = 0; bi < p->nr; ++bi)
-                {
-                    bj = pc->baseid[p->m.refid[bi]];
-                    copy_rvec(pc->sbase->p->v[bj], p->v[bi]);
-                }
-            }
-            if (p->f)
-            {
-                for (bi = 0; bi < p->nr; ++bi)
-                {
-                    bj = pc->baseid[p->m.refid[bi]];
-                    copy_rvec(pc->sbase->p->f[bj], p->f[bi]);
-                }
-            }
-        }
-        else
-        {
-            for (bi = 0; bi < p->nr; ++bi)
-            {
-                bj = pc->baseid[bi];
-                copy_rvec(pc->sbase->p->x[bj], p->x[bi]);
-            }
-            if (p->v)
-            {
-                for (bi = 0; bi < p->nr; ++bi)
-                {
-                    bj = pc->baseid[bi];
-                    copy_rvec(pc->sbase->p->v[bj], p->v[bi]);
-                }
-            }
-            if (p->f)
-            {
-                for (bi = 0; bi < p->nr; ++bi)
-                {
-                    bj = pc->baseid[bi];
-                    copy_rvec(pc->sbase->p->f[bj], p->f[bi]);
-                }
-            }
-        }
-    }
-    else /* pc->sbase is NULL */
-    {
-        if (pc->flags & POS_DYNAMIC)
-        {
-            pc->b.nr    = p->m.mapb.nr;
-            pc->b.index = p->m.mapb.index;
-            pc->b.nra   = g->isize;
-            pc->b.a     = g->index;
-        }
-        if (p->v && !fr->bV)
-        {
-            for (i = 0; i < pc->b.nra; ++i)
-            {
-                clear_rvec(p->v[i]);
-            }
-        }
-        if (p->f && !fr->bF)
-        {
-            for (i = 0; i < pc->b.nra; ++i)
-            {
-                clear_rvec(p->f[i]);
-            }
-        }
-        /* Here, we assume that the topology has been properly initialized,
-         * and do not check the return values of gmx_calc_comg*(). */
-        switch (pc->type)
-        {
-        case POS_ATOM:
-            for (i = 0; i < pc->b.nra; ++i)
-            {
-                copy_rvec(fr->x[pc->b.a[i]], p->x[i]);
-            }
-            if (p->v && fr->bV)
-            {
-                for (i = 0; i < pc->b.nra; ++i)
-                {
-                    copy_rvec(fr->v[pc->b.a[i]], p->v[i]);
-                }
-            }
-            if (p->f && fr->bF)
-            {
-                for (i = 0; i < pc->b.nra; ++i)
-                {
-                    copy_rvec(fr->f[pc->b.a[i]], p->f[i]);
-                }
-            }
-            break;
-        case POS_ALL:
-            gmx_calc_comg(pc->coll->top, fr->x, pc->b.nra, pc->b.a,
-                          pc->flags & POS_MASS, p->x[0]);
-            if (p->v && fr->bV)
-            {
-                gmx_calc_comg(pc->coll->top, fr->v, pc->b.nra, pc->b.a,
-                              pc->flags & POS_MASS, p->v[0]);
-            }
-            if (p->f && fr->bF)
-            {
-                gmx_calc_comg_f(pc->coll->top, fr->f, pc->b.nra, pc->b.a,
-                                pc->flags & POS_MASS, p->f[0]);
-            }
-            break;
-        case POS_ALL_PBC:
-            gmx_calc_comg_pbc(pc->coll->top, fr->x, pbc, pc->b.nra, pc->b.a,
-                              pc->flags & POS_MASS, p->x[0]);
-            if (p->v && fr->bV)
-            {
-                gmx_calc_comg(pc->coll->top, fr->v, pc->b.nra, pc->b.a,
-                              pc->flags & POS_MASS, p->v[0]);
-            }
-            if (p->f && fr->bF)
-            {
-                gmx_calc_comg_f(pc->coll->top, fr->f, pc->b.nra, pc->b.a,
-                                pc->flags & POS_MASS, p->f[0]);
-            }
-            break;
-        default:
-            gmx_calc_comg_blocka(pc->coll->top, fr->x, &pc->b,
-                                 pc->flags & POS_MASS, p->x);
-            if (p->v && fr->bV)
-            {
-                gmx_calc_comg_blocka(pc->coll->top, fr->v, &pc->b,
-                                     pc->flags & POS_MASS, p->v);
-            }
-            if (p->f && fr->bF)
-            {
-                gmx_calc_comg_blocka(pc->coll->top, fr->f, &pc->b,
-                                     pc->flags & POS_MASS, p->f);
-            }
-            break;
-        }
-    }
-}
diff --git a/src/gmxlib/trajana/position.c b/src/gmxlib/trajana/position.c
deleted file mode 100644 (file)
index 4edcb46..0000000
+++ /dev/null
@@ -1,426 +0,0 @@
-/*
- *
- *                This source code is part of
- *
- *                 G   R   O   M   A   C   S
- *
- *          GROningen MAchine for Chemical Simulations
- *
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
- * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
- * Copyright (c) 2001-2009, The GROMACS development team,
- * check out http://www.gromacs.org for more information.
-
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * If you want to redistribute modifications, please consider that
- * scientific software is very special. Version control is crucial -
- * bugs must be traceable. We will be happy to consider code for
- * inclusion in the official distribution, but derived work must not
- * be called official GROMACS. Details are found in the README & COPYING
- * files - if they are missing, get the official version at www.gromacs.org.
- *
- * To help us fund GROMACS development, we humbly ask that you cite
- * the papers on the package - you can find them in the top README file.
- *
- * For more info, check our website at http://www.gromacs.org
- */
-/*! \internal \file
- * \brief Implementation of functions in position.h.
- */
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <assert.h>
-#include <string.h>
-
-#include <smalloc.h>
-#include <typedefs.h>
-#include <vec.h>
-
-#include <indexutil.h>
-#include <position.h>
-
-/*!
- * \param[out] pos      Output structure.
- *
- * Any contents of \p pos are discarded without freeing.
- */
-void
-gmx_ana_pos_clear(gmx_ana_pos_t *pos)
-{
-    pos->nr = 0;
-    pos->x  = NULL;
-    pos->v  = NULL;
-    pos->f  = NULL;
-    gmx_ana_indexmap_clear(&pos->m);
-    pos->g  = NULL;
-    pos->nalloc_x = 0;
-}
-
-/*!
- * \param[in,out] pos   Position data structure.
- * \param[in]     n     Maximum number of positions.
- * \param[in]     isize Maximum number of atoms.
- *
- * Ensures that enough memory is allocated in \p pos to calculate \p n
- * positions from \p isize atoms.
- */
-void
-gmx_ana_pos_reserve(gmx_ana_pos_t *pos, int n, int isize)
-{
-    if (pos->nalloc_x < n)
-    {
-        pos->nalloc_x = n;
-        srenew(pos->x, n);
-        if (pos->v)
-        {
-            srenew(pos->v, n);
-        }
-        if (pos->f)
-        {
-            srenew(pos->f, n);
-        }
-    }
-    if (isize > 0)
-    {
-        gmx_ana_indexmap_reserve(&pos->m, n, isize);
-    }
-}
-
-/*!
- * \param[in,out] pos   Position data structure.
- *
- * Currently, this function can only be called after gmx_ana_pos_reserve()
- * has been called at least once with a \p n > 0.
- */
-void
-gmx_ana_pos_reserve_velocities(gmx_ana_pos_t *pos)
-{
-    assert(pos->nalloc_x > 0);
-    if (!pos->v)
-    {
-        snew(pos->v, pos->nalloc_x);
-    }
-}
-
-/*!
- * \param[in,out] pos   Position data structure.
- *
- * Currently, this function can only be called after gmx_ana_pos_reserve()
- * has been called at least once with a \p n > 0.
- */
-void
-gmx_ana_pos_reserve_forces(gmx_ana_pos_t *pos)
-{
-    assert(pos->nalloc_x > 0);
-    if (!pos->f)
-    {
-        snew(pos->f, pos->nalloc_x);
-    }
-}
-
-/*!
- * \param[out]    pos  Position data structure to initialize.
- * \param[in]     x    Position vector to use.
- */
-void
-gmx_ana_pos_init_const(gmx_ana_pos_t *pos, rvec x)
-{
-    gmx_ana_pos_clear(pos);
-    pos->nr = 1;
-    snew(pos->x, 1);
-    snew(pos->v, 1);
-    snew(pos->f, 1);
-    pos->nalloc_x = 1;
-    copy_rvec(x, pos->x[0]);
-    clear_rvec(pos->v[0]);
-    clear_rvec(pos->f[0]);
-    gmx_ana_indexmap_init(&pos->m, NULL, NULL, INDEX_UNKNOWN);
-}
-
-/*!
- * \param[in,out] pos   Position data structure.
- *
- * Frees any memory allocated within \p pos.
- * The pointer \p pos itself is not freed.
- *
- * \see gmx_ana_pos_free()
- */
-void
-gmx_ana_pos_deinit(gmx_ana_pos_t *pos)
-{
-    pos->nr = 0;
-    sfree(pos->x); pos->x = NULL;
-    sfree(pos->v); pos->v = NULL;
-    sfree(pos->f); pos->f = NULL;
-    pos->nalloc_x = 0;
-    gmx_ana_indexmap_deinit(&pos->m);
-}
-
-/*!
- * \param[in,out] pos   Position data structure.
- *
- * Frees any memory allocated for \p pos.
- * The pointer \p pos is also freed, and is invalid after the call.
- *
- * \see gmx_ana_pos_deinit()
- */
-void
-gmx_ana_pos_free(gmx_ana_pos_t *pos)
-{
-    gmx_ana_pos_deinit(pos);
-    sfree(pos);
-}
-
-/*!
- * \param[in,out] dest   Destination positions.
- * \param[in]     src    Source positions.
- * \param[in]     bFirst If TRUE, memory is allocated for \p dest and a full
- *   copy is made; otherwise, only variable parts are copied, and no memory
- *   is allocated.
- *
- * \p dest should have been initialized somehow (calloc() is enough).
- */
-void
-gmx_ana_pos_copy(gmx_ana_pos_t *dest, gmx_ana_pos_t *src, gmx_bool bFirst)
-{
-    if (bFirst)
-    {
-        gmx_ana_pos_reserve(dest, src->nr, 0);
-        if (src->v)
-        {
-            gmx_ana_pos_reserve_velocities(dest);
-        }
-        if (src->f)
-        {
-            gmx_ana_pos_reserve_forces(dest);
-        }
-    }
-    dest->nr = src->nr;
-    memcpy(dest->x, src->x, dest->nr*sizeof(*dest->x));
-    if (dest->v)
-    {
-        memcpy(dest->v, src->v, dest->nr*sizeof(*dest->v));
-    }
-    if (dest->f)
-    {
-        memcpy(dest->f, src->f, dest->nr*sizeof(*dest->f));
-    }
-    gmx_ana_indexmap_copy(&dest->m, &src->m, bFirst);
-    dest->g = src->g;
-}
-
-/*!
- * \param[in,out] pos  Position data structure.
- * \param[in]     nr   Number of positions.
- */
-void
-gmx_ana_pos_set_nr(gmx_ana_pos_t *pos, int nr)
-{
-    pos->nr = nr;
-}
-
-/*!
- * \param[in,out] pos  Position data structure.
- * \param         g    Evaluation group.
- *
- * The old group, if any, is discarded.
- * Note that only a pointer to \p g is stored; it is the responsibility of
- * the caller to ensure that \p g is not freed while it can be accessed
- * through \p pos.
- */
-void
-gmx_ana_pos_set_evalgrp(gmx_ana_pos_t *pos, gmx_ana_index_t *g)
-{
-    pos->g = g;
-}
-
-/*!
- * \param[in,out] pos   Position data structure.
- *
- * Sets the number of positions to 0.
- */
-void
-gmx_ana_pos_empty_init(gmx_ana_pos_t *pos)
-{
-    pos->nr = 0;
-    pos->m.nr = 0;
-    pos->m.mapb.nr = 0;
-    pos->m.b.nr = 0;
-    pos->m.b.nra = 0;
-    /* This should not really be necessary, but do it for safety... */
-    pos->m.mapb.index[0] = 0;
-    pos->m.b.index[0] = 0;
-    /* This function should only be used to construct all the possible
-     * positions, so the result should always be static. */
-    pos->m.bStatic = TRUE;
-    pos->m.bMapStatic = TRUE;
-}
-
-/*!
- * \param[in,out] pos   Position data structure.
- *
- * Sets the number of positions to 0.
- */
-void
-gmx_ana_pos_empty(gmx_ana_pos_t *pos)
-{
-    pos->nr = 0;
-    pos->m.nr = 0;
-    pos->m.mapb.nr = 0;
-    /* This should not really be necessary, but do it for safety... */
-    pos->m.mapb.index[0] = 0;
-    /* We set the flags to TRUE, although really in the empty state they
-     * should be FALSE. This makes it possible to update the flags in
-     * gmx_ana_pos_append(), and just make a simple check in
-     * gmx_ana_pos_append_finish(). */
-    pos->m.bStatic = TRUE;
-    pos->m.bMapStatic = TRUE;
-}
-
-/*!
- * \param[in,out] dest  Data structure to which the new position is appended.
- * \param[in,out] g     Data structure to which the new atoms are appended.
- * \param[in]     src   Data structure from which the position is copied.
- * \param[in]     i     Index in \p from to copy.
- */
-void
-gmx_ana_pos_append_init(gmx_ana_pos_t *dest, gmx_ana_index_t *g,
-                        gmx_ana_pos_t *src, int i)
-{
-    int  j, k;
-
-    j = dest->nr;
-    copy_rvec(src->x[i], dest->x[j]);
-    if (dest->v)
-    {
-        if (src->v)
-        {
-            copy_rvec(src->v[i], dest->v[j]);
-        }
-        else
-        {
-            clear_rvec(dest->v[j]);
-        }
-    }
-    if (dest->f)
-    {
-        if (src->f)
-        {
-            copy_rvec(src->f[i], dest->f[j]);
-        }
-        else
-        {
-            clear_rvec(dest->f[j]);
-        }
-    }
-    dest->m.refid[j] = j;
-    dest->m.mapid[j] = src->m.mapid[i];
-    dest->m.orgid[j] = src->m.orgid[i];
-    for (k = src->m.mapb.index[i]; k < src->m.mapb.index[i+1]; ++k)
-    {
-        g->index[g->isize++]         = src->g->index[k];
-        dest->m.b.a[dest->m.b.nra++] = src->m.b.a[k];
-    }
-    dest->m.mapb.index[j+1] = g->isize;
-    dest->m.b.index[j+1]    = g->isize;
-    dest->nr++;
-    dest->m.nr = dest->nr;
-    dest->m.mapb.nr = dest->nr;
-    dest->m.b.nr = dest->nr;
-}
-
-/*!
- * \param[in,out] dest  Data structure to which the new position is appended
- *      (can be NULL, in which case only \p g is updated).
- * \param[in,out] g     Data structure to which the new atoms are appended.
- * \param[in]     src   Data structure from which the position is copied.
- * \param[in]     i     Index in \p src to copy.
- * \param[in]     refid Reference ID in \p out
- *   (all negative values are treated as -1).
- *
- * If \p dest is NULL, the value of \p refid is not used.
- */
-void
-gmx_ana_pos_append(gmx_ana_pos_t *dest, gmx_ana_index_t *g,
-                   gmx_ana_pos_t *src, int i, int refid)
-{
-    int  j, k;
-
-    for (k = src->m.mapb.index[i]; k < src->m.mapb.index[i+1]; ++k)
-    {
-        g->index[g->isize++] = src->g->index[k];
-    }
-    if (dest)
-    {
-        j = dest->nr;
-        if (dest->v)
-        {
-            if (src->v)
-            {
-                copy_rvec(src->v[i], dest->v[j]);
-            }
-            else
-            {
-                clear_rvec(dest->v[j]);
-            }
-        }
-        if (dest->f)
-        {
-            if (src->f)
-            {
-                copy_rvec(src->f[i], dest->f[j]);
-            }
-            else
-            {
-                clear_rvec(dest->f[j]);
-            }
-        }
-        copy_rvec(src->x[i], dest->x[j]);
-        if (refid < 0)
-        {
-            dest->m.refid[j] = -1;
-            dest->m.bStatic = FALSE;
-            /* If we are using masks, there is no need to alter the
-             * mapid field. */
-        }
-        else
-        {
-            if (refid != j)
-            {
-                dest->m.bStatic = FALSE;
-                dest->m.bMapStatic = FALSE;
-            }
-            dest->m.refid[j] = refid;
-            /* Use the original IDs from the output structure to correctly
-             * handle user customization. */
-            dest->m.mapid[j] = dest->m.orgid[refid];
-        }
-        dest->m.mapb.index[j+1] = g->isize;
-        dest->nr++;
-        dest->m.nr = dest->nr;
-        dest->m.mapb.nr = dest->nr;
-    }
-}
-
-/*!
- * \param[in,out] pos   Position data structure.
- *
- * After gmx_ana_pos_empty(), internal state of the position data structure
- * is not consistent before this function is called. This function should be
- * called after any gmx_ana_pos_append() calls have been made.
- */
-void
-gmx_ana_pos_append_finish(gmx_ana_pos_t *pos)
-{
-    if (pos->m.nr != pos->m.b.nr)
-    {
-        pos->m.bStatic = FALSE;
-        pos->m.bMapStatic = FALSE;
-    }
-}
diff --git a/src/gmxlib/trajana/trajana.c b/src/gmxlib/trajana/trajana.c
deleted file mode 100644 (file)
index 4dde161..0000000
+++ /dev/null
@@ -1,1701 +0,0 @@
-/*
- *
- *                This source code is part of
- *
- *                 G   R   O   M   A   C   S
- *
- *          GROningen MAchine for Chemical Simulations
- *
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
- * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
- * Copyright (c) 2001-2009, The GROMACS development team,
- * check out http://www.gromacs.org for more information.
-
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * If you want to redistribute modifications, please consider that
- * scientific software is very special. Version control is crucial -
- * bugs must be traceable. We will be happy to consider code for
- * inclusion in the official distribution, but derived work must not
- * be called official GROMACS. Details are found in the README & COPYING
- * files - if they are missing, get the official version at www.gromacs.org.
- *
- * To help us fund GROMACS development, we humbly ask that you cite
- * the papers on the package - you can find them in the top README file.
- *
- * For more info, check our website at http://www.gromacs.org
- */
-/*! \page libtrajana Library for trajectory analysis
- *
- * This is a trajectory analysis library for Gromacs.
- *
- * The main features of the library are:
- *  - \subpage selengine "Flexible handling of textual selections" that can
- *    also be dynamic, i.e., depend of the trajectory frame through
- *    positions of the particles.
- *    Selections evaluate directly to positions, which can then be used in
- *    the analysis program.
- *  - \subpage selmethods "Custom selection keywords" can also be easily
- *    implemented, also on a tool-by-tool basis.
- *  - Efficient \subpage nbsearch "neighborhood searching"
- *    (currently not very efficient...).
- *  - \subpage displacements "On-the-fly calculation of displacement vectors"
- *    during a single pass over the trajectory.
- *  - \subpage histograms "Calculation of histograms" with error estimates
- *    through block averaging.
- *
- * The functions also automate several things common to most analysis programs
- * such as making molecules whole if required, reading input files, and
- * setting up index groups for analysis.
- * The library unifies the structure of analysis programs (at least a bit)
- * and makes it easier to add common functionality to all analysis programs.
- *
- *
- * \section main_using Using the library
- *
- * There is a \ref share/template/template.c "template" for writing
- * analysis programs, the documentation for it and links from there should
- * help getting started.
- *
- *
- * \internal
- * \section libtrajana_impl Implementation details
- *
- * Some internal implementation details of the library are documented on
- * separate pages:
- *  - \subpage poscalcengine
- *  - \subpage selparser
- *  - \subpage selcompiler
- */
-/*! \page selengine Text-based selections
- *
- * \section selection_basics Basics
- *
- * Selections are enabled automatically for an analysis program that uses
- * the library. The selection syntax is described in an online help that is
- * accessible from all tools that use the library.
- * By default, dynamic selections are allowed, and the user can freely
- * choose whether to analyze atoms or centers of mass/geometry of
- * residues/molecules.
- * These defaults, as well as some others, can be changed by specifying
- * flags for gmx_ana_traj_create().
- *
- * The analysis program can then access the selected positions for each frame
- * through a \p gmx_ana_selection_t array that is passed to the frame
- * analysis function (see gmx_analysisfunc()).
- * As long as the analysis program is written such that it does not assume
- * that the number of positions or the atoms in the groups groups remain
- * constant, any kind of selection expression can be used.
- *
- * Some analysis programs may require a special structure for the index groups
- * (e.g., \c g_angle requires the index group to be made of groups of three or
- * four atoms).
- * For such programs, it is up to the user to provide a proper selection
- * expression that always returns such positions.
- * Such analysis program can define \ref ANA_REQUIRE_WHOLE to make the
- * default behavior appropriate for the most common uses where the groups
- * should consist of atoms within a single residue/molecule.
- *
- * \section selection_methods Implementing new keywords
- *
- * New selection keywords can be easily implemented, either directly into the
- * library or as part of analysis programs (the latter may be useful for
- * testing or methods very specific to some analysis).
- * For both cases, you should first create a \c gmx_ana_selmethod_t structure
- * and fill it with the necessary information.
- * Details can be found on a separate page: \ref selmethods.
- */
-/*! \internal \file
- * \brief Implementation of functions in trajana.h.
- */
-/*! \internal \dir src/gmxlib/trajana
- * \brief Source code for common trajectory analysis functions.
- *
- * Selection handling is found in \ref src/gmxlib/selection.
- */
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <string.h>
-
-#include <filenm.h>
-#include <futil.h>
-#include <macros.h>
-#include <pbc.h>
-#include <rmpbc.h>
-#include <smalloc.h>
-#include <statutil.h>
-#include <typedefs.h>
-#include <tpxio.h>
-#include <vec.h>
-
-#include <poscalc.h>
-#include <selection.h>
-#include <selmethod.h>
-#include <trajana.h>
-
-/*! \internal \brief
- * Data structure for trajectory analysis tools.
- */
-struct gmx_ana_traj_t
-{
-    /*! \brief
-     * Flags that alter the behavior of the analysis library.
-     *
-     * This variable stores the flags passed to gmx_ana_traj_create() for use
-     * in the other functions.
-     */
-    unsigned long             flags;
-    /** Number of input reference groups. */
-    int                       nrefgrps;
-    /*! \brief
-     * Number of input analysis groups.
-     *
-     * This is the number of groups in addition to the reference groups
-     * that are required.
-     * If -1, any number of groups (at least one) is acceptable.
-     */
-    int                       nanagrps;
-    /*! \brief
-     * Flags for init_first_frame() to specify what to read from the
-     * trajectory.
-     */
-    int                       frflags;
-    /** TRUE if molecules should be made whole for each frame. */
-    gmx_bool                      bRmPBC;
-    /*! \brief
-     * TRUE if periodic boundary conditions should be used.
-     *
-     * If the flag is FALSE, the \p pbc pointer passed to gmx_analysisfunc()
-     * is NULL.
-     */
-    gmx_bool                      bPBC;
-
-    /** Name of the trajectory file (NULL if not provided). */
-    char                     *trjfile;
-    /** Name of the topology file (NULL if no topology loaded). */
-    char                     *topfile;
-    /** Non-NULL name of the topology file. */
-    char                     *topfile_notnull;
-    /** Name of the index file (NULL if no index file provided). */
-    char                     *ndxfile;
-    /** Name of the selection file (NULL if no file provided). */
-    char                     *selfile;
-    /** The selection string (NULL if not provided). */
-    char                     *selection;
-
-    /** The topology structure, or \p NULL if no topology loaded. */
-    t_topology               *top;
-    /** TRUE if full tpx file was loaded, FALSE otherwise. */
-    gmx_bool                      bTop;
-    /** Coordinates from the topology (see \p bTopX). */
-    rvec                     *xtop;
-    /** The box loaded from the topology file. */
-    matrix                    boxtop;
-    /** The ePBC field loaded from the topology file. */
-    int                       ePBC;
-
-    /** The current frame, or \p NULL if no frame loaded yet. */
-    t_trxframe               *fr;
-    /** Used to store the status variable from read_first_frame(). */
-    t_trxstatus              *status;
-    /** The number of frames read. */
-    int                       nframes;
-
-    /** Number of elements in the \p sel array. */
-    int                       ngrps;
-    /*! \brief
-     * Array of selection information (one element for each index group).
-     *
-     * After the call to gmx_ana_init_selections(), this array contains
-     * information about the selections the user has provided.
-     * The array contains \p ngrps elements;
-     * if \p nanagrps was -1, the number may vary.
-     * See \c gmx_ana_selection_t for details of the contents.
-     *
-     * The largest possible index groups for dynamic selections can be found
-     * in \p sel[i]->g, i.e., the program can assume that any index group
-     * passed to gmx_analysisfunc() is a subset of the provided group.
-     * After gmx_ana_do(), the same groups can be used in post-processing.
-     */
-    gmx_ana_selection_t     **sel;
-    /** Array of names of the selections for convenience. */
-    char                    **grpnames;
-    /** Position calculation data. */
-    gmx_ana_poscalc_coll_t   *pcc;
-    /** Selection data. */
-    gmx_ana_selcollection_t  *sc;
-
-    /** Data for statutil.c utilities. */
-    output_env_t              oenv;
-};
-
-/** Loads the topology. */
-static int load_topology(gmx_ana_traj_t *d, gmx_bool bReq);
-/** Loads the first frame and does some checks. */
-static int init_first_frame(gmx_ana_traj_t *d);
-
-static int add_fnmarg(int nfile, t_filenm *fnm, t_filenm *fnm_add)
-{
-    memcpy(&(fnm[nfile]), fnm_add, sizeof(*fnm_add));
-    return nfile + 1;
-}
-
-/* Copied from src/gmxlib/statutil.c */
-static int
-add_parg(int npargs, t_pargs *pa, t_pargs *pa_add)
-{
-    memcpy(&(pa[npargs]), pa_add, sizeof(*pa_add));
-    return npargs + 1;
-}
-
-/*!
- * \param[out] data  Trajectory analysis data structure poitner to initialize.
- * \param[in]  flags Combination of flags (see \ref analysis_flags).
- * \returns    0 on success.
- */
-int
-gmx_ana_traj_create(gmx_ana_traj_t **data, unsigned long flags)
-{
-    gmx_ana_traj_t     *d;
-    int                 rc;
-
-    snew(d, 1);
-
-    d->nrefgrps        = 0;
-    d->nanagrps        = 1;
-    d->frflags         = TRX_NEED_X;
-    d->bRmPBC          = TRUE;
-    d->bPBC            = TRUE;
-
-    d->trjfile         = NULL;
-    d->topfile         = NULL;
-    d->ndxfile         = NULL;
-    d->selfile         = NULL;
-    d->selection       = NULL;
-
-    d->top             = NULL;
-    d->bTop            = FALSE;
-    d->xtop            = NULL;
-    d->ePBC            = -1;
-    d->fr              = NULL;
-    d->nframes         = 0;
-
-    d->ngrps           = 0;
-    d->sel             = NULL;
-    d->grpnames        = NULL;
-
-    d->flags           = flags;
-    d->topfile_notnull = NULL;
-    rc = gmx_ana_poscalc_coll_create(&d->pcc);
-    if (rc != 0)
-    {
-        sfree(d);
-        *data = NULL;
-        return rc;
-    }
-    rc = gmx_ana_selcollection_create(&d->sc, d->pcc);
-    if (rc != 0)
-    {
-        gmx_ana_poscalc_coll_free(d->pcc);
-        sfree(d);
-        *data = NULL;
-        return rc;
-    }
-    d->status          = NULL;
-    d->oenv            = NULL;
-
-    *data              = d;
-    return 0;
-}
-
-/*!
- * \param   d  Trajectory analysis data to free.
- */
-void
-gmx_ana_traj_free(gmx_ana_traj_t *d)
-{
-    int                 i;
-
-    sfree(d->trjfile);
-    sfree(d->topfile);
-    sfree(d->topfile_notnull);
-    sfree(d->ndxfile);
-    sfree(d->selfile);
-    if (d->top)
-    {
-        done_top(d->top);
-        sfree(d->top);
-    }
-    if (d->fr)
-    {
-        /* Gromacs does not seem to have a function for freeing frame data */
-        sfree(d->fr->x);
-        sfree(d->fr->v);
-        sfree(d->fr->f);
-        sfree(d->fr);
-    }
-    sfree(d->xtop);
-    sfree(d->sel);
-    gmx_ana_selcollection_free(d->sc);
-    gmx_ana_poscalc_coll_free(d->pcc);
-    sfree(d->grpnames);
-    output_env_done(d->oenv);
-    sfree(d);
-}
-
-/*!
- * \param[in,out] d      Trajectory analysis data structure.
- * \param[in]     flags  Additional flags to set.
- * \returns       0 on success, a non-zero error code on error.
- *
- * Currently there are no checks whether the flags make sense or not.
- */
-int
-gmx_ana_add_flags(gmx_ana_traj_t *d, unsigned long flags)
-{
-    d->flags |= flags;
-    return 0;
-}
-
-/*!
- * \param[in,out] d      Trajectory analysis data structure.
- * \param[in]     bPBC   TRUE if periodic boundary conditions should be used.
- * \returns       0 on success.
- * 
- * If this function is called before parse_trjana_args(), it sets the default
- * for whether PBC are used in the analysis or not.
- * If \ref ANA_NOUSER_PBC is not set, a command-line option is provided for the
- * user to override the default value.
- * If called after parse_trjana_args(), it overrides the setting provided by
- * the user or an earlier call.
- *
- * If this function is not called, the default is to use PBC.
- *
- * If PBC are not used, the \p pbc pointer passed to gmx_analysisfunc()
- * is NULL.
- *
- * \see \ref ANA_NOUSER_PBC
- */
-int
-gmx_ana_set_pbc(gmx_ana_traj_t *d, gmx_bool bPBC)
-{
-    d->bPBC = bPBC;
-    return 0;
-}
-
-/*!
- * \param[in] d      Trajectory analysis data structure.
- * \returns   TRUE if periodic boundary conditions are set to be used.
- */
-gmx_bool
-gmx_ana_has_pbc(gmx_ana_traj_t *d)
-{
-    return d->bPBC;
-}
-
-/*!
- * \param[in,out] d      Trajectory analysis data structure.
- * \param[in]     bRmPBC TRUE if molecules should be made whole.
- * \returns       0 on success.
- * 
- * If this function is called before parse_trjana_args(), it sets the default
- * for whether molecules are made whole.
- * If \ref ANA_NOUSER_RMPBC is not set, a command-line option is provided for
- * the user to override the default value.
- * If called after parse_trjana_args(), it overrides the setting provided by
- * the user or an earlier call.
- *
- * If this function is not called, the default is to make molecules whole.
- *
- * The main use of this function is to call it with FALSE if your analysis
- * program does not require whole molecules as this can increase the
- * performance.
- * In such a case, you can also specify \ref ANA_NOUSER_RMPBC to not to
- * confuse the user with an option that would only slow the program
- * down.
- *
- * \see \ref ANA_NOUSER_RMPBC
- */
-int
-gmx_ana_set_rmpbc(gmx_ana_traj_t *d, gmx_bool bRmPBC)
-{
-    d->bRmPBC = bRmPBC;
-    return 0;
-}
-
-/*!
- * \param[in,out] d       Trajectory analysis data structure.
- * \param[in]     frflags Flags for what to read from the trajectory file.
- * \returns       0 on success, an error code on error.
- *
- * The TRX_NEED_X flag is always set.
- * If the analysis tools needs some other information (velocities, forces),
- * it can call this function to load additional information from the
- * trajectory.
- */
-int
-gmx_ana_set_frflags(gmx_ana_traj_t *d, int frflags)
-{
-    if (d->sel)
-    {
-        gmx_call("cannot set trajectory flags after initializing selections");
-        return -1;
-    }
-    if (d->fr)
-    {
-        gmx_call("cannot set trajectory flags after the first frame has been read");
-        return -1;
-    }
-    frflags |= TRX_NEED_X;
-    d->frflags = frflags;
-    return 0;
-}
-
-/*!
- * \param[in,out] d        Trajectory analysis data structure.
- * \param[in]     nrefgrps Number of reference groups required.
- * \returns       0 on success, a non-zero error code on error.
- *
- * \p nrefgrps should be a non-negative integer.
- * If this function is not called (or \p nrefgrps is 0), all selections are
- * treated as reference groups.
- */
-int
-gmx_ana_set_nrefgrps(gmx_ana_traj_t *d, int nrefgrps)
-{
-    if (nrefgrps < 0)
-    {
-        d->nrefgrps = 0;
-        gmx_incons("number of reference groups is negative");
-        return EINVAL;
-    }
-    d->nrefgrps = nrefgrps;
-    return 0;
-}
-
-/*!
- * \param[in,out] d        Trajectory analysis data structure.
- * \param[in]     nanagrps Number of analysis groups required
- *   (-1 stands for any number of analysis groups).
- * \returns       0 on success, a non-zero error code on error.
- *
- * \p nanagrps should be a positive integer or -1.
- * In the latter case, any number of groups (but at least one) is acceptable.
- * gmx_ana_get_nanagrps() can be used to access the actual value after
- * gmx_ana_init_selections() has been called.
- * If this function is not called, a single analysis group is expected.
- */
-int
-gmx_ana_set_nanagrps(gmx_ana_traj_t *d, int nanagrps)
-{
-    if (nanagrps <= 0 && nanagrps != -1)
-    {
-        d->nanagrps = 1;
-        gmx_incons("number of analysis groups is invalid");
-        return EINVAL;
-    }
-    d->nanagrps = nanagrps;
-    return 0;
-}
-
-/*!
- * \param[in]  d     Trajectory analysis data structure.
- * \param[out] ngrps Total number of selections specified by the user.
- * \returns    0 on success, a non-zero error code on error.
- *
- * The value stored in \p *ngrps is the sum of the number of reference groups
- * and the number of analysis groups.
- * If a specific number (not -1) of analysis groups has been set with
- * gmx_ana_set_nanagrps(), the value is always the sum of the values provided
- * to gmx_ana_set_nrefgrps() and gmx_ana_set_nanagrps().
- *
- * Should only be called after gmx_ana_init_selections().
- */
-int
-gmx_ana_get_ngrps(gmx_ana_traj_t *d, int *ngrps)
-{
-    if (d->nanagrps == -1)
-    {
-        *ngrps = 0;
-        gmx_call("gmx_ana_init_selections() not called");
-        return EINVAL;
-    }
-    *ngrps = d->nrefgrps + d->nanagrps;
-    return 0;
-}
-
-/*!
- * \param[in]  d        Trajectory analysis data structure.
- * \param[out] nanagrps Number of analysis groups specified by the user.
- * \returns    0 on success, a non-zero error code on error.
- *
- * If a specific number (not -1) of analysis groups has been set with
- * gmx_ana_set_nanagrps(), the value is always the same value.
- * Hence, you only need to call this function if gmx_ana_set_nanagrps() has
- * been called with \p nanagrps set to -1.
- *
- * Should only be called after gmx_ana_init_selections().
- */
-int
-gmx_ana_get_nanagrps(gmx_ana_traj_t *d, int *nanagrps)
-{
-    if (d->nanagrps == -1)
-    {
-        *nanagrps = 0;
-        gmx_call("gmx_ana_init_selections() not called");
-        return EINVAL;
-    }
-    *nanagrps = d->nanagrps;
-    return 0;
-}
-
-/*!
- * \param[in]  d   Trajectory analysis data structure.
- * \param[in]  i   Ordinal number of the reference selection to get.
- * \param[out] sel Selection object for the \p i'th reference group.
- * \returns    0 on success, a non-zero error code on error.
- *
- * The pointer returned in \p *sel should not be freed.
- * Should only be called after gmx_ana_init_selections().
- */
-int
-gmx_ana_get_refsel(gmx_ana_traj_t *d, int i, gmx_ana_selection_t **sel)
-{
-    if (i < 0 || i >= d->nrefgrps)
-    {
-        *sel = NULL;
-        gmx_call("invalid reference group number");
-        return EINVAL;
-    }
-    *sel = gmx_ana_selcollection_get_selection(d->sc, i);
-    if (!*sel)
-    {
-        gmx_incons("gmx_ana_init_selections() not called");
-        return EINVAL;
-    }
-    return 0;
-}
-
-/*!
- * \param[in]  d   Trajectory analysis data structure.
- * \param[out] sel Array of analysis selections.
- * \returns    0 on success, a non-zero error code on error.
- *
- * The pointer returned in \p *sel should not be freed.
- * Should only be called after gmx_ana_init_selections().
- */
-int
-gmx_ana_get_anagrps(gmx_ana_traj_t *d, gmx_ana_selection_t ***sel)
-{
-    if (!d->sel)
-    {
-        *sel = NULL;
-        gmx_incons("gmx_ana_init_selections() not called");
-        return EINVAL;
-    }
-    *sel = d->sel;
-    return 0;
-}
-
-/*!
- * \param[in]  d        Trajectory analysis data structure.
- * \param[out] grpnames Array of selection names.
- * \returns    0 on success, a non-zero error code on error.
- *
- * The pointer returned in \p *grpnames should not be freed.
- * Should only be called after gmx_ana_init_selections().
- */
-int
-gmx_ana_get_grpnames(gmx_ana_traj_t *d, char ***grpnames)
-{
-    if (!d->grpnames)
-    {
-        *grpnames = NULL;
-        gmx_call("gmx_ana_init_selections() not called");
-        return EINVAL;
-    }
-    *grpnames = d->grpnames;
-    return 0;
-}
-
-/*!
- * \param[in]  d   Trajectory analysis data structure.
- * \param[out] sc  Selection collection object.
- * \returns    0 on success.
- *
- * This function is mostly useful for debugging purposes.
- * The information commonly required in analysis programs is accessible
- * more conveniently through other means.
- *
- * The pointer returned in \p *sc should not be freed.
- * Can be called at any point.
- */
-int
-gmx_ana_get_selcollection(gmx_ana_traj_t *d, gmx_ana_selcollection_t **sc)
-{
-    *sc = d->sc;
-    return 0;
-}
-
-/*!
- * \param[in,out] d     Trajectory analysis data structure.
- * \returns    0 on success, a non-zero error code on error.
- *
- * This function should be called first in the analysis program, much in
- * the same way as parse_common_args() in traditional Gromacs analysis
- * programs. It adds some command-line arguments of its own, and uses
- * parse_common_args() to parse the command-line arguments.
- * It also loads topology information if required or if a topology is
- * provided on the command line.
- * Selection handling is also initialized if it is enabled and
- * the user has selected it on the command line.
- *
- * The rest of the parameters are passed on to the Gromacs routine
- * parse_common_args(), and the use of this function should be identical
- * to parse_common_args(), with the exception that for \p pca_flags,
- * \p PCA_CAN_TIME and \p PCA_BE_NICE flags are automatically added.
- * \param      argc
- * \param      argv
- * \param      pca_flags
- * \param      nfile
- * \param      fnm
- * \param      npargs
- * \param      pa
- * \param      ndesc
- * \param      desc
- * \param      nbugs
- * \param      bugs
- * \param      oenv
- */
-int
-parse_trjana_args(gmx_ana_traj_t *d,
-                  int *argc, char *argv[], unsigned long pca_flags,
-                  int nfile, t_filenm fnm[], int npargs, t_pargs *pa,
-                  int ndesc, const char **desc,
-                 int nbugs, const char **bugs,
-                  output_env_t *oenv)
-{
-    t_filenm           *all_fnm = NULL;
-    int                 max_fnm, nfall;
-    int                *fnm_map;
-    t_pargs            *all_pa = NULL;
-    int                 max_pa, npall;
-    size_t              i;
-    int                 k;
-    int                 rc;
-    const char         *tmp_fnm;
-
-    t_filenm            def_fnm[] = {
-        {efTRX, NULL,  NULL,        ffOPTRD},
-        {efTPS, NULL,  NULL,        ffREAD},
-        {efDAT, "-sf", "selection", ffOPTRD},
-        {efNDX, NULL,  NULL,        ffOPTRD},
-    };
-    gmx_bool                bPBC = TRUE;
-    t_pargs             pbc_pa[] = {
-        {"-pbc",      FALSE, etBOOL, {&bPBC},
-         "Use periodic boundary conditions for distance calculation"},
-    };
-    gmx_bool                bRmPBC = TRUE;
-    t_pargs             rmpbc_pa[] = {
-        {"-rmpbc",    FALSE, etBOOL, {&bRmPBC},
-         "Make molecules whole for each frame"},
-    };
-    char               *selection = NULL;
-    const char        **rpost     = NULL;
-    gmx_bool                bSelDump  = FALSE;
-    t_pargs             sel_pa[] = {
-        {"-select",   FALSE, etSTR,  {&selection},
-         "Selection string (use 'help' for help)"},
-        {"-seldebug", FALSE, etBOOL, {&bSelDump},
-         "HIDDENPrint out the parsed and compiled selection trees"},
-    };
-    t_pargs             dsel_pa[] = {
-        {"-selrpos",  FALSE, etENUM, {NULL},
-         "Selection reference position"},
-    };
-    const char        **spost = NULL;
-    t_pargs             selpt_pa[] = {
-        {"-seltype",  FALSE, etENUM, {NULL},
-         "Default analysis positions"},
-    };
-#define MAX_PA asize(sel_pa)+asize(dsel_pa)+5
-
-    if (d->nrefgrps < 0)
-    {
-        gmx_incons("number of reference groups is negative");
-        return EINVAL;
-    }
-
-    if (d->flags & ANA_DEBUG_SELECTION)
-    {
-        bSelDump = TRUE;
-    }
-
-    rpost = gmx_ana_poscalc_create_type_enum(!(d->flags & ANA_REQUIRE_WHOLE));
-    if (rpost == NULL)
-    {
-        return ENOMEM;
-    }
-    spost = gmx_ana_poscalc_create_type_enum(TRUE);
-    if (spost == NULL)
-    {
-        sfree(rpost);
-        return ENOMEM;
-    }
-
-    /* Construct the file name argument array */
-    max_fnm = nfile + asize(def_fnm);
-    snew(all_fnm, max_fnm);
-    nfall = 0;
-    if (!(d->flags & ANA_REQUIRE_TOP))
-    {
-        def_fnm[1].flag |= ffOPT;
-    }
-    snew(fnm_map, nfile);
-    for (k = 0; k < nfile; ++k)
-    {
-        fnm_map[k] = -1;
-    }
-
-    for (i = 0; i < asize(def_fnm); ++i)
-    {
-        for (k = 0; k < nfile; ++k)
-        {
-            if (fnm_map[k] == -1 && def_fnm[i].opt == NULL
-                && fnm[k].opt == NULL && fnm[k].ftp == def_fnm[i].ftp)
-            {
-                break;
-            }
-        }
-        if (k < nfile)
-        {
-            fnm_map[k] = nfall;
-            nfall = add_fnmarg(nfall, all_fnm, &(fnm[k]));
-        }
-        else
-        {
-            nfall = add_fnmarg(nfall, all_fnm, &(def_fnm[i]));
-        }
-    }
-
-    for (k = 0; k < nfile; ++k)
-    {
-        if (fnm_map[k] == -1)
-        {
-            fnm_map[k] = nfall;
-            nfall = add_fnmarg(nfall, all_fnm, &(fnm[k]));
-        }
-    }
-
-    /* Construct the argument array */
-    max_pa = npargs + MAX_PA;
-    snew(all_pa, max_pa);
-    npall = 0;
-
-    if (!(d->flags & ANA_NOUSER_RMPBC))
-    {
-        for (i = 0; i < asize(rmpbc_pa); ++i)
-        {
-            npall = add_parg(npall, all_pa, &(rmpbc_pa[i]));
-        }
-    }
-    if (!(d->flags & ANA_NOUSER_PBC))
-    {
-        for (i = 0; i < asize(pbc_pa); ++i)
-        {
-            npall = add_parg(npall, all_pa, &(pbc_pa[i]));
-        }
-    }
-
-    for (i = 0; i < asize(sel_pa); ++i)
-    {
-        npall = add_parg(npall, all_pa, &(sel_pa[i]));
-    }
-    if (!(d->flags & ANA_NO_DYNSEL))
-    {
-        dsel_pa[0].u.c = rpost;
-        for (i = 0; i < asize(dsel_pa); ++i)
-        {
-            npall = add_parg(npall, all_pa, &(dsel_pa[i]));
-        }
-    }
-
-    if (!(d->flags & ANA_ONLY_ATOMPOS))
-    {
-        selpt_pa[0].u.c = spost;
-        for (i = 0; i < asize(selpt_pa); ++i)
-        {
-            npall = add_parg(npall, all_pa, &(selpt_pa[i]));
-        }
-    }
-
-    for (k = 0; k < npargs; ++k)
-    {
-        npall = add_parg(npall, all_pa, &(pa[k]));
-    }
-
-    pca_flags |= PCA_CAN_TIME | PCA_BE_NICE;
-    parse_common_args(argc, argv, pca_flags, nfall, all_fnm, npall, all_pa,
-                      ndesc, desc, nbugs, bugs,oenv);
-    d->oenv = *oenv;
-
-    /* Process our own options.
-     * Make copies of file names for easier memory management. */
-    tmp_fnm            = ftp2fn_null(efTRX, nfall, all_fnm);
-    d->trjfile         = tmp_fnm ? strdup(tmp_fnm) : NULL;
-    tmp_fnm            = ftp2fn_null(efTPS, nfall, all_fnm);
-    d->topfile         = tmp_fnm ? strdup(tmp_fnm) : NULL;
-    d->topfile_notnull = strdup(ftp2fn(efTPS, nfall, all_fnm));
-    tmp_fnm            = ftp2fn_null(efNDX, nfall, all_fnm);
-    d->ndxfile         = tmp_fnm ? strdup(tmp_fnm) : NULL;
-    if (!(d->flags & ANA_NOUSER_RMPBC))
-    {
-        d->bRmPBC      = bRmPBC;
-    }
-    if (!(d->flags & ANA_NOUSER_PBC))
-    {
-        d->bPBC        = bPBC;
-    }
-    d->selection       = selection;
-    tmp_fnm            = opt2fn_null("-sf", nfall, all_fnm);
-    d->selfile         = tmp_fnm ? strdup(tmp_fnm) : NULL;
-
-    /* Copy the results back */
-    for (k = 0; k < nfile; ++k)
-    {
-        memcpy(&(fnm[k]), &(all_fnm[fnm_map[k]]), sizeof(fnm[k]));
-        /* Delegate responsibility of freeing the file names to caller. */
-        all_fnm[fnm_map[k]].nfiles = 0;
-        all_fnm[fnm_map[k]].fns    = NULL;
-    }
-    for (i = 0, k = npall - npargs; i < (size_t)npargs; ++i, ++k)
-    {
-        memcpy(&(pa[i]), &(all_pa[k]), sizeof(pa[i]));
-    }
-
-    /* Free memory we have allocated. */
-    done_filenms(nfall, all_fnm);
-    sfree(all_fnm);
-    sfree(fnm_map);
-    sfree(all_pa);
-
-    if (!(d->flags & ANA_NO_DYNSEL))
-    {
-        gmx_ana_selcollection_set_refpostype(d->sc, rpost[0]);
-    }
-    else
-    {
-        gmx_ana_selcollection_set_refpostype(d->sc, rpost[1]);
-    }
-    sfree(rpost);
-    if (bSelDump)
-    {
-        d->flags |= ANA_DEBUG_SELECTION;
-    }
-    else
-    {
-        d->flags &= ~ANA_DEBUG_SELECTION;
-    }
-
-    if (!(d->flags & ANA_ONLY_ATOMPOS))
-    {
-        gmx_ana_selcollection_set_outpostype(d->sc, spost[0], d->flags & ANA_USE_POSMASK);
-    }
-    else
-    {
-        gmx_ana_selcollection_set_outpostype(d->sc, spost[1], d->flags & ANA_USE_POSMASK);
-    }
-    sfree(spost);
-
-    /* Check if the user requested help on selections.
-     * If so, call gmx_ana_init_selections() to print the help and exit. */
-    if (selection && strncmp(selection, "help", 4) == 0)
-    {
-        gmx_ana_init_selections(d);
-    }
-
-    /* If no trajectory file is given, we need to set some flags to be able
-     * to prepare a frame from the loaded topology information. Also, check
-     * that a topology is provided. */
-    if (!d->trjfile)
-    {
-        if (!d->topfile)
-        {
-            gmx_input("No trajectory or topology provided, nothing to do!");
-            return -1;
-        }
-        d->flags |= ANA_REQUIRE_TOP;
-        d->flags |= ANA_USE_TOPX;
-    }
-
-    /* Load the topology if so requested. */
-    rc = load_topology(d, (d->flags & ANA_REQUIRE_TOP));
-    if (rc != 0)
-    {
-        return rc;
-    }
-
-    /* Initialize the selections/index groups */
-    if (!(d->flags & ANA_USER_SELINIT))
-    {
-        rc = gmx_ana_init_selections(d);
-    }
-
-    return rc;
-}
-
-/*!
- * \param[in,out] d     Trajectory analysis data structure.
- * \param[in]     bReq  If TRUE, topology loading is forced.
- * \returns       0 on success, a non-zero error code on error.
- *
- * Initializes the \c gmx_ana_traj_t::top, \c gmx_ana_traj_t::bTop,
- * \c gmx_ana_traj_t::boxtop and \c gmx_ana_traj_t::ePBC fields of the
- * analysis structure.
- * If \p bReq is TRUE, the topology is loaded even if it is not given on
- * the command line.
- *
- * The function can be called multiple times safely; extra calls are
- * ignored.
- */
-static int load_topology(gmx_ana_traj_t *d, gmx_bool bReq)
-{
-    char                title[STRLEN];
-
-    /* Return if topology already loaded */
-    if (d->top)
-    {
-        return 0;
-    }
-
-    if (d->topfile || bReq)
-    {
-        snew(d->top, 1);
-        d->bTop = read_tps_conf(d->topfile_notnull, title, d->top,
-                                &d->ePBC, &d->xtop, NULL, d->boxtop, TRUE);
-        if (!(d->flags & ANA_USE_TOPX))
-        {
-            sfree(d->xtop);
-            d->xtop = NULL;
-        }
-    }
-    return 0;
-}
-
-/*!
- * \param[in]  d     Trajectory analysis data structure.
- * \param[in]  bReq  If TRUE, topology loading is forced.
- * \param[out] top   Topology data pointer to initialize.
- * \param[out] bTop  TRUE if a full tpx file was loaded, FALSE otherwise
- *   (can be NULL, in which case it is not used).
- * \returns    0 on success, a non-zero error code on error.
- *
- * If \ref ANA_REQUIRE_TOP has not been specified and \p bReq is FALSE,
- * the pointer stored in \p *top may be NULL if no topology has been provided
- * on the command line.
- *
- * The pointer returned in \p *top should not be freed.
- */
-int
-gmx_ana_get_topology(gmx_ana_traj_t *d, gmx_bool bReq, t_topology **top, gmx_bool *bTop)
-{
-    int rc;
-
-    rc = load_topology(d, bReq);
-    if (rc != 0)
-    {
-        *top = NULL;
-        return rc;
-    }
-    *top = d->top;
-    if (bTop)
-    {
-        *bTop = d->bTop;
-    }
-    return 0;
-}
-
-/*!
- * \param[in]  d     Trajectory analysis data structure.
- * \param[out] x     Topology data pointer to initialize.
- *   (can be NULL, in which case it is not used).
- * \param[out] box   Box size from the topology file
- *   (can be NULL, in which case it is not used).
- * \param[out] ePBC  The ePBC field from the topology
- *   (can be NULL, in which case it is not used).
- * \returns    0 on success, a non-zero error code on error.
- *
- * If \ref ANA_USE_TOPX has not been specified, the \p x parameter should be
- * NULL.
- *
- * The pointer returned in \p *x should not be freed.
- */
-int
-gmx_ana_get_topconf(gmx_ana_traj_t *d, rvec **x, matrix box, int *ePBC)
-{
-    if (box)
-    {
-        copy_mat(d->boxtop, box);
-    }
-    if (ePBC)
-    {
-        *ePBC = d->ePBC;
-    }
-    if (x)
-    {
-        if (!(d->flags & ANA_USE_TOPX))
-        {
-            gmx_incons("topology coordinates requested by ANA_USE_TOPX not set");
-            *x = NULL;
-            return EINVAL;
-        }
-        *x = d->xtop;
-    }
-    return 0;
-}
-
-/*! \brief
- * Loads default index groups from a selection file.
- *
- * \param[in,out] d     Trajectory analysis data structure.
- * \param[out]    grps  Pointer to receive the default groups.
- * \returns       0 on success, a non-zero error code on error.
- */
-static int
-init_default_selections(gmx_ana_traj_t *d, gmx_ana_indexgrps_t **grps)
-{
-    gmx_ana_selcollection_t  *sc;
-    char                     *fnm;
-    int                       nr, nr_notempty, i;
-    int                       rc;
-
-    /* If an index file is provided, just load it and exit. */
-    if (d->ndxfile)
-    {
-        gmx_ana_indexgrps_init(grps, d->top, d->ndxfile);
-        return 0;
-    }
-    /* Initialize groups to NULL if we return prematurely. */
-    *grps = NULL;
-    /* Return immediately if no topology provided. */
-    if (!d->top)
-    {
-        return 0;
-    }
-
-    /* Find the default selection file, return if none found. */
-    fnm = low_gmxlibfn("defselection.dat", TRUE, FALSE);
-    if (fnm == NULL)
-    {
-        return 0;
-    }
-
-    /* Create a temporary selection collection. */
-    rc = gmx_ana_selcollection_create(&sc, d->pcc);
-    if (rc != 0)
-    {
-        sfree(fnm);
-        return rc;
-    }
-    rc = gmx_ana_selmethod_register_defaults(sc);
-    if (rc != 0)
-    {
-        gmx_ana_selcollection_free(sc);
-        sfree(fnm);
-        gmx_fatal(FARGS, "default selection method registration failed");
-        return rc;
-    }
-    /* FIXME: It would be better to not have the strings here hard-coded. */
-    gmx_ana_selcollection_set_refpostype(sc, "atom");
-    gmx_ana_selcollection_set_outpostype(sc, "atom", FALSE);
-
-    /* Parse and compile the file with no external groups. */
-    rc = gmx_ana_selcollection_parse_file(sc, fnm, NULL);
-    sfree(fnm);
-    if (rc != 0)
-    {
-        gmx_ana_selcollection_free(sc);
-        fprintf(stderr, "\nWARNING: default selection(s) could not be parsed\n");
-        return rc;
-    }
-    gmx_ana_selcollection_set_topology(sc, d->top, -1);
-    rc = gmx_ana_selcollection_compile(sc);
-    if (rc != 0)
-    {
-        gmx_ana_selcollection_free(sc);
-        fprintf(stderr, "\nWARNING: default selection(s) could not be compiled\n");
-        return rc;
-    }
-
-    /* Count the non-empty groups and check that there are no dynamic
-     * selections. */
-    nr = gmx_ana_selcollection_get_count(sc);
-    nr_notempty = 0;
-    for (i = 0; i < nr; ++i)
-    {
-        gmx_ana_selection_t  *sel;
-
-        sel = gmx_ana_selcollection_get_selection(sc, i);
-        if (sel->bDynamic)
-        {
-            fprintf(stderr, "\nWARNING: dynamic default selection ignored\n");
-        }
-        else if (sel->g->isize > 0)
-        {
-            ++nr_notempty;
-        }
-    }
-
-    /* Copy the groups to the output structure */
-    gmx_ana_indexgrps_alloc(grps, nr_notempty);
-    nr_notempty = 0;
-    for (i = 0; i < nr; ++i)
-    {
-        gmx_ana_selection_t  *sel;
-
-        sel = gmx_ana_selcollection_get_selection(sc, i);
-        if (!sel->bDynamic && sel->g->isize > 0)
-        {
-            gmx_ana_index_t  *g;
-
-            g = gmx_ana_indexgrps_get_grp(*grps, nr_notempty);
-            gmx_ana_index_copy(g, sel->g, TRUE);
-            g->name = strdup(sel->name);
-            ++nr_notempty;
-        }
-    }
-
-    gmx_ana_selcollection_free(sc);
-    return 0;
-}
-
-/*!
- * \param[in,out] d     Trajectory analysis data structure.
- * \returns       0 on success, a non-zero error code on error.
- *
- * Initializes the selection data in \c gmx_ana_traj_t based on
- * the selection options and/or index files provided on the command line.
- *
- * This function is called automatically by parse_trjana_args() and should
- * not be called directly unless \ref ANA_USER_SELINIT is specified.
- *
- * \see ANA_USER_SELINIT
- */
-int
-gmx_ana_init_selections(gmx_ana_traj_t *d)
-{
-    int                  rc;
-    int                  i;
-    int                  nr;
-    gmx_ana_indexgrps_t *grps;
-    int                  natoms;
-    gmx_bool                 bStdIn;
-    gmx_bool                 bInteractive;
-    gmx_bool                 bOk;
-
-    if (d->sel)
-    {
-        gmx_call("init_selections called more than once\n"
-                 "perhaps you forgot ANA_USER_SELINIT");
-        return -1;
-    }
-
-    gmx_ana_selcollection_set_veloutput(d->sc,
-            d->frflags & (TRX_READ_V | TRX_NEED_V));
-    gmx_ana_selcollection_set_forceoutput(d->sc,
-            d->frflags & (TRX_READ_F | TRX_NEED_F));
-    /* Check if we need some information from the topology */
-    if (gmx_ana_selcollection_requires_top(d->sc))
-    {
-        rc = load_topology(d, TRUE);
-        if (rc != 0)
-        {
-            return rc;
-        }
-    }
-    /* Initialize the default selection methods */
-    rc = gmx_ana_selmethod_register_defaults(d->sc);
-    if (rc != 0)
-    {
-        gmx_fatal(FARGS, "default selection method registration failed");
-        return rc;
-    }
-    /* Initialize index groups.
-     * We ignore the return value to continue without the default groups if
-     * there is an error there. */
-    init_default_selections(d, &grps);
-    /* Parse the selections */
-    bStdIn = (d->selfile && d->selfile[0] == '-' && d->selfile[1] == 0)
-             || (d->selection && d->selection[0] == 0)
-             || (!d->selfile && !d->selection);
-    /* Behavior is not very pretty if we cannot check for interactive input,
-     * but at least it should compile and work in most cases. */
-#ifdef HAVE_UNISTD_H
-    bInteractive = bStdIn && isatty(fileno(stdin));
-#else
-    bInteractive = bStdIn;
-#endif
-    if (bStdIn && bInteractive)
-    {
-        /* Parse from stdin */
-        /* First we parse the reference groups if there are any */
-        if (d->nrefgrps > 0)
-        {
-            fprintf(stderr, "\nSpecify ");
-            if (d->nrefgrps == 1)
-            {
-                fprintf(stderr, "a reference selection");
-            }
-            else
-            {
-                fprintf(stderr, "%d reference selections", d->nrefgrps);
-            }
-            fprintf(stderr, ":\n");
-            fprintf(stderr, "(one selection per line, 'help' for help)\n");
-            rc = gmx_ana_selcollection_parse_stdin(d->sc, d->nrefgrps, grps, TRUE);
-            nr = gmx_ana_selcollection_get_count(d->sc);
-            if (rc != 0 || nr != d->nrefgrps)
-            {
-                gmx_ana_traj_free(d);
-                gmx_input("unrecoverable error in selection parsing");
-                return rc;
-            }
-        }
-        /* Then, we parse the analysis groups */
-        fprintf(stderr, "\nSpecify ");
-        if (d->nanagrps == 1)
-        {
-            fprintf(stderr, "a selection");
-        }
-        else if (d->nanagrps == -1)
-        {
-            fprintf(stderr, "any number of selections");
-        }
-        else
-        {
-            fprintf(stderr, "%d selections", d->nanagrps);
-        }
-        fprintf(stderr, " for analysis:\n");
-        fprintf(stderr, "(one selection per line, 'help' for help%s)\n",
-                d->nanagrps == -1 ? ", Ctrl-D to end" : "");
-        rc = gmx_ana_selcollection_parse_stdin(d->sc, d->nanagrps, grps, TRUE);
-        fprintf(stderr, "\n");
-    }
-    else if (bStdIn)
-    {
-        rc = gmx_ana_selcollection_parse_stdin(d->sc, -1, grps, FALSE);
-    }
-    else if (d->selection)
-    {
-        rc = gmx_ana_selcollection_parse_str(d->sc, d->selection, grps);
-    }
-    else
-    {
-        rc = gmx_ana_selcollection_parse_file(d->sc, d->selfile, grps);
-    }
-    if (grps)
-    {
-        gmx_ana_indexgrps_free(grps);
-    }
-    if (rc != 0)
-    {
-        /* Free memory for memory leak checking */
-        gmx_ana_traj_free(d);
-        gmx_input("selection(s) could not be parsed");
-        return rc;
-    }
-
-    /* Check the number of groups */
-    nr = gmx_ana_selcollection_get_count(d->sc);
-    if (nr == 0)
-    {
-        /* TODO: Don't print this if the user has requested help */
-        fprintf(stderr, "Nothing selected, finishing up.\n");
-        gmx_ana_traj_free(d);
-        /* TODO: It would be better to return some code that tells the caller
-         * that one should exit. */
-        exit(0);
-    }
-    if (nr <= d->nrefgrps)
-    {
-        gmx_input("selection does not specify enough index groups");
-        return -1;
-    }
-    if (d->nanagrps <= 0)
-    {
-        d->nanagrps = nr - d->nrefgrps;
-    }
-    else if (nr != d->nrefgrps + d->nanagrps)
-    {
-        gmx_input("selection does not specify the correct number of index groups");
-        return -1;
-    }
-
-    if (d->flags & ANA_DEBUG_SELECTION)
-    {
-        gmx_ana_selcollection_print_tree(stderr, d->sc, FALSE);
-    }
-    if (gmx_ana_selcollection_requires_top(d->sc))
-    {
-        rc = load_topology(d, TRUE);
-        if (rc != 0)
-        {
-            return rc;
-        }
-    }
-    if (d->top)
-    {
-        natoms = -1;
-    }
-    else
-    {
-        rc = init_first_frame(d);
-        if (rc != 0)
-        {
-            return rc;
-        }
-        natoms = d->fr->natoms;
-    }
-    gmx_ana_selcollection_set_topology(d->sc, d->top, natoms);
-    rc = gmx_ana_selcollection_compile(d->sc);
-    if (rc != 0)
-    {
-        /* Free memory for memory leak checking */
-        gmx_ana_traj_free(d);
-        gmx_input("selection could not be compiled");
-        return rc;
-    }
-    /* Create the selection array */
-    d->ngrps = gmx_ana_selcollection_get_count(d->sc);
-    if (!(d->flags & ANA_USE_FULLGRPS))
-    {
-        d->ngrps -= d->nrefgrps;
-    }
-    snew(d->sel, d->ngrps);
-    for (i = 0; i < d->ngrps; ++i)
-    {
-        if (d->flags & ANA_USE_FULLGRPS)
-        {
-            d->sel[i] = gmx_ana_selcollection_get_selection(d->sc, i);
-        }
-        else
-        {
-            d->sel[i] = gmx_ana_selcollection_get_selection(d->sc, i + d->nrefgrps);
-        }
-    }
-    if (d->flags & ANA_DEBUG_SELECTION)
-    {
-        fprintf(stderr, "\n");
-        gmx_ana_selcollection_print_tree(stderr, d->sc, FALSE);
-        fprintf(stderr, "\n");
-        gmx_ana_poscalc_coll_print_tree(stderr, d->pcc);
-        fprintf(stderr, "\n");
-    }
-
-    /* Initialize the position evaluation */
-    gmx_ana_poscalc_init_eval(d->pcc);
-    if (d->flags & ANA_DEBUG_SELECTION)
-    {
-        gmx_ana_poscalc_coll_print_tree(stderr, d->pcc);
-        fprintf(stderr, "\n");
-    }
-
-    /* Check that dynamic selections are not provided if not allowed */
-    if (d->flags & ANA_NO_DYNSEL)
-    {
-        for (i = 0; i < d->nrefgrps + d->nanagrps; ++i)
-        {
-            gmx_ana_selection_t *sel;
-
-            sel = gmx_ana_selcollection_get_selection(d->sc, i);
-            if (sel->bDynamic)
-            {
-                gmx_fatal(FARGS, "%s does not support dynamic selections",
-                          ShortProgram());
-                return -1;
-            }
-        }
-    }
-    /* Check that non-atom positions are not provided if not allowed.
-     * TODO: It would be better to have these checks in the parser. */
-    if (d->flags & ANA_ONLY_ATOMPOS)
-    {
-        for (i = 0; i < d->nanagrps; ++i)
-        {
-            gmx_ana_selection_t *sel;
-
-            sel = gmx_ana_selcollection_get_selection(d->sc, i + d->nrefgrps);
-            if (sel->p.m.type != INDEX_ATOM)
-            {
-                gmx_fatal(FARGS, "%s does not support non-atom positions",
-                          ShortProgram());
-                return -1;
-            }
-        }
-    }
-    /* Create the names array */
-    snew(d->grpnames, d->ngrps);
-    for (i = 0; i < d->ngrps; ++i)
-    {
-        d->grpnames[i] = gmx_ana_selection_name(d->sel[i]);
-    }
-
-    return 0;
-}
-
-/*!
- * \param[in,out] d       Trajectory analysis data structure.
- * \param[in]     type    Type of covered fractions to calculate.
- * \returns       0 on success, a non-zero error code on error.
- *
- * By default, covered fractions are not calculated.
- * If this function is called, the covered fraction calculation is
- * initialize to calculate the fractions of type \p type for each selection.
- * The function must be called after gmx_ana_init_selections() has been
- * called.
- *
- * For more fine-grained control of the calculation, you can use
- * gmx_ana_selection_init_coverfrac(): if you initialize some selections
- * this function to something else than CFRAC_NONE before calling
- * gmx_ana_init_coverfrac(), these settings are not overwritten.
- *
- * You only need to call this function if your program needs to have
- * information about the covered fractions, e.g., for normalization.
- *
- * \see gmx_ana_selection_init_coverfrac()
- */
-int
-gmx_ana_init_coverfrac(gmx_ana_traj_t *d, e_coverfrac_t type)
-{
-    int                 g;
-
-    if (type == CFRAC_NONE)
-    {
-        return 0;
-    }
-
-    for (g = 0; g < d->ngrps; ++g)
-    {
-        if (d->sel[g]->cfractype == CFRAC_NONE)
-        {
-            gmx_ana_selection_init_coverfrac(d->sel[g], type);
-        }
-    }
-    return 0;
-}
-
-/*!
- * \param[in] out  Output file.
- * \param[in] d    Trajectory analysis data structure.
- * \returns   0 on success, a non-zero error code on error.
- */
-int xvgr_selections(FILE *out, gmx_ana_traj_t *d)
-{
-    xvgr_selcollection(out, d->sc, d->oenv);
-    return 0;
-}
-
-/*!
- * \param[in,out] d       Trajectory analysis data structure.
- * \returns       0 on success, a non-zero error code on error.
- */
-static int init_first_frame(gmx_ana_traj_t *d)
-{
-    int                 i;
-
-    /* Return if we have already initialized the trajectory */
-    if (d->fr)
-    {
-        return 0;
-    }
-
-    d->frflags |= TRX_NEED_X;
-
-    snew(d->fr, 1);
-
-    if (d->trjfile)
-    {
-        if (!read_first_frame(d->oenv, &d->status, d->trjfile, d->fr, d->frflags))
-        {
-            gmx_input("could not read coordinates from trajectory");
-            return EIO;
-        }
-
-        if (d->top && d->fr->natoms > d->top->atoms.nr)
-        {
-            gmx_fatal(FARGS, "Trajectory (%d atoms) does not match topology (%d atoms)",
-                      d->fr->natoms, d->top->atoms.nr);
-            return -1;
-        }
-        /* check index groups */
-        for (i = 0; i < d->ngrps; ++i)
-        {
-            gmx_ana_index_check(d->sel[i]->g, d->fr->natoms);
-        }
-    }
-    else
-    {
-        /* Prepare a frame from topology information */
-        /* TODO: Initialize more of the fields */
-        if (d->frflags & (TRX_NEED_V))
-        {
-            gmx_impl("Velocity reading from a topology not implemented");
-            return -1;
-        }
-        if (d->frflags & (TRX_NEED_F))
-        {
-            gmx_input("Forces cannot be read from a topology");
-            return -1;
-        }
-        d->fr->flags  = d->frflags;
-        d->fr->natoms = d->top->atoms.nr;
-        d->fr->bX     = TRUE;
-        snew(d->fr->x, d->fr->natoms);
-        memcpy(d->fr->x, d->xtop, sizeof(*d->fr->x)*d->fr->natoms);
-        d->fr->bBox   = TRUE;
-        copy_mat(d->boxtop, d->fr->box);
-    }
-
-    set_trxframe_ePBC(d->fr, d->ePBC);
-
-    return 0;
-}
-
-/*!
- * \param[in,out] d       Trajectory analysis data structure.
- * \param[out]    fr      First frame in the trajectory.
- * \returns       0 on success, a non-zero error code on error.
- *
- * The pointer stored in \p *fr should not be freed by the caller.
- *
- * You only need to call this function if your program needs to do some
- * initialization for which it requires data from the first frame.
- *
- * \see gmx_ana_do()
- */
-int gmx_ana_get_first_frame(gmx_ana_traj_t *d, t_trxframe **fr)
-{
-    int rc;
-
-    rc = init_first_frame(d);
-    if (rc != 0)
-    {
-        *fr = NULL;
-        return rc;
-    }
-    *fr = d->fr;
-    return 0;
-}
-
-/*!
- * \param[in,out] d   Trajectory analysis data structure.
- * \param[in] flags   Combination of flags
- *      (currently, there are no flags defined).
- * \param[in] analyze Pointer to frame analysis function.
- * \param     data    User data to be passed to \p analyze.
- * \returns   0 on success, a non-zero error code on error.
- *
- * This function performs the actual analysis of the trajectory.
- * It loops through all the frames in the trajectory, and calls
- * \p analyze for each frame to perform the actual analysis.
- * Before calling \p analyze, selections are updated (if there are any).
- * See gmx_analysisfunc() for description of \p analyze parameters.
- *
- * This function also calculates the number of frames during the run.
- */
-int gmx_ana_do(gmx_ana_traj_t *d, int flags, gmx_analysisfunc analyze, void *data)
-{
-    t_pbc               pbc;
-    t_pbc              *ppbc;
-    int                 rc;
-    gmx_rmpbc_t         gpbc=NULL;
-    
-    rc = init_first_frame(d);
-    if (rc != 0)
-    {
-        return rc;
-    }
-
-    ppbc = d->bPBC ? &pbc : 0;
-    if (!d->top)
-    {
-        d->bRmPBC = FALSE;
-    }
-    if (d->bRmPBC) 
-    {
-       gpbc = gmx_rmpbc_init(&d->top->idef,d->ePBC,d->fr->natoms,d->fr->box);
-    }
-    d->nframes = 0;
-    do
-    {
-        if (d->bRmPBC)
-        {
-           gmx_rmpbc_trxfr(gpbc,d->fr);
-        }
-        if (ppbc)
-        {
-            set_pbc(&pbc, d->ePBC, d->fr->box);
-        }
-
-        gmx_ana_poscalc_init_frame(d->pcc);
-        rc = gmx_ana_selcollection_evaluate(d->sc, d->fr, ppbc);
-        if (rc != 0)
-        {
-            close_trj(d->status);
-            gmx_fatal(FARGS, "selection evaluation failed");
-            return rc;
-        }
-        rc = analyze(d->top, d->fr, ppbc, d->ngrps, d->sel, data);
-        if (rc != 0)
-        {
-            close_trj(d->status);
-            return rc;
-        }
-
-        d->nframes++;
-    }
-    while (d->trjfile && read_next_frame(d->oenv, d->status, d->fr));
-    if (d->bRmPBC)
-    {
-        gmx_rmpbc_done(gpbc);
-    }
-    if (d->trjfile)
-    {
-        close_trj(d->status);
-        fprintf(stderr, "Analyzed %d frames, last time %.3f\n",
-                d->nframes, d->fr->time);
-    }
-    else
-    {
-        fprintf(stderr, "Analyzed topology coordinates\n");
-    }
-
-    /* Restore the maximal groups for dynamic selections */
-    rc = gmx_ana_selcollection_evaluate_fin(d->sc, d->nframes);
-    if (rc != 0)
-    {
-        gmx_fatal(FARGS, "selection evaluation failed");
-    }
-
-    return rc;
-}
-
-/*!
- * \param[in,out] d       Trajectory analysis data structure.
- * \param[out]    nframes Number of frames.
- * \returns   0 on success, a non-zero error code on error.
- *
- * If called before gmx_ana_do(), the behavior is currently undefined.
- */
-extern int
-gmx_ana_get_nframes(gmx_ana_traj_t *d, int *nframes)
-{
-    *nframes = d->nframes;
-    return 0;
-}
diff --git a/src/gmxlib/txtdump.c b/src/gmxlib/txtdump.c
deleted file mode 100644 (file)
index 1314861..0000000
+++ /dev/null
@@ -1,1465 +0,0 @@
-/* -*- mode: c; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; c-file-style: "stroustrup"; -*-
- *
- * 
- *                This source code is part of
- * 
- *                 G   R   O   M   A   C   S
- * 
- *          GROningen MAchine for Chemical Simulations
- * 
- *                        VERSION 3.2.0
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
- * 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.
-
- * 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:
- * GROningen Mixture of Alchemy and Childrens' Stories
- */
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-/* This file is completely threadsafe - please keep it that way! */
-#ifdef GMX_THREADS
-#include <thread_mpi.h>
-#endif
-
-
-#include <stdio.h>
-#include "smalloc.h"
-#include "typedefs.h"
-#include "names.h"
-#include "txtdump.h"
-#include "string2.h"
-#include "vec.h"
-
-
-int pr_indent(FILE *fp,int n)
-{
-  int i;
-
-  for (i=0; i<n; i++) (void) fprintf(fp," ");
-  return n;
-}
-
-int available(FILE *fp,void *p,int indent,const char *title)
-{
-  if (!p) {
-    if (indent > 0)
-      pr_indent(fp,indent);
-    (void) fprintf(fp,"%s: not available\n",title);
-  }
-  return (p!=NULL);
-}
-
-int pr_title(FILE *fp,int indent,const char *title)
-{
-  (void) pr_indent(fp,indent);
-  (void) fprintf(fp,"%s:\n",title);
-  return (indent+INDENT);
-}
-
-int pr_title_n(FILE *fp,int indent,const char *title,int n)
-{
-  (void) pr_indent(fp,indent);
-  (void) fprintf(fp,"%s (%d):\n",title,n);
-  return (indent+INDENT);
-}
-
-int pr_title_nxn(FILE *fp,int indent,const char *title,int n1,int n2)
-{
-  (void) pr_indent(fp,indent);
-  (void) fprintf(fp,"%s (%dx%d):\n",title,n1,n2);
-  return (indent+INDENT);
-}
-
-void pr_ivec(FILE *fp,int indent,const char *title,int vec[],int n, gmx_bool bShowNumbers)
-{
-  int i;
-
-  if (available(fp,vec,indent,title))
-    {
-      indent=pr_title_n(fp,indent,title,n);
-      for (i=0; i<n; i++)
-        {
-          (void) pr_indent(fp,indent);
-          (void) fprintf(fp,"%s[%d]=%d\n",title,bShowNumbers?i:-1,vec[i]);
-        }
-    }
-}
-
-void pr_ivec_block(FILE *fp,int indent,const char *title,int vec[],int n, gmx_bool bShowNumbers)
-{
-    int i,j;
-    
-    if (available(fp,vec,indent,title))
-    {
-        indent=pr_title_n(fp,indent,title,n);
-        i = 0;
-        while (i < n)
-        {
-            j = i+1;
-            while (j < n && vec[j] == vec[j-1]+1)
-            {
-                j++;
-            }
-            /* Print consecutive groups of 3 or more as blocks */
-            if (j - i < 3)
-            {
-                while(i < j)
-                {
-                    (void) pr_indent(fp,indent);
-                    (void) fprintf(fp,"%s[%d]=%d\n",
-                                   title,bShowNumbers?i:-1,vec[i]);
-                    i++;
-                }
-            }
-            else
-            {
-                (void) pr_indent(fp,indent);
-                (void) fprintf(fp,"%s[%d,...,%d] = {%d,...,%d}\n",
-                               title,
-                               bShowNumbers?i:-1,
-                               bShowNumbers?j-1:-1,
-                               vec[i],vec[j-1]); 
-                i = j;
-            }
-        }
-    }
-}
-
-void pr_bvec(FILE *fp,int indent,const char *title,gmx_bool vec[],int n, gmx_bool bShowNumbers)
-{
-  int i;
-
-  if (available(fp,vec,indent,title))
-    {
-      indent=pr_title_n(fp,indent,title,n);
-      for (i=0; i<n; i++)
-        {
-          (void) pr_indent(fp,indent);
-          (void) fprintf(fp,"%s[%d]=%s\n",title,bShowNumbers?i:-1,
-                        BOOL(vec[i]));
-        }
-    }
-}
-
-void pr_ivecs(FILE *fp,int indent,const char *title,ivec vec[],int n, gmx_bool bShowNumbers)
-{
-  int i,j;
-
-  if (available(fp,vec,indent,title))
-    {  
-      indent=pr_title_nxn(fp,indent,title,n,DIM);
-      for (i=0; i<n; i++)
-        {
-          (void) pr_indent(fp,indent);
-          (void) fprintf(fp,"%s[%d]={",title,bShowNumbers?i:-1);
-          for (j=0; j<DIM; j++)
-            {
-              if (j!=0) (void) fprintf(fp,", ");
-              fprintf(fp,"%d",vec[i][j]);
-            }
-          (void) fprintf(fp,"}\n");
-        }
-    }
-}
-
-void pr_rvec(FILE *fp,int indent,const char *title,real vec[],int n, gmx_bool bShowNumbers)
-{
-  int i;
-
-  if (available(fp,vec,indent,title))
-    {  
-      indent=pr_title_n(fp,indent,title,n);
-      for (i=0; i<n; i++)
-        {
-          pr_indent(fp,indent);
-          fprintf(fp,"%s[%d]=%12.5e\n",title,bShowNumbers?i:-1,vec[i]);
-        }
-    }
-}
-
-void pr_dvec(FILE *fp,int indent,const char *title,double vec[],int n, gmx_bool bShowNumbers)
-{
-       int i;
-       
-       if (available(fp,vec,indent,title))
-    {  
-               indent=pr_title_n(fp,indent,title,n);
-               for (i=0; i<n; i++)
-        {
-                       pr_indent(fp,indent);
-                       fprintf(fp,"%s[%d]=%12.5e\n",title,bShowNumbers?i:-1,vec[i]);
-        }
-    }
-}
-
-
-/*
-void pr_mat(FILE *fp,int indent,char *title,matrix m)
-{
-  int i,j;
-  
-  if (available(fp,m,indent,title)) {  
-    indent=pr_title_n(fp,indent,title,n);
-    for(i=0; i<n; i++) {
-      pr_indent(fp,indent);
-      fprintf(fp,"%s[%d]=%12.5e %12.5e %12.5e\n",
-             title,bShowNumbers?i:-1,m[i][XX],m[i][YY],m[i][ZZ]);
-    }
-  }
-}
-*/
-
-void pr_rvecs_len(FILE *fp,int indent,const char *title,rvec vec[],int n)
-{
-  int i,j;
-
-  if (available(fp,vec,indent,title)) {  
-    indent=pr_title_nxn(fp,indent,title,n,DIM);
-    for (i=0; i<n; i++) {
-      (void) pr_indent(fp,indent);
-      (void) fprintf(fp,"%s[%5d]={",title,i);
-      for (j=0; j<DIM; j++) {
-       if (j != 0) 
-         (void) fprintf(fp,", ");
-       (void) fprintf(fp,"%12.5e",vec[i][j]);
-      }
-      (void) fprintf(fp,"} len=%12.5e\n",norm(vec[i]));
-    }
-  }
-}
-
-void pr_rvecs(FILE *fp,int indent,const char *title,rvec vec[],int n)
-{
-  const char *fshort = "%12.5e";
-  const char *flong  = "%15.8e";
-  const char *format;
-  int i,j;
-
-  if (getenv("LONGFORMAT") != NULL)
-    format = flong;
-  else
-    format = fshort;
-    
-  if (available(fp,vec,indent,title)) {  
-    indent=pr_title_nxn(fp,indent,title,n,DIM);
-    for (i=0; i<n; i++) {
-      (void) pr_indent(fp,indent);
-      (void) fprintf(fp,"%s[%5d]={",title,i);
-      for (j=0; j<DIM; j++) {
-       if (j != 0) 
-         (void) fprintf(fp,", ");
-       (void) fprintf(fp,format,vec[i][j]);
-      }
-      (void) fprintf(fp,"}\n");
-    }
-  }
-}
-
-
-void pr_reals(FILE *fp,int indent,const char *title,real *vec,int n)
-{
-  int i;
-    
-  if (available(fp,vec,indent,title)) {  
-    (void) pr_indent(fp,indent);
-    (void) fprintf(fp,"%s:\t",title);
-    for(i=0; i<n; i++)
-      fprintf(fp,"  %10g",vec[i]);
-    (void) fprintf(fp,"\n");
-  }
-}
-
-void pr_doubles(FILE *fp,int indent,const char *title,double *vec,int n)
-{
-  int i;
-    
-  if (available(fp,vec,indent,title)) {  
-    (void) pr_indent(fp,indent);
-    (void) fprintf(fp,"%s:\t",title);
-    for(i=0; i<n; i++)
-      fprintf(fp,"  %10g",vec[i]);
-    (void) fprintf(fp,"\n");
-  }
-}
-
-static void pr_int(FILE *fp,int indent,const char *title,int i)
-{
-  pr_indent(fp,indent);
-  fprintf(fp,"%-20s = %d\n",title,i);
-}
-
-static void pr_gmx_large_int(FILE *fp,int indent,const char *title,gmx_large_int_t i)
-{
-  char buf[STEPSTRSIZE];
-
-  pr_indent(fp,indent);
-  fprintf(fp,"%-20s = %s\n",title,gmx_step_str(i,buf));
-}
-
-static void pr_real(FILE *fp,int indent,const char *title,real r)
-{
-  pr_indent(fp,indent);
-  fprintf(fp,"%-20s = %g\n",title,r);
-}
-
-static void pr_double(FILE *fp,int indent,const char *title,double d)
-{
-  pr_indent(fp,indent);
-  fprintf(fp,"%-20s = %g\n",title,d);
-}
-
-static void pr_str(FILE *fp,int indent,const char *title,const char *s)
-{
-  pr_indent(fp,indent);
-  fprintf(fp,"%-20s = %s\n",title,s);
-}
-
-void pr_qm_opts(FILE *fp,int indent,const char *title,t_grpopts *opts)
-{
-  int i,m,j;
-
-  fprintf(fp,"%s:\n",title);
-  
-  pr_int(fp,indent,"ngQM",opts->ngQM);
-  if (opts->ngQM > 0) {
-    pr_ivec(fp,indent,"QMmethod",opts->QMmethod,opts->ngQM,FALSE);
-    pr_ivec(fp,indent,"QMbasis",opts->QMbasis,opts->ngQM,FALSE);
-    pr_ivec(fp,indent,"QMcharge",opts->QMcharge,opts->ngQM,FALSE);
-    pr_ivec(fp,indent,"QMmult",opts->QMmult,opts->ngQM,FALSE);
-    pr_bvec(fp,indent,"bSH",opts->bSH,opts->ngQM,FALSE);
-    pr_ivec(fp,indent,"CASorbitals",opts->CASorbitals,opts->ngQM,FALSE);
-    pr_ivec(fp,indent,"CASelectrons",opts->CASelectrons,opts->ngQM,FALSE);
-    pr_rvec(fp,indent,"SAon",opts->SAon,opts->ngQM,FALSE);
-    pr_rvec(fp,indent,"SAon",opts->SAon,opts->ngQM,FALSE);
-    pr_ivec(fp,indent,"SAsteps",opts->SAsteps,opts->ngQM,FALSE);
-    pr_bvec(fp,indent,"bOPT",opts->bOPT,opts->ngQM,FALSE);
-    pr_bvec(fp,indent,"bTS",opts->bTS,opts->ngQM,FALSE);
-  }
-}
-
-static void pr_grp_opts(FILE *out,int indent,const char *title,t_grpopts *opts,
-                       gmx_bool bMDPformat)
-{
-  int i,m,j;
-
-  if (!bMDPformat)
-    fprintf(out,"%s:\n",title);
-  
-  pr_indent(out,indent);
-  fprintf(out,"nrdf%s",bMDPformat ? " = " : ":");
-  for(i=0; (i<opts->ngtc); i++)
-    fprintf(out,"  %10g",opts->nrdf[i]);
-  fprintf(out,"\n");
-  
-  pr_indent(out,indent);
-  fprintf(out,"ref_t%s",bMDPformat ? " = " : ":");
-  for(i=0; (i<opts->ngtc); i++)
-    fprintf(out,"  %10g",opts->ref_t[i]);
-  fprintf(out,"\n");
-
-  pr_indent(out,indent);
-  fprintf(out,"tau_t%s",bMDPformat ? " = " : ":");
-  for(i=0; (i<opts->ngtc); i++)
-    fprintf(out,"  %10g",opts->tau_t[i]);
-  fprintf(out,"\n");  
-  
-  /* Pretty-print the simulated annealing info */
-  fprintf(out,"anneal%s",bMDPformat ? " = " : ":");
-  for(i=0; (i<opts->ngtc); i++)
-    fprintf(out,"  %10s",EANNEAL(opts->annealing[i]));
-  fprintf(out,"\n");  
-  fprintf(out,"ann_npoints%s",bMDPformat ? " = " : ":");
-  for(i=0; (i<opts->ngtc); i++)
-    fprintf(out,"  %10d",opts->anneal_npoints[i]);
-  fprintf(out,"\n");  
-  for(i=0; (i<opts->ngtc); i++) {
-    if(opts->anneal_npoints[i]>0) {
-      fprintf(out,"ann. times [%d]:\t",i);
-      for(j=0; (j<opts->anneal_npoints[i]); j++)
-       fprintf(out,"  %10.1f",opts->anneal_time[i][j]);
-      fprintf(out,"\n");  
-      fprintf(out,"ann. temps [%d]:\t",i);
-      for(j=0; (j<opts->anneal_npoints[i]); j++)
-       fprintf(out,"  %10.1f",opts->anneal_temp[i][j]);
-      fprintf(out,"\n");  
-    }
-  }
-  
-  pr_indent(out,indent);
-  fprintf(out,"acc:\t");
-  for(i=0; (i<opts->ngacc); i++)
-    for(m=0; (m<DIM); m++)
-      fprintf(out,"  %10g",opts->acc[i][m]);
-  fprintf(out,"\n");
-
-  pr_indent(out,indent);
-  fprintf(out,"nfreeze:");
-  for(i=0; (i<opts->ngfrz); i++)
-    for(m=0; (m<DIM); m++)
-      fprintf(out,"  %10s",opts->nFreeze[i][m] ? "Y" : "N");
-  fprintf(out,"\n");
-
-
-  for(i=0; (i<opts->ngener); i++) {
-    pr_indent(out,indent);
-    fprintf(out,"energygrp_flags[%3d]:",i);
-    for(m=0; (m<opts->ngener); m++)
-      fprintf(out," %d",opts->egp_flags[opts->ngener*i+m]);
-    fprintf(out,"\n");
-  }
-
-  fflush(out);
-}
-
-static void pr_matrix(FILE *fp,int indent,const char *title,rvec *m,
-                     gmx_bool bMDPformat)
-{
-  if (bMDPformat)
-    fprintf(fp,"%-10s    = %g %g %g %g %g %g\n",title,
-           m[XX][XX],m[YY][YY],m[ZZ][ZZ],m[XX][YY],m[XX][ZZ],m[YY][ZZ]);
-  else
-    pr_rvecs(fp,indent,title,m,DIM);
-}
-
-static void pr_cosine(FILE *fp,int indent,const char *title,t_cosines *cos,
-                     gmx_bool bMDPformat)
-{
-  int j;
-  
-  if (bMDPformat) {
-    fprintf(fp,"%s = %d\n",title,cos->n);
-  }
-  else {
-    indent=pr_title(fp,indent,title);
-    (void) pr_indent(fp,indent);
-    fprintf(fp,"n = %d\n",cos->n);
-    if (cos->n > 0) {
-      (void) pr_indent(fp,indent+2);
-      fprintf(fp,"a =");
-      for(j=0; (j<cos->n); j++)
-       fprintf(fp," %e",cos->a[j]);
-      fprintf(fp,"\n");
-      (void) pr_indent(fp,indent+2);
-      fprintf(fp,"phi =");
-      for(j=0; (j<cos->n); j++)
-       fprintf(fp," %e",cos->phi[j]);
-      fprintf(fp,"\n");
-    }
-  }
-}
-
-#define PS(t,s) pr_str(fp,indent,t,s)
-#define PI(t,s) pr_int(fp,indent,t,s)
-#define PSTEP(t,s) pr_gmx_large_int(fp,indent,t,s)
-#define PR(t,s) pr_real(fp,indent,t,s)
-#define PD(t,s) pr_double(fp,indent,t,s)
-
-static void pr_pullgrp(FILE *fp,int indent,int g,t_pullgrp *pg)
-{
-  pr_indent(fp,indent);
-  fprintf(fp,"pull_group %d:\n",g);
-  indent += 2;
-  pr_ivec_block(fp,indent,"atom",pg->ind,pg->nat,TRUE);
-  pr_rvec(fp,indent,"weight",pg->weight,pg->nweight,TRUE);
-  PI("pbcatom",pg->pbcatom);
-  pr_rvec(fp,indent,"vec",pg->vec,DIM,TRUE);
-  pr_rvec(fp,indent,"init",pg->init,DIM,TRUE);
-  PR("rate",pg->rate);
-  PR("k",pg->k);
-  PR("kB",pg->kB);
-}
-
-static void pr_pull(FILE *fp,int indent,t_pull *pull)
-{
-  int g;
-
-  PS("pull_geometry",EPULLGEOM(pull->eGeom));
-  pr_ivec(fp,indent,"pull_dim",pull->dim,DIM,TRUE);
-  PR("pull_r1",pull->cyl_r1);
-  PR("pull_r0",pull->cyl_r0);
-  PR("pull_constr_tol",pull->constr_tol);
-  PI("pull_nstxout",pull->nstxout);
-  PI("pull_nstfout",pull->nstfout);
-  PI("pull_ngrp",pull->ngrp);
-  for(g=0; g<pull->ngrp+1; g++)
-    pr_pullgrp(fp,indent,g,&pull->grp[g]);
-}
-
-void pr_inputrec(FILE *fp,int indent,const char *title,t_inputrec *ir,
-                 gmx_bool bMDPformat)
-{
-  const char *infbuf="inf";
-  int  i;
-  
-  if (available(fp,ir,indent,title)) {
-    if (!bMDPformat)
-      indent=pr_title(fp,indent,title);
-    PS("integrator",EI(ir->eI));
-    PSTEP("nsteps",ir->nsteps);
-    PSTEP("init_step",ir->init_step);
-    PS("ns_type",ENS(ir->ns_type));
-    PI("nstlist",ir->nstlist);
-    PI("ndelta",ir->ndelta);
-    PI("nstcomm",ir->nstcomm);
-    PS("comm_mode",ECOM(ir->comm_mode));
-    PI("nstlog",ir->nstlog);
-    PI("nstxout",ir->nstxout);
-    PI("nstvout",ir->nstvout);
-    PI("nstfout",ir->nstfout);
-    PI("nstcalcenergy",ir->nstcalcenergy);
-    PI("nstenergy",ir->nstenergy);
-    PI("nstxtcout",ir->nstxtcout);
-    PR("init_t",ir->init_t);
-    PR("delta_t",ir->delta_t);
-    
-    PR("xtcprec",ir->xtcprec);
-    PI("nkx",ir->nkx);
-    PI("nky",ir->nky);
-    PI("nkz",ir->nkz);
-    PI("pme_order",ir->pme_order);
-    PR("ewald_rtol",ir->ewald_rtol);
-    PR("ewald_geometry",ir->ewald_geometry);
-    PR("epsilon_surface",ir->epsilon_surface);
-    PS("optimize_fft",BOOL(ir->bOptFFT));
-    PS("ePBC",EPBC(ir->ePBC));
-    PS("bPeriodicMols",BOOL(ir->bPeriodicMols));
-    PS("bContinuation",BOOL(ir->bContinuation));
-    PS("bShakeSOR",BOOL(ir->bShakeSOR));
-    PS("etc",ETCOUPLTYPE(ir->etc));
-    PI("nsttcouple",ir->nsttcouple);
-    PS("epc",EPCOUPLTYPE(ir->epc));
-    PS("epctype",EPCOUPLTYPETYPE(ir->epct));
-    PI("nstpcouple",ir->nstpcouple);
-    PR("tau_p",ir->tau_p);
-    pr_matrix(fp,indent,"ref_p",ir->ref_p,bMDPformat);
-    pr_matrix(fp,indent,"compress",ir->compress,bMDPformat);
-    PS("refcoord_scaling",EREFSCALINGTYPE(ir->refcoord_scaling));
-    if (bMDPformat)
-      fprintf(fp,"posres_com  = %g %g %g\n",ir->posres_com[XX],
-             ir->posres_com[YY],ir->posres_com[ZZ]);
-    else
-      pr_rvec(fp,indent,"posres_com",ir->posres_com,DIM,TRUE);
-    if (bMDPformat)
-      fprintf(fp,"posres_comB = %g %g %g\n",ir->posres_comB[XX],
-             ir->posres_comB[YY],ir->posres_comB[ZZ]);
-    else
-      pr_rvec(fp,indent,"posres_comB",ir->posres_comB,DIM,TRUE);
-    PI("andersen_seed",ir->andersen_seed);
-    PR("rlist",ir->rlist);
-    PR("rlistlong",ir->rlistlong);
-    PR("rtpi",ir->rtpi);
-    PS("coulombtype",EELTYPE(ir->coulombtype));
-    PR("rcoulomb_switch",ir->rcoulomb_switch);
-    PR("rcoulomb",ir->rcoulomb);
-    PS("vdwtype",EVDWTYPE(ir->vdwtype));
-    PR("rvdw_switch",ir->rvdw_switch);
-    PR("rvdw",ir->rvdw);
-    if (ir->epsilon_r != 0)
-      PR("epsilon_r",ir->epsilon_r);
-    else
-      PS("epsilon_r",infbuf);
-    if (ir->epsilon_rf != 0)
-      PR("epsilon_rf",ir->epsilon_rf);
-    else
-      PS("epsilon_rf",infbuf);
-    PR("tabext",ir->tabext);
-    PS("implicit_solvent",EIMPLICITSOL(ir->implicit_solvent));
-    PS("gb_algorithm",EGBALGORITHM(ir->gb_algorithm));
-    PR("gb_epsilon_solvent",ir->gb_epsilon_solvent);
-    PI("nstgbradii",ir->nstgbradii);
-    PR("rgbradii",ir->rgbradii);
-    PR("gb_saltconc",ir->gb_saltconc);
-    PR("gb_obc_alpha",ir->gb_obc_alpha);
-    PR("gb_obc_beta",ir->gb_obc_beta);
-    PR("gb_obc_gamma",ir->gb_obc_gamma);
-    PR("gb_dielectric_offset",ir->gb_dielectric_offset);
-    PS("sa_algorithm",ESAALGORITHM(ir->gb_algorithm));
-    PR("sa_surface_tension",ir->sa_surface_tension);
-         
-    PS("DispCorr",EDISPCORR(ir->eDispCorr));
-    PS("free_energy",EFEPTYPE(ir->efep));
-    PR("init_lambda",ir->init_lambda);
-    PR("delta_lambda",ir->delta_lambda);
-    if (!bMDPformat)
-    {
-        PI("n_foreign_lambda",ir->n_flambda);
-    }
-    if (ir->n_flambda > 0)
-    {
-        pr_indent(fp,indent);
-        fprintf(fp,"foreign_lambda%s",bMDPformat ? " = " : ":");
-        for(i=0; i<ir->n_flambda; i++)
-        {
-            fprintf(fp,"  %10g",ir->flambda[i]);
-        }
-        fprintf(fp,"\n");
-    }
-    PR("sc_alpha",ir->sc_alpha);
-    PI("sc_power",ir->sc_power);
-    PR("sc_sigma",ir->sc_sigma);
-    PR("sc_sigma_min",ir->sc_sigma_min);
-    PI("nstdhdl", ir->nstdhdl);
-    PS("separate_dhdl_file", SEPDHDLFILETYPE(ir->separate_dhdl_file));
-    PS("dhdl_derivatives", DHDLDERIVATIVESTYPE(ir->dhdl_derivatives));
-    PI("dh_hist_size", ir->dh_hist_size);
-    PD("dh_hist_spacing", ir->dh_hist_spacing);
-
-    PI("nwall",ir->nwall);
-    PS("wall_type",EWALLTYPE(ir->wall_type));
-    PI("wall_atomtype[0]",ir->wall_atomtype[0]);
-    PI("wall_atomtype[1]",ir->wall_atomtype[1]);
-    PR("wall_density[0]",ir->wall_density[0]);
-    PR("wall_density[1]",ir->wall_density[1]);
-    PR("wall_ewald_zfac",ir->wall_ewald_zfac);
-
-    PS("pull",EPULLTYPE(ir->ePull));
-    if (ir->ePull != epullNO)
-      pr_pull(fp,indent,ir->pull);
-
-    PS("disre",EDISRETYPE(ir->eDisre));
-    PS("disre_weighting",EDISREWEIGHTING(ir->eDisreWeighting));
-    PS("disre_mixed",BOOL(ir->bDisreMixed));
-    PR("dr_fc",ir->dr_fc);
-    PR("dr_tau",ir->dr_tau);
-    PR("nstdisreout",ir->nstdisreout);
-    PR("orires_fc",ir->orires_fc);
-    PR("orires_tau",ir->orires_tau);
-    PR("nstorireout",ir->nstorireout);
-
-    PR("dihre-fc",ir->dihre_fc);
-    
-    PR("em_stepsize",ir->em_stepsize);
-    PR("em_tol",ir->em_tol);
-    PI("niter",ir->niter);
-    PR("fc_stepsize",ir->fc_stepsize);
-    PI("nstcgsteep",ir->nstcgsteep);
-    PI("nbfgscorr",ir->nbfgscorr);
-
-    PS("ConstAlg",ECONSTRTYPE(ir->eConstrAlg));
-    PR("shake_tol",ir->shake_tol);
-    PI("lincs_order",ir->nProjOrder);
-    PR("lincs_warnangle",ir->LincsWarnAngle);
-    PI("lincs_iter",ir->nLincsIter);
-    PR("bd_fric",ir->bd_fric);
-    PI("ld_seed",ir->ld_seed);
-    PR("cos_accel",ir->cos_accel);
-    pr_matrix(fp,indent,"deform",ir->deform,bMDPformat);
-    PI("userint1",ir->userint1);
-    PI("userint2",ir->userint2);
-    PI("userint3",ir->userint3);
-    PI("userint4",ir->userint4);
-    PR("userreal1",ir->userreal1);
-    PR("userreal2",ir->userreal2);
-    PR("userreal3",ir->userreal3);
-    PR("userreal4",ir->userreal4);
-    pr_grp_opts(fp,indent,"grpopts",&(ir->opts),bMDPformat);
-    pr_cosine(fp,indent,"efield-x",&(ir->ex[XX]),bMDPformat);
-    pr_cosine(fp,indent,"efield-xt",&(ir->et[XX]),bMDPformat);
-    pr_cosine(fp,indent,"efield-y",&(ir->ex[YY]),bMDPformat);
-    pr_cosine(fp,indent,"efield-yt",&(ir->et[YY]),bMDPformat);
-    pr_cosine(fp,indent,"efield-z",&(ir->ex[ZZ]),bMDPformat);
-    pr_cosine(fp,indent,"efield-zt",&(ir->et[ZZ]),bMDPformat);
-    PS("bQMMM",BOOL(ir->bQMMM));
-    PI("QMconstraints",ir->QMconstraints);
-    PI("QMMMscheme",ir->QMMMscheme);
-    PR("scalefactor",ir->scalefactor);
-    pr_qm_opts(fp,indent,"qm_opts",&(ir->opts));
-  }
-}
-#undef PS
-#undef PR
-#undef PI
-
-static void pr_harm(FILE *fp,t_iparams *iparams,const char *r,const char *kr)
-{
-  fprintf(fp,"%sA=%12.5e, %sA=%12.5e, %sB=%12.5e, %sB=%12.5e\n",
-         r,iparams->harmonic.rA,kr,iparams->harmonic.krA,
-         r,iparams->harmonic.rB,kr,iparams->harmonic.krB);
-}
-
-void pr_iparams(FILE *fp,t_functype ftype,t_iparams *iparams)
-{
-  int i;
-  real VA[4],VB[4],*rbcA,*rbcB;
-
-  switch (ftype) {
-  case F_ANGLES:
-  case F_G96ANGLES:
-    pr_harm(fp,iparams,"th","ct");
-    break;
-  case F_CROSS_BOND_BONDS:
-    fprintf(fp,"r1e=%15.8e, r2e=%15.8e, krr=%15.8e\n",
-           iparams->cross_bb.r1e,iparams->cross_bb.r2e,
-           iparams->cross_bb.krr);
-    break;
-  case F_CROSS_BOND_ANGLES:
-    fprintf(fp,"r1e=%15.8e, r1e=%15.8e, r3e=%15.8e, krt=%15.8e\n",
-           iparams->cross_ba.r1e,iparams->cross_ba.r2e,
-           iparams->cross_ba.r3e,iparams->cross_ba.krt);
-    break;
-  case F_UREY_BRADLEY:
-    fprintf(fp,"theta=%15.8e, ktheta=%15.8e, r13=%15.8e, kUB=%15.8e\n",
-           iparams->u_b.theta,iparams->u_b.ktheta,iparams->u_b.r13,iparams->u_b.kUB);
-    break;
-  case F_QUARTIC_ANGLES:
-    fprintf(fp,"theta=%15.8e",iparams->qangle.theta);
-    for(i=0; i<5; i++)
-      fprintf(fp,", c%c=%15.8e",'0'+i,iparams->qangle.c[i]);
-    fprintf(fp,"\n");
-    break;
-  case F_BHAM:
-    fprintf(fp,"a=%15.8e, b=%15.8e, c=%15.8e\n",
-           iparams->bham.a,iparams->bham.b,iparams->bham.c);
-    break;
-  case F_BONDS:
-  case F_G96BONDS:
-  case F_HARMONIC:
-    pr_harm(fp,iparams,"b0","cb");
-    break;
-  case F_IDIHS:
-    pr_harm(fp,iparams,"xi","cx");
-    break;
-  case F_MORSE:
-    fprintf(fp,"b0=%15.8e, cb=%15.8e, beta=%15.8e\n",
-           iparams->morse.b0,iparams->morse.cb,iparams->morse.beta);
-    break;
-  case F_CUBICBONDS:
-    fprintf(fp,"b0=%15.8e, kb=%15.8e, kcub=%15.8e\n",
-           iparams->cubic.b0,iparams->cubic.kb,iparams->cubic.kcub);
-    break;
-  case F_CONNBONDS:
-    fprintf(fp,"\n");
-    break;
-  case F_FENEBONDS:
-    fprintf(fp,"bm=%15.8e, kb=%15.8e\n",iparams->fene.bm,iparams->fene.kb);
-    break;
-  case F_RESTRBONDS:
-      fprintf(fp,"lowA=%15.8e, up1A=%15.8e, up2A=%15.8e, kA=%15.8e, lowB=%15.8e, up1B=%15.8e, up2B=%15.8e, kB=%15.8e,\n",
-              iparams->restraint.lowA,iparams->restraint.up1A,
-              iparams->restraint.up2A,iparams->restraint.kA,
-              iparams->restraint.lowB,iparams->restraint.up1B,
-              iparams->restraint.up2B,iparams->restraint.kB);
-      break;
-  case F_TABBONDS:
-  case F_TABBONDSNC:
-  case F_TABANGLES:
-  case F_TABDIHS:
-    fprintf(fp,"tab=%d, kA=%15.8e, kB=%15.8e\n",
-           iparams->tab.table,iparams->tab.kA,iparams->tab.kB);
-    break;
-  case F_POLARIZATION:
-    fprintf(fp,"alpha=%15.8e\n",iparams->polarize.alpha);
-    break;
-  case F_THOLE_POL:
-    fprintf(fp,"a=%15.8e, alpha1=%15.8e, alpha2=%15.8e, rfac=%15.8e\n",
-           iparams->thole.a,iparams->thole.alpha1,iparams->thole.alpha2,
-           iparams->thole.rfac);
-    break;
-  case F_WATER_POL:
-    fprintf(fp,"al_x=%15.8e, al_y=%15.8e, al_z=%15.8e, rOH=%9.6f, rHH=%9.6f, rOD=%9.6f\n",
-           iparams->wpol.al_x,iparams->wpol.al_y,iparams->wpol.al_z,
-           iparams->wpol.rOH,iparams->wpol.rHH,iparams->wpol.rOD);
-    break;
-  case F_LJ:
-    fprintf(fp,"c6=%15.8e, c12=%15.8e\n",iparams->lj.c6,iparams->lj.c12);
-    break;
-  case F_LJ14:
-    fprintf(fp,"c6A=%15.8e, c12A=%15.8e, c6B=%15.8e, c12B=%15.8e\n",
-           iparams->lj14.c6A,iparams->lj14.c12A,
-           iparams->lj14.c6B,iparams->lj14.c12B);
-    break;
-  case F_LJC14_Q:
-    fprintf(fp,"fqq=%15.8e, qi=%15.8e, qj=%15.8e, c6=%15.8e, c12=%15.8e\n",
-           iparams->ljc14.fqq,
-           iparams->ljc14.qi,iparams->ljc14.qj,
-           iparams->ljc14.c6,iparams->ljc14.c12);
-    break;
-  case F_LJC_PAIRS_NB:
-    fprintf(fp,"qi=%15.8e, qj=%15.8e, c6=%15.8e, c12=%15.8e\n",
-           iparams->ljcnb.qi,iparams->ljcnb.qj,
-           iparams->ljcnb.c6,iparams->ljcnb.c12);
-    break;
-  case F_PDIHS:
-  case F_PIDIHS:
-  case F_ANGRES:
-  case F_ANGRESZ:
-    fprintf(fp,"phiA=%15.8e, cpA=%15.8e, phiB=%15.8e, cpB=%15.8e, mult=%d\n",
-           iparams->pdihs.phiA,iparams->pdihs.cpA,
-           iparams->pdihs.phiB,iparams->pdihs.cpB,
-           iparams->pdihs.mult);
-    break;
-  case F_DISRES:
-    fprintf(fp,"label=%4d, type=%1d, low=%15.8e, up1=%15.8e, up2=%15.8e, fac=%15.8e)\n",
-           iparams->disres.label,iparams->disres.type,
-           iparams->disres.low,iparams->disres.up1,
-           iparams->disres.up2,iparams->disres.kfac);
-    break;
-  case F_ORIRES:
-    fprintf(fp,"ex=%4d, label=%d, power=%4d, c=%15.8e, obs=%15.8e, kfac=%15.8e)\n",
-           iparams->orires.ex,iparams->orires.label,iparams->orires.power,
-           iparams->orires.c,iparams->orires.obs,iparams->orires.kfac);
-    break;
-  case F_DIHRES:
-    fprintf(fp,"label=%d, power=%4d phi=%15.8e, dphi=%15.8e, kfac=%15.8e)\n",
-           iparams->dihres.label,iparams->dihres.power,
-           iparams->dihres.phi,iparams->dihres.dphi,iparams->dihres.kfac);
-    break;
-  case F_POSRES:
-    fprintf(fp,"pos0A=(%15.8e,%15.8e,%15.8e), fcA=(%15.8e,%15.8e,%15.8e), pos0B=(%15.8e,%15.8e,%15.8e), fcB=(%15.8e,%15.8e,%15.8e)\n",
-           iparams->posres.pos0A[XX],iparams->posres.pos0A[YY],
-           iparams->posres.pos0A[ZZ],iparams->posres.fcA[XX],
-           iparams->posres.fcA[YY],iparams->posres.fcA[ZZ],
-           iparams->posres.pos0B[XX],iparams->posres.pos0B[YY],
-           iparams->posres.pos0B[ZZ],iparams->posres.fcB[XX],
-           iparams->posres.fcB[YY],iparams->posres.fcB[ZZ]);
-    break;
-  case F_RBDIHS:
-    for (i=0; i<NR_RBDIHS; i++) 
-      fprintf(fp,"%srbcA[%d]=%15.8e",i==0?"":", ",i,iparams->rbdihs.rbcA[i]);
-    fprintf(fp,"\n");
-    for (i=0; i<NR_RBDIHS; i++) 
-      fprintf(fp,"%srbcB[%d]=%15.8e",i==0?"":", ",i,iparams->rbdihs.rbcB[i]);
-    fprintf(fp,"\n");
-    break;
-  case F_FOURDIHS:
-    /* Use the OPLS -> Ryckaert-Bellemans formula backwards to get the
-     * OPLS potential constants back.
-     */
-    rbcA = iparams->rbdihs.rbcA;
-    rbcB = iparams->rbdihs.rbcB;
-
-    VA[3] = -0.25*rbcA[4];
-    VA[2] = -0.5*rbcA[3];
-    VA[1] = 4.0*VA[3]-rbcA[2];
-    VA[0] = 3.0*VA[2]-2.0*rbcA[1];
-
-    VB[3] = -0.25*rbcB[4];
-    VB[2] = -0.5*rbcB[3];
-    VB[1] = 4.0*VB[3]-rbcB[2];
-    VB[0] = 3.0*VB[2]-2.0*rbcB[1];
-
-    for (i=0; i<NR_FOURDIHS; i++) 
-      fprintf(fp,"%sFourA[%d]=%15.8e",i==0?"":", ",i,VA[i]);
-    fprintf(fp,"\n");
-    for (i=0; i<NR_FOURDIHS; i++) 
-      fprintf(fp,"%sFourB[%d]=%15.8e",i==0?"":", ",i,VB[i]);
-    fprintf(fp,"\n");
-    break;
-   
-  case F_CONSTR:
-  case F_CONSTRNC:
-    fprintf(fp,"dA=%15.8e, dB=%15.8e\n",iparams->constr.dA,iparams->constr.dB);
-    break;
-  case F_SETTLE:
-    fprintf(fp,"doh=%15.8e, dhh=%15.8e\n",iparams->settle.doh,
-           iparams->settle.dhh);
-    break;
-  case F_VSITE2:
-    fprintf(fp,"a=%15.8e\n",iparams->vsite.a);
-    break;
-  case F_VSITE3:
-  case F_VSITE3FD:
-  case F_VSITE3FAD:
-    fprintf(fp,"a=%15.8e, b=%15.8e\n",iparams->vsite.a,iparams->vsite.b);
-    break;
-  case F_VSITE3OUT:
-  case F_VSITE4FD:
-  case F_VSITE4FDN:
-    fprintf(fp,"a=%15.8e, b=%15.8e, c=%15.8e\n",
-           iparams->vsite.a,iparams->vsite.b,iparams->vsite.c);
-    break;
-  case F_VSITEN:
-    fprintf(fp,"n=%2d, a=%15.8e\n",iparams->vsiten.n,iparams->vsiten.a);
-    break;
-  case F_GB12:
-  case F_GB13:
-  case F_GB14:
-    fprintf(fp, "sar=%15.8e, st=%15.8e, pi=%15.8e, gbr=%15.8e, bmlt=%15.8e\n",iparams->gb.sar,iparams->gb.st,iparams->gb.pi,iparams->gb.gbr,iparams->gb.bmlt);
-    break;               
-  case F_CMAP:
-    fprintf(fp, "cmapA=%1d, cmapB=%1d\n",iparams->cmap.cmapA, iparams->cmap.cmapB);
-    break;               
-  default:
-    gmx_fatal(FARGS,"unknown function type %d (%s) in %s line %d",
-             ftype,interaction_function[ftype].name,__FILE__,__LINE__);
-  }
-}
-
-void pr_ilist(FILE *fp,int indent,const char *title,
-              t_functype *functype,t_ilist *ilist, gmx_bool bShowNumbers)
-{
-    int i,j,k,type,ftype;
-    t_iatom *iatoms;
-    
-    if (available(fp,ilist,indent,title) && ilist->nr > 0)
-    {  
-        indent=pr_title(fp,indent,title);
-        (void) pr_indent(fp,indent);
-        fprintf(fp,"nr: %d\n",ilist->nr);
-        if (ilist->nr > 0) {
-            (void) pr_indent(fp,indent);
-            fprintf(fp,"iatoms:\n");
-            iatoms=ilist->iatoms;
-            for (i=j=0; i<ilist->nr;) {
-#ifndef DEBUG
-                (void) pr_indent(fp,indent+INDENT);
-                type=*(iatoms++);
-                ftype=functype[type];
-                (void) fprintf(fp,"%d type=%d (%s)",
-                               bShowNumbers?j:-1,bShowNumbers?type:-1,
-                               interaction_function[ftype].name);
-                j++;
-                for (k=0; k<interaction_function[ftype].nratoms; k++)
-                    (void) fprintf(fp," %u",*(iatoms++));
-                (void) fprintf(fp,"\n");
-                i+=1+interaction_function[ftype].nratoms;
-#else
-                fprintf(fp,"%5d%5d\n",i,iatoms[i]);
-                i++;
-#endif
-            }
-        }
-    }
-}
-
-static void pr_cmap(FILE *fp, int indent, const char *title,
-                    gmx_cmap_t *cmap_grid, gmx_bool bShowNumbers)
-{
-    int i,j,nelem;
-    real dx,idx;
-       
-    dx    = 360.0 / cmap_grid->grid_spacing;
-    nelem = cmap_grid->grid_spacing*cmap_grid->grid_spacing;
-       
-    if(available(fp,cmap_grid,indent,title))
-    {
-        fprintf(fp,"%s\n",title);
-               
-        for(i=0;i<cmap_grid->ngrid;i++)
-        {
-            idx = -180.0;
-            fprintf(fp,"%8s %8s %8s %8s\n","V","dVdx","dVdy","d2dV");
-                       
-            fprintf(fp,"grid[%3d]={\n",bShowNumbers?i:-1);
-                       
-            for(j=0;j<nelem;j++)
-            {
-                if( (j%cmap_grid->grid_spacing)==0)
-                {
-                    fprintf(fp,"%8.1f\n",idx);
-                    idx+=dx;
-                }
-                               
-                fprintf(fp,"%8.3f ",cmap_grid->cmapdata[i].cmap[j*4]);
-                fprintf(fp,"%8.3f ",cmap_grid->cmapdata[i].cmap[j*4+1]);
-                fprintf(fp,"%8.3f ",cmap_grid->cmapdata[i].cmap[j*4+2]);
-                fprintf(fp,"%8.3f\n",cmap_grid->cmapdata[i].cmap[j*4+3]);
-            }
-            fprintf(fp,"\n");
-        }
-    }
-       
-}
-
-void pr_ffparams(FILE *fp,int indent,const char *title,
-                 gmx_ffparams_t *ffparams,
-                 gmx_bool bShowNumbers)
-{
-  int i,j;
-  
-  indent=pr_title(fp,indent,title);
-  (void) pr_indent(fp,indent);
-  (void) fprintf(fp,"atnr=%d\n",ffparams->atnr);
-  (void) pr_indent(fp,indent);
-  (void) fprintf(fp,"ntypes=%d\n",ffparams->ntypes);
-  for (i=0; i<ffparams->ntypes; i++) {
-      (void) pr_indent(fp,indent+INDENT);
-      (void) fprintf(fp,"functype[%d]=%s, ",
-                     bShowNumbers?i:-1,
-                     interaction_function[ffparams->functype[i]].name);
-      pr_iparams(fp,ffparams->functype[i],&ffparams->iparams[i]);
-  }
-  (void) pr_double(fp,indent,"reppow",ffparams->reppow);
-  (void) pr_real(fp,indent,"fudgeQQ",ffparams->fudgeQQ);
-  pr_cmap(fp,indent,"cmap",&ffparams->cmap_grid,bShowNumbers);
-}
-
-void pr_idef(FILE *fp,int indent,const char *title,t_idef *idef, gmx_bool bShowNumbers)
-{
-  int i,j;
-  
-  if (available(fp,idef,indent,title)) {  
-    indent=pr_title(fp,indent,title);
-    (void) pr_indent(fp,indent);
-    (void) fprintf(fp,"atnr=%d\n",idef->atnr);
-    (void) pr_indent(fp,indent);
-    (void) fprintf(fp,"ntypes=%d\n",idef->ntypes);
-    for (i=0; i<idef->ntypes; i++) {
-      (void) pr_indent(fp,indent+INDENT);
-      (void) fprintf(fp,"functype[%d]=%s, ",
-                    bShowNumbers?i:-1,
-                    interaction_function[idef->functype[i]].name);
-      pr_iparams(fp,idef->functype[i],&idef->iparams[i]);
-    }
-    (void) pr_real(fp,indent,"fudgeQQ",idef->fudgeQQ);
-
-    for(j=0; (j<F_NRE); j++)
-      pr_ilist(fp,indent,interaction_function[j].longname,
-               idef->functype,&idef->il[j],bShowNumbers);
-  }
-}
-
-static int pr_block_title(FILE *fp,int indent,const char *title,t_block *block)
-{
-  int i;
-
-  if (available(fp,block,indent,title))
-    {
-      indent=pr_title(fp,indent,title);
-      (void) pr_indent(fp,indent);
-      (void) fprintf(fp,"nr=%d\n",block->nr);
-    }
-  return indent;
-}
-
-static int pr_blocka_title(FILE *fp,int indent,const char *title,t_blocka *block)
-{
-  int i;
-
-  if (available(fp,block,indent,title))
-    {
-      indent=pr_title(fp,indent,title);
-      (void) pr_indent(fp,indent);
-      (void) fprintf(fp,"nr=%d\n",block->nr);
-      (void) pr_indent(fp,indent);
-      (void) fprintf(fp,"nra=%d\n",block->nra);
-    }
-  return indent;
-}
-
-static void low_pr_block(FILE *fp,int indent,const char *title,t_block *block, gmx_bool bShowNumbers)
-{
-  int i;
-  
-  if (available(fp,block,indent,title))
-    {
-      indent=pr_block_title(fp,indent,title,block);
-      for (i=0; i<=block->nr; i++)
-        {
-          (void) pr_indent(fp,indent+INDENT);
-          (void) fprintf(fp,"%s->index[%d]=%u\n",
-                        title,bShowNumbers?i:-1,block->index[i]);
-        }
-    }
-}
-
-static void low_pr_blocka(FILE *fp,int indent,const char *title,t_blocka *block, gmx_bool bShowNumbers)
-{
-  int i;
-  
-  if (available(fp,block,indent,title))
-    {
-      indent=pr_blocka_title(fp,indent,title,block);
-      for (i=0; i<=block->nr; i++)
-        {
-          (void) pr_indent(fp,indent+INDENT);
-          (void) fprintf(fp,"%s->index[%d]=%u\n",
-                        title,bShowNumbers?i:-1,block->index[i]);
-        }
-      for (i=0; i<block->nra; i++)
-        {
-          (void) pr_indent(fp,indent+INDENT);
-          (void) fprintf(fp,"%s->a[%d]=%u\n",
-                        title,bShowNumbers?i:-1,block->a[i]);
-        }
-    }
-}
-
-void pr_block(FILE *fp,int indent,const char *title,t_block *block,gmx_bool bShowNumbers)
-{
-  int i,j,ok,size,start,end;
-  
-  if (available(fp,block,indent,title))
-    {
-      indent=pr_block_title(fp,indent,title,block);
-      start=0;
-      end=start;
-      if ((ok=(block->index[start]==0))==0)
-        (void) fprintf(fp,"block->index[%d] should be 0\n",start);
-      else
-        for (i=0; i<block->nr; i++)
-          {
-            end=block->index[i+1];
-            size=pr_indent(fp,indent);
-            if (end<=start)
-              size+=fprintf(fp,"%s[%d]={}\n",title,i);
-            else
-              size+=fprintf(fp,"%s[%d]={%d..%d}\n",
-                           title,bShowNumbers?i:-1,
-                           bShowNumbers?start:-1,bShowNumbers?end-1:-1);
-            start=end;
-          }
-    }
-}
-
-void pr_blocka(FILE *fp,int indent,const char *title,t_blocka *block,gmx_bool bShowNumbers)
-{
-  int i,j,ok,size,start,end;
-  
-  if (available(fp,block,indent,title))
-    {
-      indent=pr_blocka_title(fp,indent,title,block);
-      start=0;
-      end=start;
-      if ((ok=(block->index[start]==0))==0)
-        (void) fprintf(fp,"block->index[%d] should be 0\n",start);
-      else
-        for (i=0; i<block->nr; i++)
-          {
-            end=block->index[i+1];
-            size=pr_indent(fp,indent);
-            if (end<=start)
-              size+=fprintf(fp,"%s[%d]={",title,i);
-            else
-              size+=fprintf(fp,"%s[%d][%d..%d]={",
-                           title,bShowNumbers?i:-1,
-                           bShowNumbers?start:-1,bShowNumbers?end-1:-1);
-            for (j=start; j<end; j++)
-              {
-                if (j>start) size+=fprintf(fp,", ");
-                if ((size)>(USE_WIDTH))
-                  {
-                    (void) fprintf(fp,"\n");
-                    size=pr_indent(fp,indent+INDENT);
-                  }
-                size+=fprintf(fp,"%u",block->a[j]);
-              }
-            (void) fprintf(fp,"}\n");
-            start=end;
-          }
-      if ((end!=block->nra)||(!ok)) 
-        {
-          (void) pr_indent(fp,indent);
-          (void) fprintf(fp,"tables inconsistent, dumping complete tables:\n");
-          low_pr_blocka(fp,indent,title,block,bShowNumbers);
-        }
-    }
-}
-
-static void pr_strings(FILE *fp,int indent,const char *title,char ***nm,int n, gmx_bool bShowNumbers)
-{
-  int i;
-
-  if (available(fp,nm,indent,title))
-    {  
-      indent=pr_title_n(fp,indent,title,n);
-      for (i=0; i<n; i++)
-        {
-          (void) pr_indent(fp,indent);
-          (void) fprintf(fp,"%s[%d]={name=\"%s\"}\n",
-                        title,bShowNumbers?i:-1,*(nm[i]));
-        }
-    }
-}
-
-static void pr_strings2(FILE *fp,int indent,const char *title,
-                       char ***nm,char ***nmB,int n, gmx_bool bShowNumbers)
-{
-  int i;
-
-  if (available(fp,nm,indent,title))
-    {  
-      indent=pr_title_n(fp,indent,title,n);
-      for (i=0; i<n; i++)
-        {
-          (void) pr_indent(fp,indent);
-          (void) fprintf(fp,"%s[%d]={name=\"%s\",nameB=\"%s\"}\n",
-                        title,bShowNumbers?i:-1,*(nm[i]),*(nmB[i]));
-        }
-    }
-}
-
-static void pr_resinfo(FILE *fp,int indent,const char *title,t_resinfo *resinfo,int n, gmx_bool bShowNumbers)
-{
-    int i;
-    
-    if (available(fp,resinfo,indent,title))
-    {  
-        indent=pr_title_n(fp,indent,title,n);
-        for (i=0; i<n; i++)
-        {
-            (void) pr_indent(fp,indent);
-            (void) fprintf(fp,"%s[%d]={name=\"%s\", nr=%d, ic='%c'}\n",
-                           title,bShowNumbers?i:-1,
-                           *(resinfo[i].name),resinfo[i].nr,
-                           (resinfo[i].ic == '\0') ? ' ' : resinfo[i].ic);
-        }
-    }
-}
-
-static void pr_atom(FILE *fp,int indent,const char *title,t_atom *atom,int n)
-{
-  int i,j;
-  
-  if (available(fp,atom,indent,title)) {  
-    indent=pr_title_n(fp,indent,title,n);
-    for (i=0; i<n; i++) {
-      (void) pr_indent(fp,indent);
-      fprintf(fp,"%s[%6d]={type=%3d, typeB=%3d, ptype=%8s, m=%12.5e, "
-              "q=%12.5e, mB=%12.5e, qB=%12.5e, resind=%5d, atomnumber=%3d}\n",
-              title,i,atom[i].type,atom[i].typeB,ptype_str[atom[i].ptype],
-              atom[i].m,atom[i].q,atom[i].mB,atom[i].qB,
-              atom[i].resind,atom[i].atomnumber);
-    }
-  }
-}
-
-static void pr_grps(FILE *fp,int indent,const char *title,t_grps grps[],
-                   char **grpname[], gmx_bool bShowNumbers)
-{
-    int i,j;
-
-    for(i=0; (i<egcNR); i++)
-    {
-        fprintf(fp,"%s[%-12s] nr=%d, name=[",title,gtypes[i],grps[i].nr);
-        for(j=0; (j<grps[i].nr); j++)
-        {
-            fprintf(fp," %s",*(grpname[grps[i].nm_ind[j]]));
-        }
-        fprintf(fp,"]\n");
-    }
-}
-
-static void pr_groups(FILE *fp,int indent,const char *title,
-                      gmx_groups_t *groups,
-                      gmx_bool bShowNumbers)
-{
-    int grpnr[egcNR];
-    int nat_max,i,g;
-
-    pr_grps(fp,indent,"grp",groups->grps,groups->grpname,bShowNumbers);
-    pr_strings(fp,indent,"grpname",groups->grpname,groups->ngrpname,bShowNumbers);
-
-    (void) pr_indent(fp,indent);
-    fprintf(fp,"groups          ");
-    for(g=0; g<egcNR; g++)
-    {
-       printf(" %5.5s",gtypes[g]);
-    }
-    printf("\n");
-
-    (void) pr_indent(fp,indent);
-    fprintf(fp,"allocated       ");
-    nat_max = 0;
-    for(g=0; g<egcNR; g++)
-    {
-        printf(" %5d",groups->ngrpnr[g]);
-        nat_max = max(nat_max,groups->ngrpnr[g]);
-    }
-    printf("\n");
-
-    if (nat_max == 0)
-    {
-        (void) pr_indent(fp,indent);
-        fprintf(fp,"groupnr[%5s] =","*");
-        for(g=0; g<egcNR; g++)
-        {
-            fprintf(fp,"  %3d ",0);
-        }
-        fprintf(fp,"\n");
-    }
-    else
-    {
-        for(i=0; i<nat_max; i++)
-        {
-            (void) pr_indent(fp,indent);
-            fprintf(fp,"groupnr[%5d] =",i);
-            for(g=0; g<egcNR; g++)
-            {
-                fprintf(fp,"  %3d ",
-                        groups->grpnr[g] ? groups->grpnr[g][i] : 0);
-            }
-            fprintf(fp,"\n");
-        }
-    }
-}
-
-void pr_atoms(FILE *fp,int indent,const char *title,t_atoms *atoms, 
-             gmx_bool bShownumbers)
-{
-  if (available(fp,atoms,indent,title))
-    {
-      indent=pr_title(fp,indent,title);
-      pr_atom(fp,indent,"atom",atoms->atom,atoms->nr);
-      pr_strings(fp,indent,"atom",atoms->atomname,atoms->nr,bShownumbers);
-      pr_strings2(fp,indent,"type",atoms->atomtype,atoms->atomtypeB,atoms->nr,bShownumbers);
-      pr_resinfo(fp,indent,"residue",atoms->resinfo,atoms->nres,bShownumbers);
-    }
-}
-
-
-void pr_atomtypes(FILE *fp,int indent,const char *title,t_atomtypes *atomtypes, 
-                 gmx_bool bShowNumbers)
-{
-  int i;
-  if (available(fp,atomtypes,indent,title)) 
-  {
-    indent=pr_title(fp,indent,title);
-    for(i=0;i<atomtypes->nr;i++) {
-      pr_indent(fp,indent);
-               fprintf(fp,
-                               "atomtype[%3d]={radius=%12.5e, volume=%12.5e, gb_radius=%12.5e, surftens=%12.5e, atomnumber=%4d, S_hct=%12.5e)}\n",
-                               bShowNumbers?i:-1,atomtypes->radius[i],atomtypes->vol[i],
-                               atomtypes->gb_radius[i],
-                               atomtypes->surftens[i],atomtypes->atomnumber[i],atomtypes->S_hct[i]);
-    }
-  }
-}
-
-static void pr_moltype(FILE *fp,int indent,const char *title,
-                       gmx_moltype_t *molt,int n,
-                       gmx_ffparams_t *ffparams,
-                       gmx_bool bShowNumbers)
-{
-    int j;
-
-    indent = pr_title_n(fp,indent,title,n);
-    (void) pr_indent(fp,indent);
-    (void) fprintf(fp,"name=\"%s\"\n",*(molt->name));
-    pr_atoms(fp,indent,"atoms",&(molt->atoms),bShowNumbers);
-    pr_block(fp,indent,"cgs",&molt->cgs, bShowNumbers);
-    pr_blocka(fp,indent,"excls",&molt->excls, bShowNumbers);
-    for(j=0; (j<F_NRE); j++) {
-        pr_ilist(fp,indent,interaction_function[j].longname,
-                 ffparams->functype,&molt->ilist[j],bShowNumbers);
-    }
-}
-
-static void pr_molblock(FILE *fp,int indent,const char *title,
-                        gmx_molblock_t *molb,int n,
-                        gmx_moltype_t *molt,
-                        gmx_bool bShowNumbers)
-{
-    indent = pr_title_n(fp,indent,title,n);
-    (void) pr_indent(fp,indent);
-    (void) fprintf(fp,"%-20s = %d \"%s\"\n",
-                   "moltype",molb->type,*(molt[molb->type].name));
-    pr_int(fp,indent,"#molecules",molb->nmol);
-    pr_int(fp,indent,"#atoms_mol",molb->natoms_mol);
-    pr_int(fp,indent,"#posres_xA",molb->nposres_xA);
-    if (molb->nposres_xA > 0) {
-        pr_rvecs(fp,indent,"posres_xA",molb->posres_xA,molb->nposres_xA);
-    }
-    pr_int(fp,indent,"#posres_xB",molb->nposres_xB);
-    if (molb->nposres_xB > 0) {
-        pr_rvecs(fp,indent,"posres_xB",molb->posres_xB,molb->nposres_xB);
-    }
-}
-
-void pr_mtop(FILE *fp,int indent,const char *title,gmx_mtop_t *mtop,
-             gmx_bool bShowNumbers)
-{
-    int mt,mb;
-
-    if (available(fp,mtop,indent,title)) {
-        indent=pr_title(fp,indent,title);
-        (void) pr_indent(fp,indent);
-        (void) fprintf(fp,"name=\"%s\"\n",*(mtop->name));
-        pr_int(fp,indent,"#atoms",mtop->natoms);
-        for(mb=0; mb<mtop->nmolblock; mb++) {
-            pr_molblock(fp,indent,"molblock",&mtop->molblock[mb],mb,
-                        mtop->moltype,bShowNumbers);
-        }
-        pr_ffparams(fp,indent,"ffparams",&(mtop->ffparams),bShowNumbers);
-        pr_atomtypes(fp,indent,"atomtypes",&(mtop->atomtypes),bShowNumbers);
-        for(mt=0; mt<mtop->nmoltype; mt++) {
-            pr_moltype(fp,indent,"moltype",&mtop->moltype[mt],mt,
-                       &mtop->ffparams,bShowNumbers);
-        }
-        pr_groups(fp,indent,"groups",&mtop->groups,bShowNumbers);
-    }
-}
-
-void pr_top(FILE *fp,int indent,const char *title,t_topology *top, gmx_bool bShowNumbers)
-{
-  if (available(fp,top,indent,title)) {
-    indent=pr_title(fp,indent,title);
-    (void) pr_indent(fp,indent);
-    (void) fprintf(fp,"name=\"%s\"\n",*(top->name));
-    pr_atoms(fp,indent,"atoms",&(top->atoms),bShowNumbers);
-    pr_atomtypes(fp,indent,"atomtypes",&(top->atomtypes),bShowNumbers);
-    pr_block(fp,indent,"cgs",&top->cgs, bShowNumbers);
-    pr_block(fp,indent,"mols",&top->mols, bShowNumbers);
-    pr_blocka(fp,indent,"excls",&top->excls, bShowNumbers);
-    pr_idef(fp,indent,"idef",&top->idef,bShowNumbers);
-  }
-}
-
-void pr_header(FILE *fp,int indent,const char *title,t_tpxheader *sh)
-{
-  char buf[22];
-    
-  if (available(fp,sh,indent,title))
-    {
-      indent=pr_title(fp,indent,title);
-      pr_indent(fp,indent);
-      fprintf(fp,"bIr    = %spresent\n",sh->bIr?"":"not ");
-      pr_indent(fp,indent);
-      fprintf(fp,"bBox   = %spresent\n",sh->bBox?"":"not ");
-      pr_indent(fp,indent);
-      fprintf(fp,"bTop   = %spresent\n",sh->bTop?"":"not ");
-      pr_indent(fp,indent);
-      fprintf(fp,"bX     = %spresent\n",sh->bX?"":"not ");
-      pr_indent(fp,indent);
-      fprintf(fp,"bV     = %spresent\n",sh->bV?"":"not ");
-      pr_indent(fp,indent);
-      fprintf(fp,"bF     = %spresent\n",sh->bF?"":"not ");
-      
-      pr_indent(fp,indent);
-      fprintf(fp,"natoms = %d\n",sh->natoms);
-      pr_indent(fp,indent);
-      fprintf(fp,"lambda = %e\n",sh->lambda);
-    }
-}
-
-void pr_commrec(FILE *fp,int indent,t_commrec *cr)
-{
-  pr_indent(fp,indent);
-  fprintf(fp,"commrec:\n");
-  indent+=2;
-  pr_indent(fp,indent);
-  fprintf(fp,"nodeid    = %d\n",cr->nodeid);
-  pr_indent(fp,indent);
-  fprintf(fp,"nnodes    = %d\n",cr->nnodes);
-  pr_indent(fp,indent);
-  fprintf(fp,"npmenodes = %d\n",cr->npmenodes);
-  /*
-  pr_indent(fp,indent);
-  fprintf(fp,"threadid  = %d\n",cr->threadid);
-  pr_indent(fp,indent);
-  fprintf(fp,"nthreads  = %d\n",cr->nthreads);
-  */
-}
diff --git a/src/gmxlib/version.c.cmakein b/src/gmxlib/version.c.cmakein
deleted file mode 100644 (file)
index 8aa4895..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-#include "version.h"
-const char _gmx_ver_string[] = "VERSION @GMX_PROJECT_VERSION_STR@";
-const char _gmx_full_git_hash[] = "@GMX_GIT_HEAD_HASH@";
-const char _gmx_central_base_hash[] = "@GMX_GIT_REMOTE_HASH@";
diff --git a/src/gromacs/CMakeLists.txt b/src/gromacs/CMakeLists.txt
new file mode 100644 (file)
index 0000000..4ca2213
--- /dev/null
@@ -0,0 +1,85 @@
+set(LIBGROMACS_SOURCES)
+
+add_subdirectory(legacyheaders)
+add_subdirectory(gmxlib)
+add_subdirectory(mdlib)
+add_subdirectory(analysisdata)
+add_subdirectory(errorreporting)
+add_subdirectory(fatalerror)
+add_subdirectory(options)
+add_subdirectory(selection)
+add_subdirectory(trajectoryanalysis)
+
+file(GLOB LIBGROMACS_HEADERS *.h)
+install(FILES ${LIBGROMACS_HEADERS} DESTINATION ${INCL_INSTALL_DIR}/gromacs
+        COMPONENT development)
+
+# only fiddle with assembly kernels if we're not doing OpenMM build
+if(NOT GMX_OPENMM) 
+if(GMX_ASM_USEASM-NASM)
+  enable_language(ASM-NASM)
+  # if NASM is used, we need a special build command for windows...
+  FOREACH(SRC ${GMX_SSEKERNEL_ASM_SRC})
+    GET_FILENAME_COMPONENT(FILE_BASE ${SRC} NAME_WE)
+    SET(OBJ ${CMAKE_CURRENT_BINARY_DIR}/${FILE_BASE}${CMAKE_C_OUTPUT_EXTENSION})
+
+    ADD_CUSTOM_COMMAND(OUTPUT ${OBJ}
+                       MAIN_DEPENDENCY ${SRC}
+                       COMMAND ${CMAKE_ASM-NASM_COMPILER} -f ${CMAKE_ASM-NASM_OBJECT_FORMAT} -o ${OBJ} ${SRC})
+
+    SET(ALL_ASM_OBJS ${ALL_ASM_OBJS} ${OBJ})
+  ENDFOREACH(SRC ${GMX_SSEKERNEL_ASM_SRC})
+  set(GMX_SSEKERNEL_ASM_SRC ${ALL_ASM_OBJS})
+else(GMX_ASM_USEASM-NASM)
+  enable_language(ASM-ATT)
+  SET(CMAKE_ASM-ATT_COMPILER ${CMAKE_C_COMPILER})
+  if(GMX_IA32_ASM)
+    set_source_files_properties(${GMX_SSEKERNEL_ASM_SRC} PROPERTIES COMPILE_FLAGS "-c -m32")
+  else()
+    set_source_files_properties(${GMX_SSEKERNEL_ASM_SRC} PROPERTIES COMPILE_FLAGS "-c -m64")
+  endif()
+endif(GMX_ASM_USEASM-NASM)
+endif(NOT GMX_OPENMM)
+
+list(APPEND LIBGROMACS_SOURCES ${GMXLIB_SOURCES} ${GMX_SSEKERNEL_ASM_SRC} ${MDLIB_SOURCES})
+
+# add target that generates version.c every time a make is run
+# only do this if we generate the version
+if (USE_VERSION_H)
+    add_custom_target(gmx_version ALL
+            COMMAND ${CMAKE_COMMAND} 
+                -D Git_EXECUTABLE="${Git_EXECUTABLE}"
+                -D Git_VERSION="${Git_VERSION}"
+                -D PROJECT_VERSION="${PROJECT_VERSION}"
+                -D PROJECT_SOURCE_DIR="${PROJECT_SOURCE_DIR}"
+                -D VERSION_C_CMAKEIN="${CMAKE_CURRENT_SOURCE_DIR}/version.c.cmakein"
+                -D VERSION_C_OUT="${CMAKE_CURRENT_BINARY_DIR}/version.c"
+                -P ${CMAKE_SOURCE_DIR}/cmake/gmxGenerateVersionInfo.cmake 
+            WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/src/gmxlib 
+            DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/version.c.cmakein
+            COMMENT "Generating version information")
+    list(APPEND LIBGROMACS_SOURCES ${CMAKE_CURRENT_BINARY_DIR}/version.c) # auto-generated
+    set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/version.c 
+                                PROPERTIES GENERATED true)
+endif (USE_VERSION_H)
+
+add_library(libgromacs ${LIBGROMACS_SOURCES})
+if (USE_VERSION_H)
+    add_dependencies(libgromacs gmx_version)
+endif (USE_VERSION_H)
+target_link_libraries(libgromacs
+                      ${GMX_EXTRA_LIBRARIES} ${FFT_LIBRARIES} ${XML_LIBRARIES}
+                      ${THREAD_LIB})
+set_target_properties(libgromacs PROPERTIES
+                      OUTPUT_NAME "gromacs${GMX_LIBS_SUFFIX}"
+                      SOVERSION ${SOVERSION}
+                      INSTALL_NAME_DIR "${LIB_INSTALL_DIR}")
+
+install(TARGETS libgromacs DESTINATION ${LIB_INSTALL_DIR} COMPONENT libraries)
+
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/libgromacs.pc.cmakein
+               ${CMAKE_CURRENT_BINARY_DIR}/libgromacs.pc @ONLY)
+install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libgromacs.pc
+        DESTINATION ${LIB_INSTALL_DIR}/pkgconfig
+        RENAME "libgromacs${GMX_LIBS_SUFFIX}.pc"
+        COMPONENT development)
diff --git a/src/gromacs/analysisdata.h b/src/gromacs/analysisdata.h
new file mode 100644 (file)
index 0000000..0af48c6
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \defgroup module_analysisdata Parallelizable Handling of Output Data
+ * \ingroup group_analysismodules
+ * \brief
+ * Provides functionality for handling and processing output data from
+ * analysis.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ */
+/*! \file
+ * \brief
+ * Public API convenience header for analysis data handling.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \inpublicapi
+ * \ingroup module_analysisdata
+ */
+#ifndef GMX_ANALYSISDATA_H
+#define GMX_ANALYSISDATA_H
+
+#include "analysisdata/analysisdata.h"
+#include "analysisdata/arraydata.h"
+#include "analysisdata/modules/average.h"
+#include "analysisdata/modules/displacement.h"
+#include "analysisdata/modules/histogram.h"
+#include "analysisdata/modules/plot.h"
+
+#endif
diff --git a/src/gromacs/analysisdata/CMakeLists.txt b/src/gromacs/analysisdata/CMakeLists.txt
new file mode 100644 (file)
index 0000000..fd0aad0
--- /dev/null
@@ -0,0 +1,13 @@
+file(GLOB ANALYSISDATA_SOURCES *.cpp modules/*.cpp)
+set(LIBGROMACS_SOURCES ${LIBGROMACS_SOURCES} ${ANALYSISDATA_SOURCES} PARENT_SCOPE)
+
+set(ANALYSISDATA_PUBLIC_HEADERS
+    abstractdata.h
+    analysisdata.h
+    arraydata.h
+    datamodule.h)
+install(FILES ${ANALYSISDATA_PUBLIC_HEADERS}
+        DESTINATION ${INCL_INSTALL_DIR}/gromacs/analysisdata
+        COMPONENT development)
+
+add_subdirectory(modules)
diff --git a/src/gromacs/analysisdata/abstractdata-impl.h b/src/gromacs/analysisdata/abstractdata-impl.h
new file mode 100644 (file)
index 0000000..3bce302
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * Declares internal implementation classes for gmx::AbstractAnalysisData and
+ * gmx::AbstractAnalysisDataStored.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_analysisdata
+ */
+#ifndef GMX_ANALYSISDATA_ABSTRACTDATA_IMPL_H
+#define GMX_ANALYSISDATA_ABSTRACTDATA_IMPL_H
+
+#include <vector>
+
+#include "types/simple.h"
+#include "abstractdata.h"
+
+namespace gmx
+{
+
+/*! \internal \brief
+ * Private implementation class for AbstractAnalysisData.
+ *
+ * \ingroup module_analysisdata
+ */
+class AbstractAnalysisData::Impl
+{
+    public:
+        //! Shorthand for list of modules added to the data.
+        typedef std::vector<AnalysisDataModuleInterface *> ModuleList;
+
+        Impl();
+        ~Impl();
+
+        /*! \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.
+         * \retval ::eeInvalidValue if \p module is not compatible with the
+         *      data object.
+         * \retval ::eedataDataNotAvailable if all data is not  available
+         *      through getData().
+         *
+         * Uses getData() in \p data to access all data in the object, and
+         * calls the notification functions in \p module as if the module had
+         * been registered to the data object when the data was added.
+         */
+        int presentData(AbstractAnalysisData *data,
+                        AnalysisDataModuleInterface *module);
+
+        //! List of modules added to the data.
+        ModuleList              _modules;
+        //! Whether notifyDataStart() has been called.
+        bool                    _bDataStart;
+        //! Whether new data is being added.
+        bool                    _bInData;
+        //! Whether data for a frame is being added.
+        bool                    _bInFrame;
+        //! true if all modules support missing data.
+        bool                    _bAllowMissing;
+        //! x value for the current frame.
+        real                    _currx;
+        //! dx value for the current frame.
+        real                    _currdx;
+};
+
+/*! \internal \brief
+ * Internal implementation class for storing a single data frame.
+ *
+ * \ingroup module_analysisdata
+ */
+class AnalysisDataFrame
+{
+    public:
+        AnalysisDataFrame();
+        ~AnalysisDataFrame();
+
+        //! Allocate memory for a given number of columns.
+        void allocate(int ncol);
+
+        //! Zero-based global index of the frame.
+        int                     _index;
+        //! x value of the frame.
+        real                    _x;
+        //! Error of x for the frame.
+        real                    _dx;
+        //! Array of column values for the frame.
+        real                   *_y;
+        //! Array of column error values for the frame.
+        real                   *_dy;
+        //! Array of flags that tell whether a value is present.
+        bool                   *_present;
+};
+
+/*! \internal \brief
+ * Private implementation class for AbstractAnalysisDataStored.
+ *
+ * \ingroup module_analysisdata
+ */
+class AbstractAnalysisDataStored::Impl
+{
+    public:
+        //! Shorthand for a list of data frames that are currently stored.
+        typedef std::vector<AnalysisDataFrame *> FrameList;
+
+        Impl();
+        ~Impl();
+
+        /*! \brief
+         * Calculates the index of a frame in the storage vector.
+         *
+         * \param[in] index  Zero-based index for the frame to query.
+         *      Negative value counts backwards from the current frame.
+         * \returns Index in \a _store corresponding to \p index,
+         *      or -1 if not available.
+         */
+        int getStoreIndex(int index) const;
+
+        /*! \brief
+         * Total number of complete frames in the data.
+         */
+        int                     _nframes;
+        /*! \brief
+         * Number of elements in \a _store.
+         *
+         * Also holds the number of frames that should be stored, even before
+         * \a _store has been allocated.
+         */
+        int                     _nalloc;
+        //! Whether all frames should be stored.
+        bool                    _bStoreAll;
+        //! List of data frames that are currently stored.
+        FrameList               _store;
+        /*! \brief
+         * Index in \a _store where the next frame will be stored.
+         *
+         * This counter is incremented after notifyPointsAdd() has been called
+         * for the frame.
+         */
+        int                     _nextind;
+};
+
+} // namespace gmx
+
+#endif
diff --git a/src/gromacs/analysisdata/abstractdata.cpp b/src/gromacs/analysisdata/abstractdata.cpp
new file mode 100644 (file)
index 0000000..67eb4b7
--- /dev/null
@@ -0,0 +1,667 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * Implements gmx::AbstractAnalysisData and gmx::AbstractAnalysisDataStored.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_analysisdata
+ */
+#include "gromacs/analysisdata/abstractdata.h"
+
+#include <cassert>
+
+// Legacy header.
+#include "smalloc.h"
+
+#include "gromacs/fatalerror/fatalerror.h"
+
+#include "abstractdata-impl.h"
+#include "dataproxy.h"
+
+namespace gmx
+{
+
+/********************************************************************
+ * AbstractAnalysisData::Impl
+ */
+
+AbstractAnalysisData::Impl::Impl()
+    : _bDataStart(false), _bInData(false), _bInFrame(false),
+      _bAllowMissing(true)
+{
+}
+
+AbstractAnalysisData::Impl::~Impl()
+{
+    ModuleList::const_iterator i;
+    for (i = _modules.begin(); i != _modules.end(); ++i)
+    {
+        delete *i;
+    }
+}
+
+
+int
+AbstractAnalysisData::Impl::presentData(AbstractAnalysisData *data,
+                                        AnalysisDataModuleInterface *module)
+{
+    int rc = module->dataStarted(data);
+    if (rc != 0)
+    {
+        return rc;
+    }
+    bool bCheckMissing = _bAllowMissing
+        && !(module->flags() & AnalysisDataModuleInterface::efAllowMissing);
+    int ncol = data->columnCount();
+    for (int i = 0; i < data->frameCount(); ++i)
+    {
+        real        x, dx;
+        const real *y, *dy;
+        const bool *present;
+
+        rc = data->getDataWErr(i, &x, &dx, &y, &dy, &present);
+        if (rc == 0)
+        {
+            if (bCheckMissing && present)
+            {
+                for (int j = 0; j < ncol; ++j)
+                {
+                    if (!present[j])
+                    {
+                        GMX_ERROR(eeInvalidValue,
+                                  "Missing data not supported by a module");
+                    }
+                }
+            }
+            rc = module->frameStarted(x, dx);
+        }
+        if (rc == 0)
+        {
+            rc = module->pointsAdded(x, dx, 0, ncol, y, dy, present);
+        }
+        if (rc == 0)
+        {
+            rc = module->frameFinished();
+        }
+        if (rc != 0)
+        {
+            return rc;
+        }
+    }
+    if (!_bInData)
+    {
+        rc = module->dataFinished();
+    }
+    return rc;
+}
+
+
+/********************************************************************
+ * AbstractAnalysisData
+ */
+
+AbstractAnalysisData::AbstractAnalysisData()
+    : _impl(new Impl()), _ncol(0), _bMultiPoint(false)
+{
+}
+
+
+AbstractAnalysisData::~AbstractAnalysisData()
+{
+    delete _impl;
+}
+
+
+int
+AbstractAnalysisData::getData(int index, real *x, const real **y,
+                              const bool **missing) const
+{
+    return getDataWErr(index, x, 0, y, 0, missing);
+}
+
+
+int
+AbstractAnalysisData::getErrors(int index, real *dx, const real **dy) const
+{
+    return getDataWErr(index, 0, dx, 0, dy, 0);
+}
+
+
+int
+AbstractAnalysisData::addModule(AnalysisDataModuleInterface *module)
+{
+    if ((columnCount() > 1 && !(module->flags() & AnalysisDataModuleInterface::efAllowMulticolumn))
+        || (isMultipoint() && !(module->flags() & AnalysisDataModuleInterface::efAllowMultipoint))
+        || (!isMultipoint() && (module->flags() & AnalysisDataModuleInterface::efOnlyMultipoint)))
+    {
+        GMX_ERROR(eeInvalidValue,
+                  "Data module not compatible with data object properties");
+    }
+
+    if (_impl->_bDataStart)
+    {
+        if (_impl->_bInFrame)
+        {
+            GMX_ERROR(eeInvalidCall,
+                      "Cannot add data modules in mid-frame");
+        }
+        int rc = _impl->presentData(this, module);
+        if (rc != 0)
+        {
+            return rc;
+        }
+    }
+    if (!(module->flags() & AnalysisDataModuleInterface::efAllowMissing))
+    {
+        _impl->_bAllowMissing = false;
+    }
+    _impl->_modules.push_back(module);
+    return 0;
+}
+
+
+int
+AbstractAnalysisData::addColumnModule(int col, int span,
+                                      AnalysisDataModuleInterface *module)
+{
+    assert(col >= 0 && span >= 1 && col + span <= _ncol);
+    if (_impl->_bDataStart)
+    {
+        GMX_ERROR(eeNotImplemented,
+                  "Cannot add column modules after data");
+    }
+
+    AnalysisDataProxy *proxy = new AnalysisDataProxy(col, span, this);
+    int rc = proxy->addModule(module);
+    if (rc == 0)
+    {
+        rc = addModule(proxy);
+    }
+    if (rc != 0)
+    {
+        delete proxy;
+    }
+    return rc;
+}
+
+
+int
+AbstractAnalysisData::applyModule(AnalysisDataModuleInterface *module)
+{
+    if ((columnCount() > 1 && !(module->flags() & AnalysisDataModuleInterface::efAllowMulticolumn))
+        || (isMultipoint() && !(module->flags() & AnalysisDataModuleInterface::efAllowMultipoint))
+        || (!isMultipoint() && (module->flags() & AnalysisDataModuleInterface::efOnlyMultipoint)))
+    {
+        GMX_ERROR(eeInvalidValue,
+                  "Data module not compatible with data object properties");
+    }
+    if (!_impl->_bDataStart || _impl->_bInData)
+    {
+        GMX_ERROR(eeInvalidCall,
+                  "Data module can only be applied to ready data");
+    }
+
+    return _impl->presentData(this, module);
+}
+
+
+void
+AbstractAnalysisData::setColumnCount(int ncol)
+{
+    assert(ncol > 0);
+    assert(_ncol == 0 || _impl->_modules.empty());
+    assert(!_impl->_bDataStart);
+    _ncol = ncol;
+}
+
+
+void
+AbstractAnalysisData::setMultipoint(bool multipoint)
+{
+    assert(_impl->_modules.empty());
+    assert(!_impl->_bDataStart);
+    _bMultiPoint = multipoint;
+}
+
+
+/*! \internal
+ * This method is not const because the dataStarted() methods of the attached
+ * modules can request storage of the data.
+ */
+int
+AbstractAnalysisData::notifyDataStart()
+{
+    assert(!_impl->_bDataStart);
+    assert(_ncol > 0);
+    _impl->_bDataStart = _impl->_bInData = true;
+
+    Impl::ModuleList::const_iterator i;
+
+    for (i = _impl->_modules.begin(); i != _impl->_modules.end(); ++i)
+    {
+        if (_ncol > 1 && !((*i)->flags() & AnalysisDataModuleInterface::efAllowMulticolumn))
+        {
+            GMX_ERROR(eeInvalidValue,
+                      "Data module not compatible with data object properties");
+        }
+        int rc = (*i)->dataStarted(this);
+        if (rc != 0)
+        {
+            return rc;
+        }
+    }
+    return 0;
+}
+
+
+int
+AbstractAnalysisData::notifyFrameStart(real x, real dx) const
+{
+    assert(_impl->_bInData && !_impl->_bInFrame);
+    _impl->_bInFrame = true;
+    _impl->_currx  = x;
+    _impl->_currdx = dx;
+
+    Impl::ModuleList::const_iterator i;
+    for (i = _impl->_modules.begin(); i != _impl->_modules.end(); ++i)
+    {
+        int rc = (*i)->frameStarted(x, dx);
+        if (rc != 0)
+        {
+            return rc;
+        }
+    }
+    return 0;
+}
+
+
+int
+AbstractAnalysisData::notifyPointsAdd(int firstcol, int n,
+                                      const real *y, const real *dy,
+                                      const bool *present) const
+{
+    assert(_impl->_bInData && _impl->_bInFrame);
+    assert(firstcol >= 0 && n > 0 && firstcol + n <= _ncol);
+    if (present && !_impl->_bAllowMissing)
+    {
+        for (int i = 0; i < n; ++i)
+        {
+            if (!present[i])
+            {
+                GMX_ERROR(eeInvalidValue,
+                          "Missing data not supported by a module");
+            }
+        }
+    }
+
+    Impl::ModuleList::const_iterator i;
+    for (i = _impl->_modules.begin(); i != _impl->_modules.end(); ++i)
+    {
+        int rc = (*i)->pointsAdded(_impl->_currx, _impl->_currdx, firstcol, n,
+                                   y, dy, present);
+        if (rc != 0)
+        {
+            return rc;
+        }
+    }
+    return 0;
+}
+
+
+int
+AbstractAnalysisData::notifyFrameFinish() const
+{
+    assert(_impl->_bInData && _impl->_bInFrame);
+    _impl->_bInFrame = false;
+
+    Impl::ModuleList::const_iterator i;
+
+    for (i = _impl->_modules.begin(); i != _impl->_modules.end(); ++i)
+    {
+        int rc = (*i)->frameFinished();
+        if (rc != 0)
+        {
+            return rc;
+        }
+    }
+    return 0;
+}
+
+
+int
+AbstractAnalysisData::notifyDataFinish() const
+{
+    assert(_impl->_bInData && !_impl->_bInFrame);
+    _impl->_bInData = false;
+
+    Impl::ModuleList::const_iterator i;
+
+    for (i = _impl->_modules.begin(); i != _impl->_modules.end(); ++i)
+    {
+        int rc = (*i)->dataFinished();
+        if (rc != 0)
+        {
+            return rc;
+        }
+    }
+    return 0;
+}
+
+
+/********************************************************************
+ * AnalysisDataFrame
+ */
+
+AnalysisDataFrame::AnalysisDataFrame()
+    : _y(NULL), _dy(NULL), _present(NULL)
+{
+}
+
+AnalysisDataFrame::~AnalysisDataFrame()
+{
+    sfree(_y);
+    sfree(_dy);
+    sfree(_present);
+}
+
+
+void AnalysisDataFrame::allocate(int ncol)
+{
+    snew(_y, ncol);
+    snew(_dy, ncol);
+    snew(_present, ncol);
+}
+
+
+/********************************************************************
+ * AbstractAnalysisDataStored::Impl
+ */
+
+AbstractAnalysisDataStored::Impl::Impl()
+    : _nframes(0), _nalloc(0), _bStoreAll(false), _nextind(-1)
+{
+}
+
+
+AbstractAnalysisDataStored::Impl::~Impl()
+{
+    FrameList::const_iterator i;
+    for (i = _store.begin(); i != _store.end(); ++i)
+    {
+        delete *i;
+    }
+}
+
+
+int
+AbstractAnalysisDataStored::Impl::getStoreIndex(int index) const
+{
+    // Check that the requested index is available.
+    if ((index < 0 && (-index > _nalloc || -index > _nframes))
+        || index >= _nframes || (index >= 0 && index < _nframes - _nalloc))
+    {
+        return -1;
+    }
+    // Calculate the index into the storage array.
+    if (index < 0)
+    {
+        index = _nextind + index;
+        if (index < 0)
+        {
+            index += _nalloc;
+        }
+    }
+    else if (_nframes > _nalloc)
+    {
+        index %= _nalloc;
+    }
+    return index;
+}
+
+
+/********************************************************************
+ * AbstractAnalysisDataStored
+ */
+
+AbstractAnalysisDataStored::AbstractAnalysisDataStored()
+    : _impl(new Impl())
+{
+}
+
+
+AbstractAnalysisDataStored::~AbstractAnalysisDataStored()
+{
+    delete _impl;
+}
+
+
+int
+AbstractAnalysisDataStored::frameCount() const
+{
+    return _impl->_nframes;
+}
+
+
+int
+AbstractAnalysisDataStored::getDataWErr(int index, real *x, real *dx,
+                                        const real **y, const real **dy,
+                                        const bool **present) const
+{
+    index = _impl->getStoreIndex(index);
+    if (index < 0)
+    {
+        return eedataDataNotAvailable;
+    }
+
+    // Retrieve the data.
+    AnalysisDataFrame *fr = _impl->_store[index];
+    if (x)
+    {
+        *x = fr->_x;
+    }
+    if (dx)
+    {
+        *dx = fr->_dx;
+    }
+    if (y)
+    {
+        *y = fr->_y;
+    }
+    if (dy)
+    {
+        *dy = fr->_dy;
+    }
+    if (present)
+    {
+        *present = fr->_present;
+    }
+    return 0;
+}
+
+
+int
+AbstractAnalysisDataStored::requestStorage(int nframes)
+{
+    assert(nframes >= -1);
+    if (nframes == 0)
+    {
+        return 0;
+    }
+    if (isMultipoint())
+    {
+        GMX_ERROR(eeNotImplemented,
+                  "Storage of multipoint data not supported");
+    }
+
+    // Handle the case when everything needs to be stored.
+    if (nframes == -1)
+    {
+        _impl->_bStoreAll = true;
+        _impl->_nalloc = 1;
+        return 0;
+    }
+    // Check whether an earier call has requested more storage.
+    if (_impl->_bStoreAll || nframes < _impl->_nalloc)
+    {
+        return 0;
+    }
+    _impl->_nalloc = nframes;
+    return 0;
+}
+
+
+void
+AbstractAnalysisDataStored::setMultipoint(bool multipoint)
+{
+    assert(_impl->_nalloc == 0 || !multipoint);
+    AbstractAnalysisData::setMultipoint(multipoint);
+}
+
+
+int
+AbstractAnalysisDataStored::startDataStore()
+{
+    // We first notify any attached modules, because they also might request
+    // some storage.
+    int rc = notifyDataStart();
+    if (rc != 0)
+    {
+        return rc;
+    }
+
+    int ncol = columnCount();
+
+    // If any storage has been requested, preallocate it.
+    if (_impl->_nalloc > 0)
+    {
+        _impl->_store.resize(_impl->_nalloc);
+        for (int i = 0; i < _impl->_nalloc; ++i)
+        {
+            _impl->_store[i] = new AnalysisDataFrame();
+            _impl->_store[i]->allocate(ncol);
+        }
+        _impl->_nextind = 0;
+    }
+    return 0;
+}
+
+
+int
+AbstractAnalysisDataStored::startNextFrame(real x, real dx)
+{
+    // Start storing the frame if needed.
+    if (_impl->_nalloc > 0)
+    {
+        if (_impl->_nextind >= _impl->_nalloc)
+        {
+            if (_impl->_bStoreAll)
+            {
+                int ncol = columnCount();
+
+                _impl->_nalloc = _impl->_nextind + 1;
+                _impl->_store.resize(_impl->_nalloc);
+                for (int i = _impl->_nextind; i < _impl->_nalloc; ++i)
+                {
+                    _impl->_store[i] = new AnalysisDataFrame();
+                    _impl->_store[i]->allocate(ncol);
+                }
+            }
+            else
+            {
+                _impl->_nextind = 0;
+            }
+        }
+
+        _impl->_store[_impl->_nextind]->_x  = x;
+        _impl->_store[_impl->_nextind]->_dx = dx;
+    }
+
+    // Notify any modules.
+    return notifyFrameStart(x, dx);
+}
+
+
+int
+AbstractAnalysisDataStored::storeThisFrame(const real *y, const real *dy,
+                                           const bool *present)
+{
+    int ncol = columnCount();
+
+    // Store the values if required.
+    if (_impl->_nextind >= 0)
+    {
+        AnalysisDataFrame *fr = _impl->_store[_impl->_nextind];
+
+        for (int i = 0; i < ncol; ++i)
+        {
+            fr->_y[i] = y[i];
+            if (dy)
+            {
+                fr->_dy[i] = dy[i];
+            }
+            if (present)
+            {
+                fr->_present[i] = present[i];
+            }
+        }
+    }
+    ++_impl->_nframes;
+
+    // Notify modules of new data.
+    int rc = notifyPointsAdd(0, ncol, y, dy, present);
+    // The index needs to be incremented after the notifications to allow
+    // the modules to use getData() properly.
+    if (_impl->_nextind >= 0)
+    {
+        ++_impl->_nextind;
+    }
+    if (rc != 0)
+    {
+        return rc;
+    }
+    return notifyFrameFinish();
+}
+
+
+int
+AbstractAnalysisDataStored::storeNextFrame(real x, real dx, const real *y,
+                                           const real *dy, const bool *present)
+{
+    int rc = startNextFrame(x, dx);
+    if (rc != 0)
+    {
+        return rc;
+    }
+    return storeThisFrame(y, dy, present);
+}
+
+} // namespace gmx
diff --git a/src/gromacs/analysisdata/abstractdata.h b/src/gromacs/analysisdata/abstractdata.h
new file mode 100644 (file)
index 0000000..25942c8
--- /dev/null
@@ -0,0 +1,369 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \libinternal \file
+ * \brief
+ * Declares gmx::AbstractAnalysisData and gmx::AbstractAnalysisDataStored.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \inlibraryapi
+ * \ingroup module_analysisdata
+ */
+#ifndef GMX_ANALYSISDATA_ABSTRACTDATA_H
+#define GMX_ANALYSISDATA_ABSTRACTDATA_H
+
+#include "../legacyheaders/types/simple.h"
+
+namespace gmx
+{
+
+//! Additional error codes for functions in the analysis data module.
+enum AnalysisDataErrorCode
+{
+    eedataDataNotAvailable = -1,
+};
+
+class AnalysisDataModuleInterface;
+
+/*! \libinternal \brief
+ * Abstract base class for all objects that provide data.
+ *
+ * The public interface includes functions for querying the data
+ * (isMultipoint(), columnCount(), frameCount(), getDataWErr(), getData(),
+ * getErrors(), requestStorage()) and functions for using modules for
+ * processing the data (addModule(), addColumnModule(), applyModule()).
+ *
+ * There are also protected functions for use in derived classes:
+ * setting the properties returned by isMultipoint() and columnCount()
+ * through setMultipoint() and setColumnCount(), and notifying attached
+ * modules of added data.
+ *
+ * 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 relatively safe to return a non-const pointer of this type
+ * pointing to an internal data structure without worrying about possible
+ * modifications of the data.
+ *
+ * It is up to subclasses to ensure that the protected functions are called
+ * in a correct sequence (the functions will assert in most incorrect use
+ * cases), and that the data provided through the public interface matches
+ * that passed to the modules with the notify methods.
+ *
+ * \inlibraryapi
+ * \ingroup module_analysisdata
+ */
+class AbstractAnalysisData
+{
+    public:
+        virtual ~AbstractAnalysisData();
+
+        /*! \brief
+         * Whether the data can have multiple points in the same column
+         * in the same frame.
+         *
+         * \returns \c true if multiple points in the same column are
+         *     allowed within a single frame.
+         *
+         * This kind of data can appear in many histogramming applications
+         * (e.g., RDFs), where each trajectory frame has several data points
+         * (possibly a different number for each frame). The current interface
+         * doesn't support storing such data, but this should rarely be
+         * necessary.
+         *
+         * Derived classes can change the type by calling setMultipoint().
+         * If this is not done, the function always returns false.
+         */
+        bool isMultipoint() const { return _bMultiPoint; }
+        /*! \brief
+         * Returns the number of columns in the data.
+         *
+         * \returns The number of columns in the data.
+         *
+         * Derived classes should set the number of columns with
+         * setColumnCount().
+         * If the number of columns is not set, returns 0.
+         */
+        int columnCount() const { return _ncol; }
+        /*! \brief
+         * Returns the total number of frames in the data.
+         *
+         * \returns The total number of frames in the data.
+         *
+         * This function returns the number of frames that the object has
+         * produced. If requestStorage() has been successfully called,
+         * getData() can be used to access some or all of these frames.
+         */
+        virtual int frameCount() const = 0;
+        /*! \brief
+         * Access stored data.
+         *
+         * \param[in]  index   Frame index to access
+         *      (negative indices count backwards from the current frame).
+         * \param[out] x
+         * \param[out] dx
+         * \param[out] y
+         * \param[out] dy
+         * \param[out] present Returns a pointer to an array that tells
+         *      whether the corresponding column is present in that frame.
+         *      If NULL, no missing information is returned.
+         * \retval 0 on success.
+         * \retval ::eedataDataNotAvailable if data for the requested frame is
+         *      no longer available (this is regarded as a normal outcome,
+         *      i.e., no error handlers are invoked).
+         *
+         * Derived classes can choose to return ::eedataDataNotAvailable if
+         * requestStorage() has not been called at all, or if the frame is
+         * too old (compared to the value given to requestStorage()).
+         */
+        virtual int getDataWErr(int index, real *x, real *dx,
+                                const real **y, const real **dy,
+                                const bool **present = 0) const = 0;
+        /*! \brief
+         * Convenience function for accessing stored data.
+         *
+         * \see getDataWErr()
+         */
+        int getData(int index, real *x, const real **y,
+                    const bool **present = 0) const;
+        /*! \brief
+         * Convenience function for accessing errors for stored data.
+         *
+         * \see getDataWErr()
+         */
+        int getErrors(int index, real *dx, const real **dy) const;
+        /*! \brief
+         * Request storage of frames.
+         *
+         * \param[in] nframes  Request storing at least \c nframes previous
+         *     frames (-1 = request storing all).
+         * \retval 0 on success.
+         * \retval eedataInvalidCall if data has already been added and
+         *      cannot be stored.
+         * \retval eedataNotSupported if the object does not support storage.
+         *
+         * If called multiple times, the largest request should be honored.
+         *
+         * \see getData()
+         */
+        virtual int requestStorage(int nframes = -1) = 0;
+
+        /*! \brief
+         * Adds a module to process the data.
+         *
+         * \param  module  Module to add.
+         * \retval 0 on success.
+         * \retval ::eeInvalidValue if \p module is not compatible with the
+         *      data object.
+         * \retval ::eedataDataNotAvailable if data has already been added to
+         *      the data object and everything is not available through
+         *      getData().
+         *
+         * If data has already been added to the module, the new module
+         * immediately processes all existing data.  ::eedataDataNotAvailable
+         * is returned if all data is not available through getData().
+         *
+         * If the call successful, the data object takes ownership of the
+         * module, and automatically destructs it when the data object itself
+         * is destroyed.
+         */
+        int addModule(AnalysisDataModuleInterface *module);
+        /*! \brief
+         * Adds a module that processes only a subset of the columns.
+         *
+         * \param[in] col     First column.
+         * \param[in] span    Number of columns.
+         * \param     module  Module to add.
+         * \retval 0 on success.
+         *
+         * Can return any of the return codes for addModule().
+         */
+        int addColumnModule(int col, int span, AnalysisDataModuleInterface *module);
+        /*! \brief
+         * Applies a module to process data that is ready.
+         *
+         * \param  module  Module to apply.
+         *
+         * This function works as addModule(), except that it does not take
+         * ownership of \p module. Also, it can only be called after the data
+         * is ready, and only if getData() gives access to all of the data.
+         * It is provided for additional flexibility in postprocessing
+         * in-memory data.
+         */
+        int applyModule(AnalysisDataModuleInterface *module);
+
+    protected:
+        AbstractAnalysisData();
+
+        /*! \brief
+         * Sets the number of columns.
+         *
+         * \param[in] ncol  Number of columns in the data (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).
+         *
+         * \see columnCount()
+         */
+        void setColumnCount(int ncol);
+        /*! \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.
+         *
+         * \see isMultipoint()
+         */
+        void setMultipoint(bool multipoint);
+
+        /*! \brief
+         * Notifies attached modules of the start of data.
+         *
+         * Should be called once, after data properties have been set with
+         * setColumnCount() and isMultipoint(), and before any of the
+         * notification functions. The derived class should prepare for
+         * requestStorage() calls from the attached modules.
+         */
+        int notifyDataStart();
+        /*! \brief
+         * Notifies attached modules of the start of a frame.
+         *
+         * Should be called once for each frame, before notifyPointsAdd() calls
+         * for thet frame.
+         */
+        int notifyFrameStart(real x, real dx) const;
+        /*! \brief
+         * Notifies attached modules of the addition of points to the
+         * current frame.
+         *
+         * Can be called zero or more times for each frame.
+         * The caller should ensure that any column occurs at most once in the
+         * calls, unless the data is multipoint.
+         * For efficiency reasons, calls to this method should be aggregated
+         * whenever possible, i.e., it's better to handle multiple columns or
+         * even the whole frame in a single call rather than calling the method
+         * for each column separately.
+         */
+        int notifyPointsAdd(int firstcol, int n,
+                            const real *y, const real *dy,
+                            const bool *present) const;
+        /*! \brief
+         * Notifies attached modules of the end of a frame.
+         *
+         * Should be called once for each call of notifyFrameStart(), after any
+         * notifyPointsAdd() calls for the frame.
+         */
+        int notifyFrameFinish() const;
+        /*! \brief
+         * Notifies attached modules of the end of data.
+         *
+         * Should be called once, after all the other notification calls.
+         */
+        int notifyDataFinish() const;
+
+    private:
+        class Impl;
+
+        Impl                   *_impl;
+        int                     _ncol;
+        bool                    _bMultiPoint;
+
+        // Disallow copy and assign.
+        AbstractAnalysisData(const AbstractAnalysisData &);
+        void operator =(const AbstractAnalysisData &);
+};
+
+
+/*! \libinternal \brief
+ * Abstract class that implements storage of data.
+ *
+ * This class implements a standard way of storing data, to avoid implementing
+ * storage in each derived class separately. All the pure virtual methods of
+ * AbstractData are implemented, and protected methods are provided to add data
+ * to the storage. These protected methods automatically call notifyDataStart(),
+ * notifyFrameStart(), notifyPointsAdd() and notifyFrameFinish()
+ * functions in AbstractAnalysisData, but the derived class should still
+ * call notifyDataFinish().
+ *
+ * Additional protected functions could be implemented to allow optimization:
+ * in the current interface, some data copying is unavoidable.
+ * Some changes could make it possible to obtain a pointer to the
+ * storage, allowing the calculated values to be stored there directly
+ * instead of a temporary array.
+ *
+ * \inlibraryapi
+ * \ingroup module_analysisdata
+ */
+class AbstractAnalysisDataStored : public AbstractAnalysisData
+{
+    public:
+        virtual ~AbstractAnalysisDataStored();
+
+        virtual int frameCount() const;
+        virtual int getDataWErr(int index, real *x, real *dx,
+                                const real **y, const real **dy,
+                                const bool **present = 0) const;
+        virtual int requestStorage(int nframes = -1);
+
+    protected:
+        AbstractAnalysisDataStored();
+
+        /*! \copydoc AbstractAnalysisData::setMultipoint()
+         *
+         * The overridden method also asserts if
+         * storage has been requested and \p multipoint is \c true.
+         */
+        void setMultipoint(bool multipoint);
+
+        //! Start storing data.
+        int startDataStore();
+        //! Starts storing a next frame.
+        int startNextFrame(real x, real dx);
+        //! Stores the whole frame in a single call after start_next_frame().
+        int storeThisFrame(const real *y, const real *dy, const bool *present);
+        //! Convenience function for storing a whole frame in a single call.
+        int storeNextFrame(real x, real dx, const real *y, const real *dy,
+                           const bool *present);
+
+    private:
+        class Impl;
+
+        Impl                   *_impl;
+
+        // Copy and assign disallowed by base class.
+};
+
+} // namespace gmx
+
+#endif
diff --git a/src/gromacs/analysisdata/analysisdata-impl.h b/src/gromacs/analysisdata/analysisdata-impl.h
new file mode 100644 (file)
index 0000000..a8c49e3
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * Declares private implementation class for gmx::AnalysisData.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_analysisdata
+ */
+#ifndef GMX_ANALYSISDATA_ANALYSISDATA_IMPL_H
+#define GMX_ANALYSISDATA_ANALYSISDATA_IMPL_H
+
+#include <vector>
+
+#include "analysisdata.h"
+
+#include "abstractdata-impl.h"
+
+namespace gmx
+{
+
+/*! \internal \brief
+ * Private implementation class for AnalysisData.
+ *
+ * \ingroup module_analysisdata
+ */
+class AnalysisData::Impl
+{
+    public:
+        //! Shorthand for a list of data handles.
+        typedef std::vector<AnalysisDataHandle *> HandleList;
+        //! Shorthand for a list of frames.
+        typedef std::vector<AnalysisDataFrame *>  FrameList;
+
+        //! Creates an implementation class associated with the given object.
+        explicit Impl(AnalysisData *data);
+        ~Impl();
+
+        /*! \brief
+         * Handles a new frame.
+         *
+         * If all earlier frames are ready, the data is directly passed to
+         * AbstractStoredData.  Otherwise, it is put into the correct location
+         * in \a _pending.  Calls processPendingFrame() after processing \p fr.
+         */
+        int addPendingFrame(AnalysisDataFrame *fr);
+        /*! \brief
+         * Passes pending frames to base class if all earlier frames are ready.
+         */
+        int processPendingFrames();
+        //! Increments \a _pstart.
+        void incrementPStart();
+
+        //! The data object that uses this implementation class.
+        AnalysisData           &_data;
+        //! List of handles for this data object.
+        HandleList              _handles;
+        /*! \brief
+         * Index into \a _pending that points to the location where the current
+         * frame would go.
+         */
+        size_t                  _pstart;
+        /*! \brief
+         * Circular buffer for frames that are ready but waiting for earlier
+         * frames.
+         */
+        FrameList               _pending;
+};
+
+/*! \internal \brief
+ * Private implementation class for AnalysisDataHandle.
+ *
+ * \ingroup module_analysisdata
+ */
+class AnalysisDataHandle::Impl
+{
+    public:
+        //! Creates a handle associated with the given data object.
+        explicit Impl(AnalysisData *data);
+        ~Impl();
+
+        //! The data object that this handle belongs to.
+        AnalysisData            &_data;
+        //! Frame object where the current frame is being accumulated.
+        AnalysisDataFrame       *_frame;
+};
+
+} // namespace gmx
+
+#endif
diff --git a/src/gromacs/analysisdata/analysisdata.cpp b/src/gromacs/analysisdata/analysisdata.cpp
new file mode 100644 (file)
index 0000000..1e5a7f8
--- /dev/null
@@ -0,0 +1,391 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * Implements classes in analysisdata.h.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_analysisdata
+ */
+#include "gromacs/analysisdata/analysisdata.h"
+
+#include <algorithm>
+
+#include <cassert>
+
+#include "gromacs/fatalerror/fatalerror.h"
+
+#include "abstractdata-impl.h"
+#include "analysisdata-impl.h"
+
+namespace gmx
+{
+
+/********************************************************************
+ * AnalysisData::Impl
+ ********************************************************************/
+
+static bool
+frame_index_gtr(AnalysisDataFrame *a, AnalysisDataFrame *b)
+{
+    return a->_index > b->_index;
+}
+
+
+AnalysisData::Impl::Impl(AnalysisData *data)
+    : _data(*data), _pstart(0)
+{
+}
+
+
+AnalysisData::Impl::~Impl()
+{
+    HandleList::const_iterator i;
+    for (i = _handles.begin(); i != _handles.end(); ++i)
+    {
+        delete *i;
+    }
+
+    FrameList::const_iterator j;
+    for (j = _pending.begin(); j != _pending.end(); ++j)
+    {
+        delete *j;
+    }
+}
+
+
+int
+AnalysisData::Impl::addPendingFrame(AnalysisDataFrame *fr)
+{
+    assert(fr->_index >= _data.frameCount());
+    size_t pindex = fr->_index - _data.frameCount();
+    if (pindex == 0)
+    {
+        int rc;
+
+        // Just store our frame if it is the next one.
+        rc = _data.storeNextFrame(fr->_x, fr->_dx,
+                                  fr->_y, fr->_dy, fr->_present);
+        if (rc != 0)
+        {
+            return rc;
+        }
+        incrementPStart();
+    }
+    else
+    {
+        if (pindex >= _pending.size())
+        {
+            // TODO: We need to wait until earlier frames are ready...
+        }
+        // TODO: This is not thread-safe.
+        pindex += _pstart;
+        if (pindex > _pending.size())
+        {
+            pindex -= _pending.size();
+        }
+
+        int ncol = _data.columnCount();
+        _pending[pindex]->_x     = fr->_x;
+        _pending[pindex]->_dx    = fr->_dx;
+        for (int i = 0; i < ncol; ++i)
+        {
+            _pending[pindex]->_y[i]       = fr->_y[i];
+            _pending[pindex]->_dy[i]      = fr->_dy[i];
+            _pending[pindex]->_present[i] = fr->_present[i];
+        }
+        _pending[pindex]->_index = fr->_index;
+    }
+    return processPendingFrames();
+}
+
+
+int
+AnalysisData::Impl::processPendingFrames()
+{
+    while (_pending[_pstart]->_index != -1)
+    {
+        AnalysisDataFrame *fr = _pending[_pstart];
+
+        int rc = _data.storeNextFrame(fr->_x, fr->_dx,
+                                      fr->_y, fr->_dy, fr->_present);
+        if (rc != 0)
+        {
+            return rc;
+        }
+        fr->_index = -1;
+        incrementPStart();
+    }
+    return 0;
+}
+
+
+void
+AnalysisData::Impl::incrementPStart()
+{
+    size_t val = _pstart;
+
+    ++val;
+    if (val >= _pending.size())
+    {
+        val -= _pending.size();
+    }
+    _pstart = val;
+}
+
+
+/********************************************************************
+ * AnalysisData
+ */
+
+AnalysisData::AnalysisData()
+    : _impl(new Impl(this))
+{
+}
+
+
+AnalysisData::~AnalysisData()
+{
+    delete _impl;
+}
+
+
+void
+AnalysisData::setColumns(int ncol, bool multipoint)
+{
+    assert(ncol > 0);
+    assert(_impl->_handles.empty());
+    setColumnCount(ncol);
+    setMultipoint(multipoint);
+}
+
+
+int
+AnalysisData::startData(AnalysisDataHandle **handlep,
+                        AnalysisDataParallelOptions opt)
+{
+    if (_impl->_handles.empty())
+    {
+        int rc = startDataStore();
+        if (rc != 0)
+        {
+            return rc;
+        }
+    }
+    else if (isMultipoint())
+    {
+        GMX_ERROR(eeNotImplemented,
+                  "Parallelism not supported for multipoint data");
+    }
+
+    AnalysisDataHandle *handle = new AnalysisDataHandle(this);
+    _impl->_handles.push_back(handle);
+    *handlep = handle;
+
+    _impl->_pending.resize(2 * _impl->_handles.size() - 1);
+    Impl::FrameList::iterator i;
+    for (i = _impl->_pending.begin(); i != _impl->_pending.end(); ++i)
+    {
+        *i = new AnalysisDataFrame();
+        (*i)->allocate(columnCount());
+        (*i)->_index = -1;
+    }
+
+    return 0;
+}
+
+
+int
+AnalysisData::finishData(AnalysisDataHandle *handle)
+{
+    Impl::HandleList::iterator i;
+
+    i = std::find(_impl->_handles.begin(), _impl->_handles.end(), handle);
+    assert(i != _impl->_handles.end());
+
+    _impl->_handles.erase(i);
+    delete handle;
+
+    if (_impl->_handles.empty())
+    {
+        return notifyDataFinish();
+    }
+    return 0;
+}
+
+
+/********************************************************************
+ * AnalysisDataHandle::Impl
+ */
+
+AnalysisDataHandle::Impl::Impl(AnalysisData *data)
+    : _data(*data), _frame(NULL)
+{
+    if (!_data.isMultipoint())
+    {
+        _frame = new AnalysisDataFrame();
+        _frame->allocate(_data.columnCount());
+    }
+}
+
+
+AnalysisDataHandle::Impl::~Impl()
+{
+    delete _frame;
+}
+
+
+/********************************************************************
+ * AnalysisDataHandle
+ */
+
+AnalysisDataHandle::AnalysisDataHandle(AnalysisData *data)
+    : _impl(new Impl(data))
+{
+}
+
+
+AnalysisDataHandle::~AnalysisDataHandle()
+{
+    delete _impl;
+}
+
+
+int
+AnalysisDataHandle::startFrame(int index, real x, real dx)
+{
+    if (_impl->_data.isMultipoint())
+    {
+        return _impl->_data.notifyFrameStart(x, dx);
+    }
+    else
+    {
+        _impl->_frame->_index = index;
+        _impl->_frame->_x  = x;
+        _impl->_frame->_dx = dx;
+        for (int i = 0; i < _impl->_data.columnCount(); ++i)
+        {
+            _impl->_frame->_y[i]  = 0.0;
+            _impl->_frame->_dy[i] = 0.0;
+            _impl->_frame->_present[i] = false;
+        }
+        return 0;
+    }
+}
+
+
+int
+AnalysisDataHandle::addPoint(int col, real y, real dy, bool present)
+{
+    if (_impl->_data.isMultipoint())
+    {
+        return _impl->_data.notifyPointsAdd(col, 1, &y, &dy, &present);
+    }
+    else
+    {
+        assert(!_impl->_frame->_present[col]);
+        _impl->_frame->_y[col] = y;
+        _impl->_frame->_dy[col] = dy;
+        _impl->_frame->_present[col] = present;
+        return 0;
+    }
+}
+
+
+int
+AnalysisDataHandle::addPoints(int firstcol, int n,
+                              const real *y, const real *dy,
+                              const bool *present)
+{
+    if (_impl->_data.isMultipoint())
+    {
+        return _impl->_data.notifyPointsAdd(firstcol, n, y, dy, present);
+    }
+    else
+    {
+        for (int i = 0; i < n; ++i)
+        {
+            addPoint(firstcol + i, y[i], dy ? dy[i] : 0.0,
+                     present ? present[i] : true);
+        }
+        return 0;
+    }
+}
+
+
+int
+AnalysisDataHandle::finishFrame()
+{
+    if (_impl->_data.isMultipoint())
+    {
+        return _impl->_data.notifyFrameFinish();
+    }
+    else
+    {
+        return _impl->_data._impl->addPendingFrame(_impl->_frame);
+    }
+}
+
+
+int
+AnalysisDataHandle::addFrame(int index, real x, const real *y, const real *dy,
+                             const bool *present)
+{
+    return addFrame(index, x, 0.0, y, dy, present);
+}
+
+
+int
+AnalysisDataHandle::addFrame(int index, real x, real dx,
+                             const real *y, const real *dy,
+                             const bool *present)
+{
+    int rc = startFrame(index, x, dx);
+    if (rc == 0)
+    {
+        rc = addPoints(0, _impl->_data.columnCount(), y, dy, present);
+    }
+    if (rc == 0)
+    {
+        rc = finishFrame();
+    }
+    return rc;
+}
+
+
+int
+AnalysisDataHandle::finishData()
+{
+    // Calls delete this
+    return _impl->_data.finishData(this);
+}
+
+} // namespace gmx
diff --git a/src/gromacs/analysisdata/analysisdata.h b/src/gromacs/analysisdata/analysisdata.h
new file mode 100644 (file)
index 0000000..0564333
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \file
+ * \brief
+ * Declares gmx::AnalysisData and related classes.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \inpublicapi
+ * \ingroup module_analysisdata
+ */
+#ifndef GMX_ANALYSISDATA_ANALYSISDATA_H
+#define GMX_ANALYSISDATA_ANALYSISDATA_H
+
+#include "abstractdata.h"
+
+namespace gmx
+{
+
+class AnalysisDataHandle;
+
+//! Placeholder type for parallelization options.
+typedef void *AnalysisDataParallelOptions;
+
+/*! \brief
+ * Parallelizable data container for raw data.
+ *
+ * This is the only data object (in addition to the tightly coupled
+ * \c AnalysisDataHandle object) that needs explicit parallelization.
+ *
+ * Special note for MPI implementation: assuming that the initialization of
+ * data objects is identical in all processes, associating the data objects
+ * in different MPI processes should be possible without changes in the
+ * interface.
+ * Alternative, more robust implementation could get a unique ID as parameter
+ * to the constructor or a separate function, but would require all tools to
+ * provide it.
+ *
+ * \inpublicapi
+ * \ingroup module_analysisdata
+ */
+class AnalysisData : public AbstractAnalysisDataStored
+{
+    public:
+        //! Creates an empty analysis data object.
+        AnalysisData();
+        virtual ~AnalysisData();
+
+        /*! \brief
+         * Sets the number of columns in the data and type of the data.
+         *
+         * \see isMultipoint()
+         */
+        void setColumns(int ncol, bool multipoint = false);
+
+        /*! \brief
+         * Create a handle for adding data.
+         *
+         * \param[out] handlep The created handle is stored in \p *handlep.
+         * \param[in]  opt     Options for setting how this handle will be
+         *     used.
+         */
+        int startData(AnalysisDataHandle **handlep,
+                      AnalysisDataParallelOptions opt);
+        /*! \brief
+         * Destroy a handle after all data has been added.
+         *
+         * \param[in]  handle  Handle to destroy.
+         *
+         * The pointer \p handle is invalid after the call.
+         */
+        int finishData(AnalysisDataHandle *handle);
+
+    private:
+        class Impl;
+
+        Impl                *_impl;
+
+        friend class Impl;
+        friend class AnalysisDataHandle;
+
+        // Copy and assign disallowed by base class.
+};
+
+
+/*! \brief
+ * Handle for inserting data into AnalysisData.
+ *
+ * Several handles can exist concurrently.
+ *
+ * \inpublicapi
+ * \ingroup module_analysisdata
+ */
+class AnalysisDataHandle
+{
+    public:
+        //! Start data for a new frame.
+        int startFrame(int index, real x, real dx = 0.0);
+        //! Add a data point for in single column for the current frame.
+        int addPoint(int col, real y, real dy = 0.0, bool present = true);
+        //! Add multiple data points in neighboring columns for the current frame.
+        int addPoints(int firstcol, int n,
+                      const real *y, const real *dy = 0,
+                      const bool *present = 0);
+        //! Finish data for the current frame.
+        int finishFrame();
+        //! Convenience function for adding a complete frame.
+        int addFrame(int index, real x, const real *y, const real *dy = 0,
+                     const bool *present = 0);
+        //! Convenience function for adding a complete frame.
+        int addFrame(int index, real x, real dx,
+                     const real *y, const real *dy = 0,
+                     const bool *present = 0);
+        //! Calls AnalysisData::finishData() for this handle.
+        int finishData();
+
+    private:
+        /*! \brief
+         * Creates a new data handle associated with \p data.
+         *
+         * \param  data Data to associate the handle with.
+         *
+         * The constructor is private because data handles should only be
+         * constructed through AnalysisData::startData().
+         */
+        explicit AnalysisDataHandle(AnalysisData *data);
+        /*! \brief
+         * Frees memory allocated for the internal implementation.
+         *
+         * The destructor is private because data handles should only be
+         * deleted by calling AnalysisData::finishData() (or finishData()).
+         */
+        ~AnalysisDataHandle();
+
+        class Impl;
+
+        Impl                *_impl;
+
+        friend class AnalysisData;
+
+        // Disallow copy and assign.
+        AnalysisDataHandle(const AnalysisDataHandle &);
+        void operator =(const AnalysisDataHandle &);
+};
+
+} // namespace gmx
+
+#endif
diff --git a/src/gromacs/analysisdata/arraydata.cpp b/src/gromacs/analysisdata/arraydata.cpp
new file mode 100644 (file)
index 0000000..04e0703
--- /dev/null
@@ -0,0 +1,198 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * Implements classes in arraydata.h.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_analysisdata
+ */
+#include "gromacs/analysisdata/arraydata.h"
+
+#include <cassert>
+
+// Legacy header.
+#include "smalloc.h"
+
+#include "gromacs/fatalerror/fatalerror.h"
+
+namespace gmx
+{
+
+AbstractAnalysisArrayData::AbstractAnalysisArrayData()
+    : _nrows(0), _value(NULL), _xstart(0.0), _xstep(1.0), _bReady(false)
+{
+}
+
+AbstractAnalysisArrayData::~AbstractAnalysisArrayData()
+{
+    sfree(_value);
+}
+
+
+int
+AbstractAnalysisArrayData::frameCount() const
+{
+    return _bReady ? _nrows : 0;
+}
+
+
+int
+AbstractAnalysisArrayData::getDataWErr(int index, real *x, real *dx,
+                                       const real **y, const real **dy,
+                                       const bool **present) const
+{
+    if (index < 0)
+    {
+        index += _nrows;
+        if (index < 0)
+        {
+            GMX_ERROR(eeInvalidValue, "Frame index out of range");
+        }
+    }
+    if (index >= frameCount())
+    {
+        GMX_ERROR(eeInvalidValue, "Frame index out of range");
+    }
+    if (x)
+    {
+        *x = _xstart + index * _xstep;
+    }
+    if (dx)
+    {
+        *dx = 0.0;
+    }
+    if (y)
+    {
+        *y = _value + (index * columnCount());
+    }
+    if (dy)
+    {
+        // TODO: Implement
+        *dy = NULL;
+    }
+    if (present)
+    {
+        // TODO: Implement
+        *present = NULL;
+    }
+    return 0;
+}
+
+
+int
+AbstractAnalysisArrayData::requestStorage(int nframes)
+{
+    return 0;
+}
+
+
+void
+AbstractAnalysisArrayData::setColumnCount(int ncols)
+{
+    assert(!_value);
+    AbstractAnalysisData::setColumnCount(ncols);
+}
+
+
+void
+AbstractAnalysisArrayData::setRowCount(int nrows)
+{
+    assert(nrows > 0);
+    assert(!_value && columnCount() > 0);
+    _nrows = nrows;
+    snew(_value, _nrows * columnCount());
+}
+
+
+void
+AbstractAnalysisArrayData::setXAxis(real start, real step)
+{
+    assert(!_bReady);
+    _xstart = start;
+    _xstep = step;
+}
+
+
+int
+AbstractAnalysisArrayData::valuesReady()
+{
+    assert(columnCount() > 0 && _nrows > 0);
+    if (_bReady)
+    {
+        return 0;
+    }
+    _bReady = true;
+
+    int rc = notifyDataStart();
+    if (rc != 0)
+    {
+        return rc;
+    }
+    for (int i = 0; i < _nrows; ++i)
+    {
+        rc = notifyFrameStart(_xstart + i * _xstep, 0);
+        if (rc != 0)
+        {
+            return rc;
+        }
+        rc = notifyPointsAdd(0, columnCount(), _value + (i * columnCount()),
+                             NULL, NULL);
+        if (rc != 0)
+        {
+            return rc;
+        }
+        rc = notifyFrameFinish();
+        if (rc != 0)
+        {
+            return rc;
+        }
+    }
+    return notifyDataFinish();
+}
+
+
+void
+AbstractAnalysisArrayData::copyContents(const AbstractAnalysisArrayData *src,
+                                        AbstractAnalysisArrayData *dest)
+{
+    assert(src->columnCount() > 0 && src->_nrows > 0 && src->_value);
+    assert(!dest->_value);
+    dest->setColumnCount(src->columnCount());
+    dest->setRowCount(src->_nrows);
+    dest->setXAxis(src->_xstart, src->_xstep);
+    for (int i = 0; i < src->_nrows * src->columnCount(); ++i)
+    {
+        dest->_value[i] = src->_value[i];
+    }
+}
+
+} // namespace gmx
diff --git a/src/gromacs/analysisdata/arraydata.h b/src/gromacs/analysisdata/arraydata.h
new file mode 100644 (file)
index 0000000..4c7d4b3
--- /dev/null
@@ -0,0 +1,179 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \file
+ * \brief
+ * Declares gmx::AbstractAnalysisArrayData and gmx::AnalysisArrayData.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \inpublicapi
+ * \ingroup module_analysisdata
+ */
+#ifndef GMX_ANALYSISDATA_ARRAYDATA_H
+#define GMX_ANALYSISDATA_ARRAYDATA_H
+
+#include <cassert>
+
+#include "abstractdata.h"
+
+namespace gmx
+{
+
+/*! \brief
+ * Abstract base class for data objects that present in-memory data.
+ *
+ * This class implements a subclass of AbstractAnalysisData that presents an
+ * in-memory array through the AbstractAnalysisData interface.  Subclasses
+ * should initialize the in-memory array through the provided protected member
+ * functions.
+ *
+ * \ingroup module_analysisdata
+ */
+class AbstractAnalysisArrayData : public AbstractAnalysisData
+{
+    public:
+        virtual ~AbstractAnalysisArrayData();
+
+        virtual int frameCount() const;
+        virtual int getDataWErr(int index, real *x, real *dx,
+                                const real **y, const real **dy,
+                                const bool **present = 0) const;
+        virtual int requestStorage(int nframes = -1);
+
+    protected:
+        AbstractAnalysisArrayData();
+
+        /*! \brief
+         * Returns the number of rows in the data array.
+         *
+         * This function is identical to frameCount(), except that frameCount()
+         * returns 0 before valuesReady() has been called.
+         */
+        int rowCount() const { return _nrows; }
+        /*! \brief
+         * Sets the number of columns in the data array.
+         */
+        void setColumnCount(int ncols);
+        /*! \brief
+         * Sets the number of rows in the data array.
+         */
+        void setRowCount(int nrows);
+        //! Returns the x value of the first frame.
+        real xstart() const { return _xstart; }
+        //! Returns the step between frame x values.
+        real xstep() const { return _xstep; }
+        /*! \brief
+         * Sets the values reported as x values for frames.
+         */
+        void setXAxis(real start, real step);
+        //! Returns a reference to a given array element.
+        real &value(int row, int col)
+        {
+            assert(row >= 0 && row < _nrows);
+            assert(col >= 0 && col < columnCount());
+            assert(_value);
+            return _value[row * columnCount() + col];
+        }
+        //! Returns a given array element.
+        const real &value(int row, int col) const
+        {
+            assert(row >= 0 && row < _nrows);
+            assert(col >= 0 && col < columnCount());
+            assert(_value);
+            return _value[row * columnCount() + col];
+        }
+        /*! \brief
+         * Sets the value of an element in the array.
+         */
+        void setValue(int row, int col, real val)
+        {
+            value(row, col) = val;
+        }
+        /*! \brief
+         * Notifies modules of the data.
+         *
+         * This function should be called once the values in the array
+         * have been initialized. The values should not be changed after this
+         * function has been called.
+         */
+        int valuesReady();
+
+        /*! \brief
+         * Copies the contents into a new object.
+         *
+         * \param[in]     src  Object to copy data from.
+         * \param[in,out] dest Empty array data object to copy data to.
+         *
+         * \p dest should not have previous contents.
+         */
+        static void copyContents(const AbstractAnalysisArrayData *src,
+                                 AbstractAnalysisArrayData *dest);
+
+    private:
+        int                  _nrows;
+        real                *_value;
+        real                 _xstart;
+        real                 _xstep;
+        bool                 _bReady;
+
+        // Copy and assign disallowed by base.
+};
+
+/*! \brief
+ * Simple in-memory data array.
+ *
+ * This class simply exposes the protected functions of
+ * AbstractAnalysisArrayData to allow construction of simple in-memory data
+ * arrays for input into data modules.
+ *
+ * \inpublicapi
+ * \ingroup module_analysisdata
+ */
+class AnalysisArrayData : public AbstractAnalysisArrayData
+{
+    public:
+        AnalysisArrayData() {}
+
+        using AbstractAnalysisArrayData::rowCount;
+        using AbstractAnalysisArrayData::setColumnCount;
+        using AbstractAnalysisArrayData::setRowCount;
+        using AbstractAnalysisArrayData::xstart;
+        using AbstractAnalysisArrayData::xstep;
+        using AbstractAnalysisArrayData::setXAxis;
+        using AbstractAnalysisArrayData::value;
+        using AbstractAnalysisArrayData::setValue;
+        using AbstractAnalysisArrayData::valuesReady;
+
+        // Copy and assign disallowed by base.
+};
+
+} // namespace gmx
+
+#endif
diff --git a/src/gromacs/analysisdata/datamodule.h b/src/gromacs/analysisdata/datamodule.h
new file mode 100644 (file)
index 0000000..93dbd9e
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \libinternal \file
+ * \brief
+ * Declares gmx::AnalysisDataModuleInterface.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \inlibraryapi
+ * \ingroup module_analysisdata
+ */
+#ifndef GMX_ANALYSISDATA_DATAMODULE_H
+#define GMX_ANALYSISDATA_DATAMODULE_H
+
+#include "../legacyheaders/types/simple.h"
+
+namespace gmx
+{
+
+class AbstractAnalysisData;
+
+/*! \brief
+ * Interface for a module that gets notified whenever data is added.
+ *
+ * The interface provides one method (flags()) that describes features of
+ * data objects the module supports. Only most common features are included
+ * in the flags; custom checks can be implemented in the dataStarted() method
+ * (see below).
+ * All other methods in the interface are callbacks that are called by the
+ * data object to which the module is attached to describe the data.
+ *
+ * \inlibraryapi
+ * \ingroup module_analysisdata
+ */
+class AnalysisDataModuleInterface
+{
+    public:
+        /*! \brief
+         * Possible flags for flags().
+         */
+        enum {
+            //! The module can process multipoint data.
+            efAllowMultipoint    = 0x01,
+            //! The module does not make sense for non-multipoint data.
+            efOnlyMultipoint     = 0x02,
+            //! The module can process data with more than one column.
+            efAllowMulticolumn   = 0x04,
+            //! The module can process data with missing points.
+            efAllowMissing       = 0x08,
+        };
+
+        virtual ~AnalysisDataModuleInterface() {};
+
+        /*! \brief
+         * Returns properties supported by the module.
+         *
+         * The return value of this method should not change after the module
+         * has been added to a data (this responsibility can, and in most cases
+         * must, be delegated to the user of the module).
+         *
+         * The purpose of this method is to remove the need for common checks
+         * for data compatibility in the classes that implement the interface.
+         * Instead, AbstractData performs these checks based on the flags
+         * provided.
+         */
+        virtual int flags() const = 0;
+
+        /*! \brief
+         * Called (once) when the data has been set up properly.
+         *
+         * The data to which the module is attached is passed as an argument
+         * to provide access to properties of the data for initialization
+         * and/or validation.
+         * This is the only place where the module gets access to the data;
+         * if properties of the data are required later, the module should
+         * store them internally. It is guaranteed that the data properties
+         * (column count, whether it's multipoint) do not change once this
+         * method has been called.
+         */
+        virtual int dataStarted(AbstractAnalysisData *data) = 0;
+        /*! \brief
+         * Called at the start of each data frame.
+         */
+        virtual int frameStarted(real x, real dx) = 0;
+        /*! \brief
+         * Called one or more times during each data frame.
+         *
+         * For convenience, the \p x and \p dx values for the frame are
+         * passed to each call of this function.
+         */
+        virtual int pointsAdded(real x, real dx, int firstcol, int n,
+                                const real *y, const real *dy,
+                                const bool *present) = 0;
+        /*! \brief
+         * Called when a data frame is finished.
+         */
+        virtual int frameFinished() = 0;
+        /*! \brief
+         * Called (once) when no more data is available.
+         */
+        virtual int dataFinished() = 0;
+
+    protected:
+        AnalysisDataModuleInterface() {}
+};
+
+} // namespace gmx
+
+#endif
diff --git a/src/gromacs/analysisdata/dataproxy.cpp b/src/gromacs/analysisdata/dataproxy.cpp
new file mode 100644 (file)
index 0000000..becb5d8
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * Implements gmx::AnalysisDataProxy.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_analysisdata
+ */
+#include "dataproxy.h"
+
+#include <cassert>
+
+namespace gmx
+{
+
+AnalysisDataProxy::AnalysisDataProxy(int col, int span,
+                                     AbstractAnalysisData *data)
+    : _source(*data), _col(col), _span(span)
+{
+    assert(data);
+    assert(col >= 0 && span > 0);
+    setColumnCount(span);
+    setMultipoint(_source.isMultipoint());
+}
+
+
+int
+AnalysisDataProxy::frameCount() const
+{
+    return _source.frameCount();
+}
+
+
+int
+AnalysisDataProxy::getDataWErr(int index, real *x, real *dx,
+                               const real **y, const real **dy,
+                               const bool **missing) const
+{
+    int rc = _source.getDataWErr(index, x, dx, y, dy, missing);
+    if (rc == 0)
+    {
+        if (y && *y)
+        {
+            *y += _col;
+        }
+        if (dy && *dy)
+        {
+            *dy += _col;
+        }
+        if (missing && *missing)
+        {
+            *missing += _col;
+        }
+    }
+    return rc;
+}
+
+
+int
+AnalysisDataProxy::requestStorage(int nframes)
+{
+    return _source.requestStorage(nframes);
+}
+
+
+int
+AnalysisDataProxy::flags() const
+{
+    return efAllowMultipoint | efAllowMulticolumn | efAllowMissing;
+}
+
+
+int
+AnalysisDataProxy::dataStarted(AbstractAnalysisData *data)
+{
+    assert(data == &_source);
+    assert(_col + _span <= _source.columnCount());
+    return notifyDataStart();
+}
+
+
+int
+AnalysisDataProxy::frameStarted(real x, real dx)
+{
+    return notifyFrameStart(x, dx);
+}
+
+
+int
+AnalysisDataProxy::pointsAdded(real x, real dx, int firstcol, int n,
+                               const real *y, const real *dy,
+                               const bool *missing)
+{
+    if (firstcol + n <= _col || firstcol >= _col + _span)
+    {
+        return 0;
+    }
+    firstcol -= _col;
+    if (firstcol < 0)
+    {
+        if (y)
+        {
+            y +=  -firstcol;
+        }
+        if (dy)
+        {
+            dy += -firstcol;
+        }
+        if (missing)
+        {
+            missing += -firstcol;
+        }
+        n -= -firstcol;
+        firstcol = 0;
+    }
+    if (firstcol + n > _span)
+    {
+        n = _span - firstcol;
+    }
+    return notifyPointsAdd(firstcol, n, y, dy, missing);
+}
+
+
+int
+AnalysisDataProxy::frameFinished()
+{
+    return notifyFrameFinish();
+}
+
+
+int
+AnalysisDataProxy::dataFinished()
+{
+    return notifyDataFinish();
+}
+
+} // namespace gmx
diff --git a/src/gromacs/analysisdata/dataproxy.h b/src/gromacs/analysisdata/dataproxy.h
new file mode 100644 (file)
index 0000000..7e63656
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * Declares gmx::AnalysisDataProxy.
+ *
+ * This header is only meant for internal use of the gmx::AbstractAnalysisData
+ * class to implement modules that handle only a subset of columns.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_analysisdata
+ */
+#ifndef GMX_ANALYSISDATA_DATAPROXY_H
+#define GMX_ANALYSISDATA_DATAPROXY_H
+
+#include "abstractdata.h"
+#include "datamodule.h"
+
+namespace gmx
+{
+
+/*! \internal \brief
+ * Internal implementation class used to implement column modules.
+ *
+ * \ingroup module_analysisdata
+ */
+class AnalysisDataProxy : public AbstractAnalysisData,
+                          public AnalysisDataModuleInterface
+{
+    public:
+        /*! \brief
+         * Creates a proxy object that only presents certain columns.
+         *
+         * \param[in] col   First column to present.
+         * \param[in] span  Number of columns to present.
+         * \param[in] data  Data object that should be wrapped.
+         */
+        AnalysisDataProxy(int col, int span, AbstractAnalysisData *data);
+
+        virtual int frameCount() const;
+        virtual int getDataWErr(int index, real *x, real *dx,
+                                const real **y, const real **dy,
+                                const bool **missing = 0) const;
+        virtual int requestStorage(int nframes = -1);
+
+        virtual int flags() const;
+
+        virtual int dataStarted(AbstractAnalysisData *data);
+        virtual int frameStarted(real x, real dx);
+        virtual int pointsAdded(real x, real dx, int firstcol, int n,
+                                const real *y, const real *dy,
+                                const bool *missing);
+        virtual int frameFinished();
+        virtual int dataFinished();
+
+    private:
+        AbstractAnalysisData   &_source;
+        int                     _col;
+        int                     _span;
+
+        // Copy and assign disallowed by base.
+};
+
+} // namespace gmx
+
+#endif
diff --git a/src/gromacs/analysisdata/modules/CMakeLists.txt b/src/gromacs/analysisdata/modules/CMakeLists.txt
new file mode 100644 (file)
index 0000000..61b3e75
--- /dev/null
@@ -0,0 +1,8 @@
+set(ANALYSISDATA_MODULES_PUBLIC_HEADERS
+    average.h
+    displacement.h
+    histogram.h
+    plot.h)
+install(FILES ${ANALYSISDATA_MODULES_PUBLIC_HEADERS}
+        DESTINATION ${INCL_INSTALL_DIR}/gromacs/analysisdata/modules
+        COMPONENT development)
diff --git a/src/gromacs/analysisdata/modules/average.cpp b/src/gromacs/analysisdata/modules/average.cpp
new file mode 100644 (file)
index 0000000..da7ad90
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * Implements gmx::AnalysisDataAverageModule.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_analysisdata
+ */
+#include "gromacs/analysisdata/modules/average.h"
+
+#include <cmath>
+
+// Legacy include
+#include "smalloc.h"
+
+#include "gromacs/basicmath.h"
+
+namespace gmx
+{
+
+AnalysisDataAverageModule::AnalysisDataAverageModule()
+    : _nsamples(NULL)
+{
+    setColumnCount(2);
+}
+
+
+AnalysisDataAverageModule::~AnalysisDataAverageModule()
+{
+    sfree(_nsamples);
+}
+
+
+int
+AnalysisDataAverageModule::flags() const
+{
+    return efAllowMultipoint | efAllowMulticolumn | efAllowMissing;
+}
+
+
+int
+AnalysisDataAverageModule::dataStarted(AbstractAnalysisData *data)
+{
+    int nrows = data->columnCount();
+    setRowCount(nrows);
+    snew(_nsamples, nrows);
+    return 0;
+}
+
+
+int
+AnalysisDataAverageModule::frameStarted(real x, real dx)
+{
+    return 0;
+}
+
+
+int
+AnalysisDataAverageModule::pointsAdded(real x, real dx, int firstcol, int n,
+                                       const real *y, const real *dy,
+                                       const bool *present)
+{
+    for (int i = 0; i < n; ++i)
+    {
+        if (!present || present[i])
+        {
+            value(firstcol + i, 0)  += y[i];
+            value(firstcol + i, 1)  += y[i] * y[i];
+            _nsamples[firstcol + i] += 1;
+        }
+    }
+    return 0;
+}
+
+
+int
+AnalysisDataAverageModule::frameFinished()
+{
+    return 0;
+}
+
+
+int
+AnalysisDataAverageModule::dataFinished()
+{
+    for (int i = 0; i < rowCount(); ++i)
+    {
+        real ave = value(i, 0) / _nsamples[i];
+        real std = sqrt(value(i, 1) / _nsamples[i] - ave * ave);
+        setValue(i, 0, ave);
+        setValue(i, 1, std);
+    }
+    return valuesReady();
+}
+
+
+real
+AnalysisDataAverageModule::average(int index) const
+{
+    return value(index, 0);
+}
+
+
+real
+AnalysisDataAverageModule::stddev(int index) const
+{
+    return value(index, 1);
+}
+
+} // namespace gmx
diff --git a/src/gromacs/analysisdata/modules/average.h b/src/gromacs/analysisdata/modules/average.h
new file mode 100644 (file)
index 0000000..1aa5151
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \file
+ * \brief
+ * Declares gmx::AnalysisDataAverageModule.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \inpublicapi
+ * \ingroup module_analysisdata
+ */
+#ifndef GMX_ANALYSISDATA_MODULES_AVERAGE_H
+#define GMX_ANALYSISDATA_MODULES_AVERAGE_H
+
+#include "../arraydata.h"
+#include "../datamodule.h"
+
+namespace gmx
+{
+
+/*! \brief
+ * Data module for simple averaging of columns.
+ *
+ * Output data contains a frame for each column of input data.
+ * There are two columns: the average and standard deviation of
+ * that column.
+ * The data becomes available only after the original data has been
+ * finished.
+ *
+ * Multipoint data and missing data points are both supported. The average
+ * is always calculated over all data points present in a column.
+ *
+ * \inpublicapi
+ * \ingroup module_analysisdata
+ */
+class AnalysisDataAverageModule : public AbstractAnalysisArrayData,
+                                  public AnalysisDataModuleInterface
+{
+    public:
+        AnalysisDataAverageModule();
+        virtual ~AnalysisDataAverageModule();
+
+        using AbstractAnalysisArrayData::setXAxis;
+
+        virtual int flags() const;
+
+        virtual int dataStarted(AbstractAnalysisData *data);
+        virtual int frameStarted(real x, real dx);
+        virtual int pointsAdded(real x, real dx, int firstcol, int n,
+                                const real *y, const real *dy,
+                                const bool *present);
+        virtual int frameFinished();
+        virtual int 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;
+
+    private:
+        int                    *_nsamples;
+
+        // Copy and assign disallowed by base.
+};
+
+} // namespace gmx
+
+#endif
diff --git a/src/gromacs/analysisdata/modules/displacement-impl.h b/src/gromacs/analysisdata/modules/displacement-impl.h
new file mode 100644 (file)
index 0000000..3d6b0f6
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * Declares private implementation class for
+ * gmx::AnalysisDataDisplacementModule.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_analysisdata
+ */
+#ifndef GMX_ANALYSISDATA_MODULES_DISPLACEMENT_IMPL_H
+#define GMX_ANALYSISDATA_MODULES_DISPLACEMENT_IMPL_H
+
+#include "displacement.h"
+
+namespace gmx
+{
+
+class AbstractHistogramModule;
+
+/*! \internal \brief
+ * Private implementation class for AnalysisDataDisplacementModule.
+ *
+ * \ingroup module_analysisdata
+ */
+class AnalysisDataDisplacementModule::Impl
+{
+    public:
+        Impl();
+        ~Impl();
+
+        //! Maximum number of particles for which the displacements are calculated.
+        int                     nmax;
+        //! Maximum time for which the displacements are needed.
+        real                    tmax;
+        //! Number of dimensions per data point.
+        int                     ndim;
+
+        //! TRUE if no frames have been read.
+        bool                    bFirst;
+        //! Stores the time of the first frame.
+        real                    t0;
+        //! Stores the time interval between frames.
+        real                    dt;
+        //! Stores the time of the current frame.
+        real                    t;
+        //! Stores the index in the store for the current positions.
+        int                     ci;
+
+        //! Maximum number of positions to store for a particle.
+        int                     max_store;
+        //! The total number of positions ever stored (can be larger than \p max_store).
+        int                     nstored;
+        //! Old values.
+        real                   *oldval;
+        //! The most recently calculated displacements.
+        real                   *currd;
+
+        //! Histogram module for calculating MSD histograms, or NULL if not set.
+        AbstractHistogramModule *histm;
+};
+
+} // namespace gmx
+
+#endif
diff --git a/src/gromacs/analysisdata/modules/displacement.cpp b/src/gromacs/analysisdata/modules/displacement.cpp
new file mode 100644 (file)
index 0000000..c20c11d
--- /dev/null
@@ -0,0 +1,298 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * Implements gmx::AnalysisDataDisplacementModule.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_analysisdata
+ */
+#include "gromacs/analysisdata/modules/displacement.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+// Legacy include.
+#include "smalloc.h"
+
+#include "gromacs/analysisdata/modules/histogram.h"
+#include "gromacs/basicmath.h"
+#include "gromacs/fatalerror/fatalerror.h"
+
+#include "displacement-impl.h"
+
+namespace gmx
+{
+
+/********************************************************************
+ * AnalysisDataDisplacementModule::Impl
+ */
+
+AnalysisDataDisplacementModule::Impl::Impl()
+    : nmax(0), tmax(0.0), ndim(3),
+      bFirst(true), t0(0.0), dt(0.0), t(0.0),
+      max_store(-1), nstored(0), oldval(NULL), currd(NULL),
+      histm(NULL)
+{
+}
+
+AnalysisDataDisplacementModule::Impl::~Impl()
+{
+    sfree(oldval);
+    sfree(currd);
+}
+
+/********************************************************************
+ * AnalysisDataDisplacementModule
+ */
+
+AnalysisDataDisplacementModule::AnalysisDataDisplacementModule()
+    : _impl(new Impl())
+{
+    setMultipoint(true);
+}
+
+
+AnalysisDataDisplacementModule::~AnalysisDataDisplacementModule()
+{
+    delete _impl;
+}
+
+
+void
+AnalysisDataDisplacementModule::setMaxTime(real tmax)
+{
+    _impl->tmax = tmax;
+}
+
+
+int
+AnalysisDataDisplacementModule::setMSDHistogram(AnalysisDataBinAverageModule *histm)
+{
+    assert(!_impl->histm);
+    _impl->histm = histm;
+    histm->setIgnoreMissing(true);
+    return addModule(histm);
+}
+
+
+int
+AnalysisDataDisplacementModule::frameCount() const
+{
+    return _impl->nstored > 1 ? _impl->nstored - 1 : 0;
+}
+
+
+int
+AnalysisDataDisplacementModule::getDataWErr(int index, real *x, real *dx,
+                                            const real **y, const real **dy,
+                                            const bool **present) const
+{
+    return eedataDataNotAvailable;
+}
+
+
+int
+AnalysisDataDisplacementModule::requestStorage(int nframes)
+{
+    GMX_ERROR(eeNotImplemented, "Displacement storage not supported");
+}
+
+
+int
+AnalysisDataDisplacementModule::flags() const
+{
+    return efAllowMulticolumn;
+}
+
+
+int
+AnalysisDataDisplacementModule::dataStarted(AbstractAnalysisData *data)
+{
+    if (data->columnCount() % _impl->ndim != 0)
+    {
+        GMX_ERROR(eeInvalidValue, "Data has incorrect number of columns");
+    }
+    _impl->nmax = data->columnCount();
+    snew(_impl->oldval, _impl->nmax);
+    _impl->ci = -_impl->nmax;
+
+    int ncol = _impl->nmax / _impl->ndim + 1;
+    snew(_impl->currd, ncol);
+    setColumnCount(ncol);
+
+    return 0;
+}
+
+
+int
+AnalysisDataDisplacementModule::frameStarted(real x, real dx)
+{
+    // Initialize times.
+    if (_impl->bFirst)
+    {
+        _impl->t0 = x;
+    }
+    else if (_impl->dt <= 0)
+    {
+        _impl->dt = x - _impl->t0;
+        if (_impl->dt < 0 || gmx_within_tol(_impl->dt, 0.0, GMX_REAL_EPS))
+        {
+            GMX_ERROR(eeInvalidInput, "Identical or decreasing frame times");
+        }
+    }
+    else
+    {
+        if (!gmx_within_tol(x - _impl->t, _impl->dt, GMX_REAL_EPS))
+        {
+            GMX_ERROR(eeInvalidInput, "Frames not evenly spaced");
+        }
+    }
+    _impl->t = x;
+
+    // Allocate memory for all the positions once it is possible.
+    if (_impl->max_store == -1 && !_impl->bFirst)
+    {
+        _impl->max_store = _impl->nmax * (int)(_impl->tmax/_impl->dt + 1);
+        srenew(_impl->oldval, _impl->max_store);
+    }
+
+    // Increment the index where current positions are stored.
+    _impl->ci += _impl->nmax;
+    if (_impl->ci >= _impl->max_store)
+    {
+        _impl->ci = 0;
+    }
+
+/*
+    for (int i = 0; i < _impl->nmax; ++i)
+    {
+        _impl->p[_impl->ci + i].bPres = false;
+    }
+*/
+    _impl->nstored++;
+    _impl->bFirst = false;
+    return 0;
+}
+
+
+int
+AnalysisDataDisplacementModule::pointsAdded(real x, real dx, int firstcol, int n,
+                                            const real *y, const real *dy,
+                                            const bool *present)
+{
+    if (firstcol % _impl->ndim != 0 || n % _impl->ndim != 0)
+    {
+        GMX_ERROR(eeInvalidValue, "Partial data points");
+    }
+    for (int i = firstcol; i < firstcol + n; ++i)
+    {
+        _impl->oldval[_impl->ci + i] = y[i];
+    }
+    return 0;
+}
+
+
+int
+AnalysisDataDisplacementModule::frameFinished()
+{
+    if (_impl->nstored <= 1)
+    {
+        return 0;
+    }
+
+    int step, i;
+    int rc;
+
+    if (_impl->nstored == 2)
+    {
+        if (_impl->histm)
+        {
+            _impl->histm->initNBins(0, _impl->dt,
+                                    _impl->max_store / _impl->nmax, true);
+        }
+        rc = notifyDataStart();
+        if (rc != 0)
+        {
+            _impl->nstored = 1;
+            return rc;
+        }
+    }
+    rc = notifyFrameStart(_impl->t, 0);
+    if (rc != 0)
+    {
+        return rc;
+    }
+
+    for (i = _impl->ci - _impl->nmax, step = 1;
+         step < _impl->nstored && i != _impl->ci;
+         i -= _impl->nmax, ++step)
+    {
+        if (i < 0)
+        {
+            i += _impl->max_store;
+        }
+        _impl->currd[0] = step * _impl->dt;
+        int k = 1;
+        for (int j = 0; j < _impl->nmax; j += _impl->ndim, ++k)
+        {
+            real dist2 = 0.0;
+
+            for (int d = 0; d < _impl->ndim; ++d)
+            {
+                dist2 += sqr(_impl->oldval[_impl->ci + j + d]
+                             - _impl->oldval[i + j + d]);
+            }
+            _impl->currd[k] = dist2;
+        }
+        rc = notifyPointsAdd(0, k, _impl->currd, NULL, NULL);
+        if (rc != 0)
+        {
+            return rc;
+        }
+    }
+
+    return notifyFrameFinish();
+}
+
+
+int
+AnalysisDataDisplacementModule::dataFinished()
+{
+    if (_impl->nstored >= 2)
+    {
+        return notifyDataFinish();
+    }
+    return 0;
+}
+
+} // namespace gmx
diff --git a/src/gromacs/analysisdata/modules/displacement.h b/src/gromacs/analysisdata/modules/displacement.h
new file mode 100644 (file)
index 0000000..dbbd9c8
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \file
+ * \brief
+ * Declares gmx::AnalysisDataDisplacementModule.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \inpublicapi
+ * \ingroup module_analysisdata
+ */
+#ifndef GMX_ANALYSISDATA_MODULES_DISPLACEMENT_H
+#define GMX_ANALYSISDATA_MODULES_DISPLACEMENT_H
+
+#include "../analysisdata.h"
+#include "../datamodule.h"
+
+namespace gmx
+{
+
+class AnalysisDataBinAverageModule;
+
+/*! \brief
+ * Data module for calculating displacements.
+ *
+ * Output data contains a frame for each frame in the input data except the
+ * first one.  For each frame, there can be multiple points, each of which
+ * describes displacement for a certain time difference ending that that frame.
+ * The first column contains the time difference (backwards from the current
+ * frame), and the remaining columns the sizes of the displacements.
+ *
+ * Current implementation is not very generic, but should be easy to extend.
+ *
+ * \inpublicapi
+ * \ingroup module_analysisdata
+ */
+class AnalysisDataDisplacementModule : public AbstractAnalysisData,
+                                       public AnalysisDataModuleInterface
+{
+    public:
+        AnalysisDataDisplacementModule();
+        virtual ~AnalysisDataDisplacementModule();
+
+        /*! \brief
+         * Sets the largest displacement time to be calculated.
+         */
+        void setMaxTime(real tmax);
+        /*! \brief
+         * Sets an histogram module that will receive a MSD histogram.
+         *
+         * If this function is not called, no histogram is calculated.
+         */
+        int setMSDHistogram(AnalysisDataBinAverageModule *histm);
+
+        virtual int frameCount() const;
+        virtual int getDataWErr(int index, real *x, real *dx,
+                                const real **y, const real **dy,
+                                const bool **present = 0) const;
+        virtual int requestStorage(int nframes = -1);
+
+        virtual int flags() const;
+
+        virtual int dataStarted(AbstractAnalysisData *data);
+        virtual int frameStarted(real x, real dx);
+        virtual int pointsAdded(real x, real dx, int firstcol, int n,
+                                const real *y, const real *dy,
+                                const bool *present);
+        virtual int frameFinished();
+        virtual int dataFinished();
+
+    private:
+        class Impl;
+
+        Impl                   *_impl;
+};
+
+} // namespace gmx
+
+#endif
diff --git a/src/gromacs/analysisdata/modules/histogram.cpp b/src/gromacs/analysisdata/modules/histogram.cpp
new file mode 100644 (file)
index 0000000..f760527
--- /dev/null
@@ -0,0 +1,527 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * Implements classes in histogram.h.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_analysisdata
+ */
+#include "gromacs/analysisdata/modules/histogram.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <cassert>
+#include <cmath>
+
+// Legacy include.
+#include "smalloc.h"
+
+#include "gromacs/basicmath.h"
+#include "gromacs/fatalerror/fatalerror.h"
+
+namespace gmx
+{
+
+/********************************************************************
+ * AbstractHistogramModule
+ */
+
+AbstractHistogramModule::AbstractHistogramModule()
+    : _hist(NULL), _averager(NULL), _nbins(0)
+{
+}
+
+AbstractHistogramModule::~AbstractHistogramModule()
+{
+    sfree(_hist);
+}
+
+
+int
+AbstractHistogramModule::initNBins(real miny, real binw, int nbins,
+                                   bool bIntegerBins)
+{
+    assert(nbins > 0 && binw > 0);
+    if (bIntegerBins)
+    {
+        miny -= 0.5*binw;
+    }
+    _nbins    = nbins;
+    _miny     = miny;
+    _binwidth = binw;
+    _maxy     = miny + nbins * binw;
+    _invbw    = 1.0/binw;
+    setColumnCount(_nbins);
+    return 0;
+}
+
+
+int
+AbstractHistogramModule::initRange(real miny, real maxy, real binw,
+                                   bool bIntegerBins)
+{
+    assert(miny < maxy && binw > 0);
+    if (bIntegerBins)
+    {
+        _nbins = ceil((maxy - miny) / binw) + 1;
+        miny -= 0.5 * binw;
+        maxy  = miny + _nbins * binw;
+    }
+    else
+    {
+        miny = binw * floor(miny / binw);
+        maxy = binw * ceil(maxy / binw);
+        if (miny != 0)
+        {
+            miny -= binw;
+        }
+        maxy += binw;
+        _nbins = (int)((maxy - miny) / binw + 0.5);
+    }
+    _miny     = miny;
+    _maxy     = maxy;
+    _binwidth = binw;
+    _invbw    = 1.0/binw;
+    setColumnCount(_nbins);
+    return 0;
+}
+
+
+void
+AbstractHistogramModule::setAll(bool bAll)
+{
+    _bAll = bAll;
+}
+
+
+int
+AbstractHistogramModule::findBin(real y) const
+{
+    if (y < _miny)
+    {
+        return _bAll ? 0 : -1;
+    }
+    else if (y >= _maxy)
+    {
+        return _bAll ? _nbins-1 : -1;
+    }
+    return (int)((y - _miny) * _invbw);
+}
+
+
+HistogramAverageModule *
+AbstractHistogramModule::averager()
+{
+    if (!_averager)
+    {
+        createAverager();
+    }
+    return _averager;
+}
+
+
+int
+AbstractHistogramModule::flags() const
+{
+    return efAllowMultipoint;
+}
+
+
+int
+AbstractHistogramModule::dataStarted(AbstractAnalysisData *data)
+{
+    if (!_averager)
+    {
+        createAverager();
+    }
+    _averager->setXAxis(_miny + 0.5 * _binwidth, _binwidth);
+    snew(_hist, nbins());
+    return startDataStore();
+}
+
+
+int
+AbstractHistogramModule::frameStarted(real x, real dx)
+{
+    for (int i = 0; i < nbins(); ++i)
+    {
+        _hist[i] = 0.0;
+    }
+    return startNextFrame(x, dx);
+}
+
+
+int
+AbstractHistogramModule::frameFinished()
+{
+    return storeThisFrame(_hist, NULL, NULL);
+}
+
+
+int
+AbstractHistogramModule::dataFinished()
+{
+    return notifyDataFinish();
+}
+
+
+void
+AbstractHistogramModule::createAverager()
+{
+    _averager = new HistogramAverageModule();
+    addModule(_averager);
+    _averager->setXAxis(_miny + 0.5 * _binwidth, _binwidth);
+}
+
+
+/********************************************************************
+ * HistogramAverageModule
+ */
+
+HistogramAverageModule::HistogramAverageModule()
+    : _nframes(0), _bIgnoreMissing(false)
+{
+    setColumnCount(2);
+}
+
+
+void
+HistogramAverageModule::setIgnoreMissing(bool bIgnoreMissing)
+{
+    _bIgnoreMissing = bIgnoreMissing;
+    setColumnCount(bIgnoreMissing ? 3 : 2);
+}
+
+
+int
+HistogramAverageModule::flags() const
+{
+    return efAllowMulticolumn | efAllowMissing;
+}
+
+
+int
+HistogramAverageModule::dataStarted(AbstractAnalysisData *data)
+{
+    setRowCount(data->columnCount());
+    return 0;
+}
+
+
+int
+HistogramAverageModule::frameStarted(real x, real dx)
+{
+    return 0;
+}
+
+
+int
+HistogramAverageModule::pointsAdded(real x, real dx, int firstcol, int n,
+                                    const real *y, const real *dy,
+                                    const bool *present)
+{
+    for (int i = 0; i < n; ++i)
+    {
+        value(firstcol + i, 0) += y[i];
+        value(firstcol + i, 1) += y[i] * y[i];
+    }
+    if (_bIgnoreMissing)
+    {
+        assert(present != NULL);
+        for (int i = 0; i < n; ++i)
+        {
+            if (present[i])
+            {
+                value(firstcol + i, 2) += 1;
+            }
+        }
+    }
+    return 0;
+}
+
+
+int
+HistogramAverageModule::frameFinished()
+{
+    ++_nframes;
+    return 0;
+}
+
+
+int
+HistogramAverageModule::dataFinished()
+{
+    for (int i = 0; i < rowCount(); ++i)
+    {
+        real ave = 0.0;
+        real std = 0.0;
+        if (_bIgnoreMissing)
+        {
+            if (value(i, 2) > 0)
+            {
+                ave = value(i, 0) / value(i, 2);
+                std = sqrt(value(i, 1) / value(i, 2) - ave * ave);
+            }
+        }
+        else
+        {
+            ave = value(i, 0) / _nframes;
+            std = sqrt(value(i, 1) / _nframes - ave * ave);
+        }
+        setValue(i, 0, ave);
+        setValue(i, 1, std);
+    }
+    return 0;
+}
+
+
+HistogramAverageModule *
+HistogramAverageModule::resampleDoubleBinWidth(bool bIntegerBins) const
+{
+    HistogramAverageModule *dest = new HistogramAverageModule();
+    int nbins = rowCount() / 2;
+    dest->setRowCount(nbins);
+    real minx = xstart() + xstep() / 2;
+    if (bIntegerBins)
+    {
+        minx -= xstep();
+    }
+    dest->setXAxis(minx, xstep() * 2);
+
+    int  i, j;
+    for (i = j = 0; i < nbins; ++i)
+    {
+        real  v, ve;
+        if (bIntegerBins && i == 0)
+        {
+            v  = value(0, 0);
+            ve = sqr(value(0, 1));
+            ++j;
+        }
+        else
+        {
+            v  =     value(j, 0)  +     value(j+1, 0);
+            ve = sqr(value(j, 1)) + sqr(value(j+1, 1));
+            j += 2;
+        }
+        ve = sqrt(ve);
+        dest->setValue(i, 0, v);
+        dest->setValue(i, 1, ve);
+    }
+    return dest;
+}
+
+
+HistogramAverageModule *
+HistogramAverageModule::clone() const
+{
+    HistogramAverageModule *dest = new HistogramAverageModule();
+    copyContents(this, dest);
+    return dest;
+}
+
+
+void
+HistogramAverageModule::normalizeProbability()
+{
+    real sum = 0;
+    for (int i = 0; i < rowCount(); ++i)
+    {
+        sum += value(i, 0);
+    }
+    scale(1.0 / (sum * xstep()));
+}
+
+
+void
+HistogramAverageModule::scale(real norm)
+{
+    for (int i = 0; i < rowCount(); ++i)
+    {
+        value(i, 0) *= norm;
+        value(i, 1) *= norm;
+    }
+}
+
+
+void
+HistogramAverageModule::scaleVector(real norm[])
+{
+    for (int i = 0; i < rowCount(); ++i)
+    {
+        value(i, 0) *= norm[i];
+        value(i, 1) *= norm[i];
+    }
+}
+
+
+/********************************************************************
+ * AnalysisDataSimpleHistogramModule
+ */
+
+int
+AnalysisDataSimpleHistogramModule::pointsAdded(real /*x*/, real /*dx*/,
+                                               int /*firstcol*/, int n,
+                                               const real *y, const real * /*dy*/,
+                                               const bool * /*present*/)
+{
+    for (int i = 0; i < n; ++i)
+    {
+        int bin = findBin(y[i]);
+        _hist[bin] += 1;
+    }
+    return 0;
+}
+
+
+/********************************************************************
+ * AnalysisDataWeightedHistogramModule
+ */
+
+int
+AnalysisDataWeightedHistogramModule::flags() const
+{
+    return AbstractHistogramModule::flags() | efAllowMulticolumn;
+}
+
+
+int
+AnalysisDataWeightedHistogramModule::pointsAdded(real x, real dx, int firstcol, int n,
+                                                 const real *y, const real *dy,
+                                                 const bool *present)
+{
+    if (firstcol != 0 || n < 2)
+    {
+        GMX_ERROR(eeInvalidValue, "Invalid data layout");
+    }
+    int bin = findBin(y[0]);
+    for (int i = 1; i < n; ++i)
+    {
+        _hist[bin] += y[i];
+    }
+    return 0;
+}
+
+
+/********************************************************************
+ * AnalysisDataBinAverageModule
+ */
+
+AnalysisDataBinAverageModule::AnalysisDataBinAverageModule()
+    : _n(NULL), _present(NULL), _bIgnoreMissing(false)
+{
+}
+
+AnalysisDataBinAverageModule::~AnalysisDataBinAverageModule()
+{
+    sfree(_n);
+    sfree(_present);
+}
+
+
+void
+AnalysisDataBinAverageModule::setIgnoreMissing(bool bIgnoreMissing)
+{
+    // Changes can only be made before there is data.
+    assert(!_n);
+    _bIgnoreMissing = bIgnoreMissing;
+    averager()->setIgnoreMissing(bIgnoreMissing);
+}
+
+
+int
+AnalysisDataBinAverageModule::flags() const
+{
+    return AbstractHistogramModule::flags() | efAllowMulticolumn;
+}
+
+
+int
+AnalysisDataBinAverageModule::dataStarted(AbstractAnalysisData *data)
+{
+    snew(_n, nbins());
+    snew(_present, nbins());
+    return AbstractHistogramModule::dataStarted(data);
+}
+
+
+int
+AnalysisDataBinAverageModule::frameStarted(real x, real dx)
+{
+    for (int i = 0; i < nbins(); ++i)
+    {
+        _n[i] = 0.0;
+    }
+    return AbstractHistogramModule::frameStarted(x, dx);
+}
+
+
+int
+AnalysisDataBinAverageModule::pointsAdded(real x, real dx, int firstcol, int n,
+                                          const real *y, const real *dy,
+                                          const bool *present)
+{
+    if (firstcol != 0 || n < 2)
+    {
+        GMX_ERROR(eeInvalidValue, "Invalid data layout");
+    }
+    int bin = findBin(y[0]);
+    for (int i = 1; i < n; ++i)
+    {
+        _hist[bin] += y[i];
+    }
+    _n[bin] += n - 1;
+    return 0;
+}
+
+
+int
+AnalysisDataBinAverageModule::frameFinished()
+{
+    for (int i = 0; i < nbins(); ++i)
+    {
+        _present[i] = (_n[i] > 0);
+        if (_n[i] > 0)
+        {
+            _hist[i] /= _n[i];
+        }
+    }
+    if (!_bIgnoreMissing)
+    {
+        return AbstractHistogramModule::frameFinished();
+    }
+    return storeThisFrame(_hist, NULL, _present);
+}
+
+} // namespace gmx
diff --git a/src/gromacs/analysisdata/modules/histogram.h b/src/gromacs/analysisdata/modules/histogram.h
new file mode 100644 (file)
index 0000000..233d3bd
--- /dev/null
@@ -0,0 +1,284 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \file
+ * \brief
+ * Declares analysis data modules for calculating histograms.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \inpublicapi
+ * \ingroup module_analysisdata
+ */
+#ifndef GMX_ANALYSISDATA_MODULES_HISTOGRAM_H
+#define GMX_ANALYSISDATA_MODULES_HISTOGRAM_H
+
+#include "../analysisdata.h"
+#include "../arraydata.h"
+#include "../datamodule.h"
+
+namespace gmx
+{
+
+class HistogramAverageModule;
+
+/*! \brief
+ * Abstract base class for per-frame histogram modules.
+ *
+ * \ingroup module_analysisdata
+ */
+class AbstractHistogramModule : public AbstractAnalysisDataStored,
+                                public AnalysisDataModuleInterface
+{
+    public:
+        virtual ~AbstractHistogramModule();
+
+        /*! \brief
+         * Initializes the histogram using bin width and the number of bins.
+         */
+        int initNBins(real miny, real binw, int nbins,
+                      bool bIntegerBins = false);
+        /*! \brief
+         * Initializes the histogram using a range and a bin width.
+         */
+        int initRange(real miny, real maxy, real binw,
+                      bool bIntegerBins = false);
+        /*! \brief
+         * Sets the histogram to match all values.
+         *
+         * If \p bAll is true, the histogram behaves as if the bins at the ends
+         * extended to +-infinity.
+         */
+        void setAll(bool bAll);
+
+        /*! \brief
+         * Returns the average histogram over all frames.
+         *
+         * Can be called already before the histogram is calculated to
+         * customize the way the average histogram is calculated.
+         *
+         * \see HistogramAverageModule
+         */
+        HistogramAverageModule *averager();
+
+        //! Returns the number of bins in the histogram.
+        int nbins() const { return _nbins; }
+        //! Returns the width of a bin in the histogram.
+        real binwidth() const { return _binwidth; }
+        //! Returns a zero-based bin index for a value, or -1 if not in range.
+        int findBin(real y) const;
+
+        virtual int flags() const;
+
+        virtual int dataStarted(AbstractAnalysisData *data);
+        virtual int frameStarted(real x, real dx);
+        virtual int pointsAdded(real x, real dx, int firstcol, int n,
+                                const real *y, const real *dy,
+                                const bool *present) = 0;
+        virtual int frameFinished();
+        virtual int dataFinished();
+
+    protected:
+        AbstractHistogramModule();
+
+        //! Actual histogram data.
+        real                   *_hist;
+
+    private:
+        void createAverager();
+
+        HistogramAverageModule *_averager;
+        int                     _nbins;
+        real                    _miny;
+        real                    _maxy;
+        real                    _binwidth;
+        real                    _invbw;
+        bool                    _bAll;
+
+        // Copy and assign disallowed by base.
+};
+
+
+/*! \brief
+ * Data module for averaging histograms over frames.
+ *
+ * The averaging module for a per-frame histogram is always created by the
+ * AbstractHistogramModule class, and can be accessed using
+ * AbstractHistogramModule::averager().
+ * The user can alter some properties of the average histogram directly, but
+ * the main use of the object is to postprocess the histogram once the
+ * calculation is finished.
+ *
+ * \inpublicapi
+ * \ingroup module_analysisdata
+ */
+class HistogramAverageModule : public AbstractAnalysisArrayData,
+                               public AnalysisDataModuleInterface
+{
+    public:
+        virtual int flags() const;
+
+        virtual int dataStarted(AbstractAnalysisData *data);
+        virtual int frameStarted(real x, real dx);
+        virtual int pointsAdded(real x, real dx, int firstcol, int n,
+                                const real *y, const real *dy,
+                                const bool *present);
+        virtual int frameFinished();
+        virtual int dataFinished();
+
+        /*! \brief
+         * Sets the averager to ignore missing values.
+         */
+        void setIgnoreMissing(bool bIgnoreMissing);
+
+        /*! \brief
+         * Creates a copy of the histogram with double the bin width.
+         */
+        HistogramAverageModule *resampleDoubleBinWidth(bool bIntegerBins) const;
+        //! Creates a deep copy of the histogram.
+        HistogramAverageModule *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 the value of each bin by a different scaling factor.
+        void scaleVector(real norm[]);
+        /*! \brief
+         * Notifies attached modules of the histogram data.
+         *
+         * After this function has been called, it is no longer possible to
+         * alter the histogram.
+         */
+        int done() { return AbstractAnalysisArrayData::valuesReady(); }
+
+    private:
+        HistogramAverageModule();
+
+        int                     _nframes;
+        bool                    _bIgnoreMissing;
+
+        friend class AbstractHistogramModule;
+
+        // Copy and assign disallowed by base.
+};
+
+
+/*! \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.
+ *
+ * \inpublicapi
+ * \ingroup module_analysisdata
+ */
+class AnalysisDataSimpleHistogramModule : public AbstractHistogramModule
+{
+    public:
+        virtual int pointsAdded(real x, real dx, int firstcol, int n,
+                                const real *y, const real *dy,
+                                const bool *present);
+
+        // Copy and assign disallowed by base.
+};
+
+
+/*! \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.
+ *
+ * \inpublicapi
+ * \ingroup module_analysisdata
+ */
+class AnalysisDataWeightedHistogramModule : public AbstractHistogramModule
+{
+    public:
+        virtual int flags() const;
+
+        virtual int pointsAdded(real x, real dx, int firstcol, int n,
+                                const real *y, const real *dy,
+                                const bool *present);
+
+        // Copy and assign disallowed by base.
+};
+
+
+/*! \brief
+ * Data module for per-frame bin averages.
+ *
+ * Output data contains the same number of frames as the input data.
+ * Each frame contains the average for the points in that frame within each 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.
+ * The number of columns equals the number of bins.
+ *
+ * \inpublicapi
+ * \ingroup module_analysisdata
+ */
+class AnalysisDataBinAverageModule : public AbstractHistogramModule
+{
+    public:
+        AnalysisDataBinAverageModule();
+        virtual ~AnalysisDataBinAverageModule();
+
+        //! Ignore missing bins in the average histogram.
+        void setIgnoreMissing(bool bIgnoreMissing);
+
+        virtual int flags() const;
+
+        virtual int dataStarted(AbstractAnalysisData *data);
+        virtual int frameStarted(real x, real dx);
+        virtual int pointsAdded(real x, real dx, int firstcol, int n,
+                                const real *y, const real *dy,
+                                const bool *present);
+        virtual int frameFinished();
+
+    private:
+        int                    *_n;
+        bool                   *_present;
+        bool                    _bIgnoreMissing;
+
+        // Copy and assign disallowed by base.
+};
+
+} // namespace gmx
+
+#endif
diff --git a/src/gromacs/analysisdata/modules/plot-impl.h b/src/gromacs/analysisdata/modules/plot-impl.h
new file mode 100644 (file)
index 0000000..3b7c137
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * Declares private implementation class for gmx::AbstractPlotModule.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ */
+#ifndef GMX_ANALYSISDATA_MODULES_PLOT_IMPL_H
+#define GMX_ANALYSISDATA_MODULES_PLOT_IMPL_H
+
+#include <string>
+#include <vector>
+
+#include "plot.h"
+
+namespace gmx
+{
+
+class Options;
+
+class AbstractPlotModule::Impl
+{
+    public:
+        explicit Impl(const Options &options);
+        ~Impl();
+
+        void closeFile();
+
+        std::string             fnm;
+        FILE                   *fp;
+
+        bool                    bPlain;
+        output_env_t            oenv;
+        SelectionCollection    *sel;
+        std::string             title;
+        std::string             subtitle;
+        std::string             xlabel;
+        std::string             ylabel;
+        std::vector<std::string>  leg;
+        char                    xfmt[15];
+        char                    yfmt[15];
+};
+
+} // namespace gmx
+
+#endif
diff --git a/src/gromacs/analysisdata/modules/plot.cpp b/src/gromacs/analysisdata/modules/plot.cpp
new file mode 100644 (file)
index 0000000..c0b4a2b
--- /dev/null
@@ -0,0 +1,410 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * Implements classes in plot.h.
+ *
+ * \ingroup module_analysisdata
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ */
+#include "gromacs/analysisdata/modules/plot.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string>
+#include <vector>
+
+#include <cassert>
+#include <cstdio>
+#include <cstring>
+
+#include <gmxfio.h>
+#include <statutil.h>
+#include <vec.h>
+#include <xvgr.h>
+
+#include "gromacs/options/globalproperties.h"
+#include "gromacs/options/options.h"
+#include "gromacs/fatalerror/fatalerror.h"
+#include "gromacs/selection/selectioncollection.h"
+
+#include "plot-impl.h"
+
+namespace gmx
+{
+
+/********************************************************************
+ * AbstractPlotModule::Impl
+ */
+
+AbstractPlotModule::Impl::Impl(const Options &options)
+    : fp(NULL), bPlain(false),
+      oenv(options.globalProperties().output_env()),
+      sel(options.globalProperties().selectionCollection())
+{
+    strcpy(xfmt, "%11.3f");
+    strcpy(yfmt, " %8.3f");
+}
+
+AbstractPlotModule::Impl::~Impl()
+{
+    closeFile();
+}
+
+
+void
+AbstractPlotModule::Impl::closeFile()
+{
+    if (fp)
+    {
+        if (bPlain)
+        {
+            gmx_fio_fclose(fp);
+        }
+        else
+        {
+            xvgrclose(fp);
+        }
+        fp = NULL;
+    }
+}
+
+
+/********************************************************************
+ * AbstractPlotModule
+ */
+
+AbstractPlotModule::AbstractPlotModule(const Options &options)
+    : _impl(new Impl(options))
+{
+}
+
+
+AbstractPlotModule::~AbstractPlotModule()
+{
+    delete _impl;
+}
+
+
+void
+AbstractPlotModule::setFileName(const std::string &fnm)
+{
+    _impl->fnm = fnm;
+}
+
+
+void
+AbstractPlotModule::setPlainOutput(bool bPlain)
+{
+    _impl->bPlain = bPlain;
+}
+
+
+void
+AbstractPlotModule::setTitle(const char *title)
+{
+    _impl->title = title;
+}
+
+
+void
+AbstractPlotModule::setSubtitle(const char *subtitle)
+{
+    _impl->subtitle = subtitle;
+}
+
+
+void
+AbstractPlotModule::setXLabel(const char *label)
+{
+    _impl->xlabel = label;
+}
+
+
+void
+AbstractPlotModule::setXTimeLabel()
+{
+    _impl->xlabel = output_env_get_xvgr_tlabel(_impl->oenv);
+}
+
+
+void
+AbstractPlotModule::setYLabel(const char *label)
+{
+    _impl->ylabel = label;
+}
+
+
+void
+AbstractPlotModule::setLegend(int nsets, const char * const *setname)
+{
+    _impl->leg.reserve(_impl->leg.size() + nsets);
+    for (int i = 0; i < nsets; ++i)
+    {
+        appendLegend(setname[i]);
+    }
+}
+
+
+void
+AbstractPlotModule::appendLegend(const char *setname)
+{
+    _impl->leg.push_back(setname);
+}
+
+
+void
+AbstractPlotModule::setXFormat(int width, int prec, char fmt)
+{
+    assert(width >= 0 && prec >= 0 && width <= 99 && prec <= 99);
+    assert(strchr("eEfFgG", fmt) != NULL);
+    sprintf(_impl->xfmt, "%%%d.%d%c", width, prec, fmt);
+}
+
+
+void
+AbstractPlotModule::setYFormat(int width, int prec, char fmt)
+{
+    assert(width >= 0 && prec >= 0 && width <= 99 && prec <= 99);
+    assert(strchr("eEfFgG", fmt) != NULL);
+    sprintf(_impl->yfmt, " %%%d.%d%c", width, prec, fmt);
+}
+
+
+int
+AbstractPlotModule::flags() const
+{
+    return efAllowMulticolumn | efAllowMultipoint;
+}
+
+
+int
+AbstractPlotModule::dataStarted(AbstractAnalysisData *data)
+{
+    if (!_impl->fnm.empty())
+    {
+        if (_impl->bPlain)
+        {
+            _impl->fp = gmx_fio_fopen(_impl->fnm.c_str(), "w");
+        }
+        else
+        {
+            _impl->fp = xvgropen(_impl->fnm.c_str(), _impl->title.c_str(),
+                                 _impl->xlabel.c_str(), _impl->ylabel.c_str(),
+                                 _impl->oenv);
+            if (_impl->sel != NULL)
+            {
+                _impl->sel->printXvgrInfo(_impl->fp, _impl->oenv);
+            }
+            if (!_impl->subtitle.empty())
+            {
+                xvgr_subtitle(_impl->fp, _impl->subtitle.c_str(), _impl->oenv);
+            }
+            if (output_env_get_print_xvgr_codes(_impl->oenv)
+                && !_impl->leg.empty())
+            {
+                const char **leg;
+
+                leg = new const char *[_impl->leg.size()];
+                for (size_t i = 0; i < _impl->leg.size(); ++i)
+                {
+                    leg[i] = _impl->leg[i].c_str();
+                }
+                xvgr_legend(_impl->fp, _impl->leg.size(), leg, _impl->oenv);
+                delete [] leg;
+            }
+        }
+    }
+
+    return 0;
+}
+
+
+int
+AbstractPlotModule::frameStarted(real x, real dx)
+{
+    if (!isFileOpen())
+    {
+        return 0;
+    }
+    std::fprintf(_impl->fp, _impl->xfmt, x);
+    return 0;
+}
+
+
+int
+AbstractPlotModule::frameFinished()
+{
+    if (!isFileOpen())
+    {
+        return 0;
+    }
+    std::fprintf(_impl->fp, "\n");
+    return 0;
+}
+
+
+int
+AbstractPlotModule::dataFinished()
+{
+    _impl->closeFile();
+    return 0;
+}
+
+
+bool
+AbstractPlotModule::isFileOpen() const
+{
+    return _impl->fp != NULL;
+}
+
+
+void
+AbstractPlotModule::writeValue(real value) const
+{
+    assert(isFileOpen());
+    std::fprintf(_impl->fp, _impl->yfmt, value);
+}
+
+
+/********************************************************************
+ * DataPlotModule
+ */
+
+AnalysisDataPlotModule::AnalysisDataPlotModule(const Options &options)
+    : AbstractPlotModule(options)
+{
+}
+
+
+int
+AnalysisDataPlotModule::pointsAdded(real x, real dx, int firstcol, int n,
+                                    const real *y, const real *dy,
+                                    const bool *present)
+{
+    if (!isFileOpen())
+    {
+        return 0;
+    }
+    for (int i = 0; i < n; ++i)
+    {
+        writeValue(y[i]);
+    }
+    return 0;
+}
+
+
+/********************************************************************
+ * DataVectorPlotModule
+ */
+
+AnalysisDataVectorPlotModule::AnalysisDataVectorPlotModule(const Options &options)
+    : AbstractPlotModule(options)
+{
+    for (int i = 0; i < DIM; ++i)
+    {
+        _bWrite[i] = true;
+    }
+    _bWrite[DIM] = false;
+}
+
+
+void
+AnalysisDataVectorPlotModule::setWriteX(bool bWrite)
+{
+    _bWrite[XX] = bWrite;
+}
+
+
+void
+AnalysisDataVectorPlotModule::setWriteY(bool bWrite)
+{
+    _bWrite[YY] = bWrite;
+}
+
+
+void
+AnalysisDataVectorPlotModule::setWriteZ(bool bWrite)
+{
+    _bWrite[ZZ] = bWrite;
+}
+
+
+void
+AnalysisDataVectorPlotModule::setWriteNorm(bool bWrite)
+{
+    _bWrite[DIM] = bWrite;
+}
+
+
+void
+AnalysisDataVectorPlotModule::setWriteMask(bool bWrite[4])
+{
+    for (int i = 0; i < DIM + 1; ++i)
+    {
+        _bWrite[i] = bWrite[i];
+    }
+}
+
+
+int
+AnalysisDataVectorPlotModule::pointsAdded(real x, real dx, int firstcol, int n,
+                                          const real *y, const real *dy,
+                                          const bool *present)
+{
+    if (firstcol % DIM != 0)
+    {
+        GMX_ERROR(eeInvalidValue, "Partial data points");
+    }
+    if (!isFileOpen())
+    {
+        return 0;
+    }
+    for (int i = 0; i < n; i += 3)
+    {
+        for (int d = 0; d < DIM; ++d)
+        {
+            if (_bWrite[i])
+            {
+                writeValue(y[i + d]);
+            }
+        }
+        if (_bWrite[DIM])
+        {
+            writeValue(norm(&y[i]));
+        }
+    }
+    return 0;
+}
+
+} // namespace gmx
diff --git a/src/gromacs/analysisdata/modules/plot.h b/src/gromacs/analysisdata/modules/plot.h
new file mode 100644 (file)
index 0000000..5c39014
--- /dev/null
@@ -0,0 +1,213 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \file
+ * \brief
+ * Declares gmx::AnalysisDataPlotModule for plotting data (into a file).
+ *
+ * \inpublicapi
+ * \ingroup module_analysisdata
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ */
+#ifndef GMX_ANALYSISDATA_MODULES_PLOT_H
+#define GMX_ANALYSISDATA_MODULES_PLOT_H
+
+#include <string>
+
+#include "../datamodule.h"
+
+namespace gmx
+{
+
+class Options;
+
+/*! \brief
+ * Abstract data module for writing data into a file.
+ *
+ * Implements features common to all plotting modules.  Subclasses implement
+ * features specific to certain applications (AnalysisDataPlotModule implements
+ * 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.
+ * 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.
+ *
+ * \inpublicapi
+ * \ingroup module_analysisdata
+ */
+class AbstractPlotModule : public AnalysisDataModuleInterface
+{
+    public:
+        virtual ~AbstractPlotModule();
+
+        /*! \brief
+         * Set the output file name.
+         *
+         * If no file name is set (or if \p fnm is NULL), no output occurs.
+         */
+        void setFileName(const std::string &fnm);
+        /*! \brief
+         * Set plain output.
+         *
+         * If \p bPlain is true, no xvgr headers are written to the file.
+         * In this case, only setXFormat() and setYFormat() methods have any
+         * effect on the output.
+         */
+        void setPlainOutput(bool bPlain);
+        /*! \brief
+         * Set plot title.
+         */
+        void setTitle(const char *title);
+        /*! \brief
+         * Set plot subtitle.
+         */
+        void setSubtitle(const char *subtitle);
+        /*! \brief
+         * Set X axis label.
+         */
+        void setXLabel(const char *label);
+        /*! \brief
+         * Set X axis label for time.
+         */
+        void setXTimeLabel();
+        /*! \brief
+         * Set Y axis label.
+         */
+        void setYLabel(const char *label);
+        /*! \brief
+         * Add legend from an array of strings.
+         *
+         * Multiple calls to setLegend() and/or appendLegend() are added
+         * together.
+         */
+        void setLegend(int nsets, const char * const *setname);
+        /*! \brief
+         * Add a legend string for the next data set.
+         *
+         * Multiple calls to setLegend() and/or appendLegend() are added
+         * together.
+         */
+        void appendLegend(const char *setname);
+        /*! \brief
+         * Set field width and precision for X value output.
+         */
+        void setXFormat(int width, int prec, char fmt = 'f');
+        /*! \brief
+         * Set field width and precision for Y value output.
+         */
+        void setYFormat(int width, int prec, char fmt = 'f');
+
+        virtual int flags() const;
+
+        virtual int dataStarted(AbstractAnalysisData *data);
+        virtual int frameStarted(real x, real dx);
+        virtual int pointsAdded(real x, real dx, int firstcol, int n,
+                                const real *y, const real *dy,
+                                const bool *present) = 0;
+        virtual int frameFinished();
+        virtual int dataFinished();
+
+    protected:
+        explicit AbstractPlotModule(const Options &options);
+
+        bool isFileOpen() const;
+        void writeValue(real value) const;
+
+    private:
+        class Impl;
+
+        Impl                   *_impl;
+
+        // Disallow copy and assign.
+        AbstractPlotModule(const AbstractPlotModule &);
+        void operator =(const AbstractPlotModule &);
+};
+
+
+/*! \brief
+ * Plotting module for straightforward plotting of data.
+ *
+ * See AbstractPlotModule for common plotting options.
+ *
+ * \inpublicapi
+ * \ingroup module_analysisdata
+ */
+class AnalysisDataPlotModule : public AbstractPlotModule
+{
+    public:
+        explicit AnalysisDataPlotModule(const Options &options);
+
+        virtual int pointsAdded(real x, real dx, int firstcol, int n,
+                                const real *y, const real *dy,
+                                const bool *present);
+
+        // Copy and assign disallowed by base.
+};
+
+
+/*! \brief
+ * Plotting module specifically for data consisting of vectors.
+ *
+ * See AbstractPlotModule for common plotting options.
+ *
+ * \inpublicapi
+ * \ingroup module_analysisdata
+ */
+class AnalysisDataVectorPlotModule : public AbstractPlotModule
+{
+    public:
+        explicit AnalysisDataVectorPlotModule(const Options &options);
+
+        void setWriteX(bool bWrite);
+        void setWriteY(bool bWrite);
+        void setWriteZ(bool bWrite);
+        void setWriteNorm(bool bWrite);
+        void setWriteMask(bool bWrite[4]);
+
+        virtual int pointsAdded(real x, real dx, int firstcol, int n,
+                                const real *y, const real *dy,
+                                const bool *present);
+
+    private:
+        bool                    _bWrite[4];
+
+        // Copy and assign disallowed by base.
+};
+
+} // namespace gmx
+
+#endif
diff --git a/src/gromacs/basicmath.h b/src/gromacs/basicmath.h
new file mode 100644 (file)
index 0000000..673b7fd
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ *                        VERSION 3.2.0
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * 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.
+
+ * 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
+ */
+#ifndef GMX_BASICMATH_H
+#define GMX_BASICMATH_H
+
+#include <cmath>
+
+#include "types/simple.h"
+
+namespace gmx
+{
+
+template <typename T> static inline
+T sqr(const T &value)
+{
+    return value * value;
+}
+
+/*! \brief
+ * Check if two numbers are within a tolerance
+ *
+ * This routine checks if the relative difference between two numbers is
+ * approximately within the given tolerance, defined as
+ * fabs(f1-f2)<=tolerance*fabs(f1+f2).
+ *
+ * To check if two floating-point numbers are almost identical, use this routine
+ * with the tolerance GMX_REAL_EPS, or GMX_DOUBLE_EPS if the check should be
+ * done in double regardless of Gromacs precision.
+ *
+ * To check if two algorithms produce similar results you will normally need
+ * to relax the tolerance significantly since many operations (e.g. summation)
+ * accumulate floating point errors.
+ *
+ * \param f1  First number to compare
+ * \param f2  Second number to compare
+ * \param tol Tolerance to use
+ *
+ * \return 1 if the relative difference is within tolerance, 0 if not.
+ */
+static int
+gmx_within_tol(double   f1,
+               double   f2,
+               double   tol)
+{
+    /* The or-equal is important - otherwise we return false if f1==f2==0 */
+    if (std::fabs(f1-f2) <= tol * 0.5 * (std::fabs(f1) + std::fabs(f2)))
+    {
+        return 1;
+    }
+    else
+    {
+        return 0;
+    }
+}
+
+
+
+/*! \brief
+ * Check if a number is smaller than some preset safe minimum
+ * value, currently defined as GMX_REAL_MIN/GMX_REAL_EPS.
+ *
+ * If a number is smaller than this value we risk numerical overflow
+ * if any number larger than 1.0/GMX_REAL_EPS is divided by it.
+ *
+ * \return 1  if 'almost' numerically zero, 0 otherwise.
+ */
+static int
+gmx_numzero(double a)
+{
+  return gmx_within_tol(a,0.0,GMX_REAL_MIN/GMX_REAL_EPS);
+}
+
+}
+
+#endif
diff --git a/src/gromacs/errorreporting.h b/src/gromacs/errorreporting.h
new file mode 100644 (file)
index 0000000..e7c1cb4
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \defgroup module_errorreporting Reporting of Non-Fatal Errors
+ * \ingroup group_utilitymodules
+ * \brief
+ * Provides functions and classes for reporting non-fatal errors.
+ *
+ * Facilities for customizable reporting of non-fatal errors are provided by an
+ * abstract class AbstractErrorReporter.  Objects of this class can be passed
+ * to functions for reporting non-fatal errors.  The caller can then create a
+ * reporter object derived from AbstractErrorReporter to implement desired
+ * behavior for reporting the errors to the user.  Two basic reporter classes
+ * are provided by this module: EmptyErrorReporter that only counts the number
+ * of errors occurred, and StandardErrorReporter that writes the errors to
+ * standard error.
+ *
+ * An ErrorContext class is also provided to ease implementation of functions
+ * that need to report errors that originate deeper in the call stack.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ */
+/*! \file
+ * \brief
+ * Public API convenience header for non-fatal error reporting.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \inpublicapi
+ * \ingroup module_errorreporting
+ */
+#ifndef GMX_ERRORREPORTING_H
+#define GMX_ERRORREPORTING_H
+
+#include "errorreporting/abstracterrorreporter.h"
+#include "errorreporting/emptyerrorreporter.h"
+#include "errorreporting/errorcontext.h"
+#include "errorreporting/standarderrorreporter.h"
+
+#endif
diff --git a/src/gromacs/errorreporting/CMakeLists.txt b/src/gromacs/errorreporting/CMakeLists.txt
new file mode 100644 (file)
index 0000000..8566977
--- /dev/null
@@ -0,0 +1,11 @@
+file(GLOB ERRORREPORTING_SOURCES *.cpp)
+set(LIBGROMACS_SOURCES ${LIBGROMACS_SOURCES} ${ERRORREPORTING_SOURCES} PARENT_SCOPE)
+
+set(ERRORREPORTING_PUBLIC_HEADERS
+    abstracterrorreporter.h
+    emptyerrorreporter.h
+    errorcontext.h
+    standarderrorreporter.h)
+install(FILES ${ERRORREPORTING_PUBLIC_HEADERS}
+        DESTINATION ${INCL_INSTALL_DIR}/gromacs/errorreporting
+        COMPONENT development)
diff --git a/src/gromacs/errorreporting/abstracterrorreporter.h b/src/gromacs/errorreporting/abstracterrorreporter.h
new file mode 100644 (file)
index 0000000..50b154d
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \file
+ * \brief
+ * Defines ::gmx::AbstractErrorReporter.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \inpublicapi
+ * \ingroup module_errorreporting
+ */
+#ifndef GMX_ERRORREPORTING_ABSTRACTERRORREPORTER_H
+#define GMX_ERRORREPORTING_ABSTRACTERRORREPORTER_H
+
+#include <string>
+
+namespace gmx
+{
+
+/*! \brief
+ * Abstract base class for error reporters.
+ *
+ * This class provides an interface for reporting non-fatal errors from a
+ * complex function.  Such a function should take a pointer to an
+ * AbstractErrorReporter object, and use the provided methods to report any errors
+ * it encounters.  If the function calls other functions that can also detect
+ * errors, it can pass the reporter object to these functions as well, possibly
+ * after adding context information using startContext()/finishContext() or the
+ * ErrorContext class.  The caller of such a function can then create an error
+ * reporter of their choice and pass it to the function to alter how errors are
+ * reported to the user.
+ *
+ * This abstract implementation provides basic facilities to implement counting
+ * of errors of different type.  Derived classes should call the
+ * incrementCount() method from their implementation of the add() method for
+ * this to work properly.
+ *
+ * \see ErrorContext
+ * \inpublicapi
+ * \ingroup module_errorreporting
+ */
+class AbstractErrorReporter
+{
+    public:
+        /*! \brief
+         * Type of error.
+         */
+        enum ErrorType
+        {
+            etNote,
+            etWarning,
+            etError,
+            etNR
+        };
+
+        virtual ~AbstractErrorReporter() {}
+
+        /*! \brief
+         * Starts a context for errors.
+         *
+         * \param[in] name  Short description of the context.
+         *
+         * Derived classes should duplicate the string if they need to store
+         * it.
+         *
+         * \see ErrorContext
+         */
+        virtual void startContext(const char *name) = 0;
+        /*! \brief
+         * Reports a new error.
+         *
+         * \param[in] type    Type of the error.
+         * \param[in] reason  Short description of the error.
+         *
+         * Derived classes should duplicate the string if they need to store
+         * it.
+         */
+        virtual void add(ErrorType type, const char *reason) = 0;
+        /*! \brief
+         * Ends a context started with startContext().
+         *
+         * \see ErrorContext
+         */
+        virtual void finishContext() = 0;
+
+        /*! \brief
+         * Convenience wrapper for startContext(const char *).
+         */
+        void startContext(const std::string &name) { startContext(name.c_str()); }
+        /*! \brief
+         * Convenience wrapper for add(ErrorType, const char *).
+         */
+        void add(ErrorType type, const std::string &reason) { add(type, reason.c_str()); }
+        /*! \brief
+         * Convenience wrapper for add() for adding notes.
+         */
+        void note(const char *reason) { add(etNote, reason); }
+        //! \copydoc note(const char *)
+        void note(const std::string &reason) { add(etNote, reason); }
+        /*! \brief
+         * Convenience wrapper for add() for adding warnings.
+         */
+        void warning(const char *reason) { add(etWarning, reason); }
+        //! \copydoc warning(const char *)
+        void warning(const std::string &reason) { add(etWarning, reason); }
+        /*! \brief
+         * Convenience wrapper for add() for adding errors.
+         */
+        void error(const char *reason) { add(etError, reason); }
+        //! \copydoc error(const char *)
+        void error(const std::string &reason) { add(etError, reason); }
+
+        /*! \brief
+         * Returns the number of errors of particular type that have occurred.
+         */
+        int errorCount(ErrorType type) const { return _count[type]; }
+
+    protected:
+        /*! \brief
+         * Initializes a reporter with zero error counts.
+         */
+        AbstractErrorReporter()
+        {
+            for (int i = 0; i < etNR; ++i)
+            {
+                _count[i] = 0;
+            }
+        }
+
+        /*! \brief
+         * Increment the count of a particular error type.
+         *
+         * Derived classes should call this function from their implementation
+         * of the add() method.
+         */
+        void incrementCount(ErrorType type) { _count[type]++; }
+
+    private:
+        //! Number of errors occurred for each type.
+        int                      _count[etNR];
+};
+
+} // namespace gmx
+
+#endif
diff --git a/src/gromacs/errorreporting/emptyerrorreporter.h b/src/gromacs/errorreporting/emptyerrorreporter.h
new file mode 100644 (file)
index 0000000..43ea398
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \file
+ * \brief
+ * Declares ::gmx::EmptyErrorReporter.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \inpublicapi
+ * \ingroup module_errorreporting
+ */
+#ifndef GMX_ERRORREPORTING_EMPTYERRORREPORTER_H
+#define GMX_ERRORREPORTING_EMPTYERRORREPORTER_H
+
+#include "abstracterrorreporter.h"
+
+namespace gmx
+{
+
+/*! \brief
+ * Error reporter that only counts the number of different types of errors.
+ *
+ * All descriptions of the errors are discarded.
+ * Mostly useful for testing purposes.
+ *
+ * \inpublicapi
+ * \ingroup module_errorreporting
+ */
+class EmptyErrorReporter : public AbstractErrorReporter
+{
+    public:
+        EmptyErrorReporter() {}
+        virtual ~EmptyErrorReporter() {}
+
+        virtual void startContext(const char *name);
+        virtual void add(ErrorType type, const char *reason);
+        virtual void finishContext();
+};
+
+} // namespace gmx
+
+#endif
diff --git a/src/gromacs/errorreporting/errorcontext.h b/src/gromacs/errorreporting/errorcontext.h
new file mode 100644 (file)
index 0000000..a7634df
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \file
+ * \brief
+ * Defines ::gmx::ErrorContext.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \inpublicapi
+ * \ingroup module_errorreporting
+ */
+#ifndef GMX_ERRORREPORTING_ERRORCONTEXT_H
+#define GMX_ERRORREPORTING_ERRORCONTEXT_H
+
+#include <string>
+
+#include "abstracterrorreporter.h"
+
+namespace gmx
+{
+
+/*! \brief
+ * Convenience class for creating an error context.
+ *
+ * This class provides a RAII-style interface to the
+ * AbstractErrorReporter::startContext() and
+ * AbstractErrorReporter::finishContext() methods: finishContext() is called
+ * upon destruction of the object.  This avoids the need to call
+ * AbstractErrorReporter::finishContext() on every possible exit point.
+ *
+ * Example usage:
+ * \code
+int function(::gmx::AbstractErrorReporter *errors)
+{
+    ::gmx::ErrorContext errcontext(errors, "In function()");
+    int rc;
+    rc = function2(errors);
+    if (rc != 0)
+    {
+        return rc;
+    }
+    rc = function3(errors);
+    if (rc != 0)
+    {
+        return rc;
+    }
+    // <more processing>
+    return 0;
+}
+ * \endcode
+ *
+ * \see AbstractErrorReporter
+ * \inpublicapi
+ * \ingroup module_errorreporting
+ */
+class ErrorContext
+{
+    public:
+        /*! \brief
+         * Adds a context for the given reporter.
+         */
+        ErrorContext(AbstractErrorReporter *reporter, const char *name)
+            : _reporter(*reporter)
+        {
+            _reporter.startContext(name);
+        }
+        /*! \brief
+         * Adds a context for the given reporter.
+         */
+        ErrorContext(AbstractErrorReporter *reporter, const std::string &name)
+            : _reporter(*reporter)
+        {
+            _reporter.startContext(name);
+        }
+        /*! \brief
+         * Calls AbstractReporter::finishContext() on the wrapped reporter.
+         */
+        ~ErrorContext()
+        {
+            _reporter.finishContext();
+        }
+
+    private:
+        //! The wrapped reporter object.
+        AbstractErrorReporter  &_reporter;
+
+        // Disallow copy and assign.
+        ErrorContext(const ErrorContext &);
+        void operator =(const ErrorContext &);
+};
+
+} // namespace gmx
+
+#endif
diff --git a/src/gromacs/errorreporting/reporters.cpp b/src/gromacs/errorreporting/reporters.cpp
new file mode 100644 (file)
index 0000000..684e978
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * Implements error reporter classes.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_errorreporting
+ */
+#include <cstdio>
+
+#include "gromacs/errorreporting/abstracterrorreporter.h"
+#include "gromacs/errorreporting/emptyerrorreporter.h"
+#include "gromacs/errorreporting/standarderrorreporter.h"
+
+#include "standarderrorreporter-impl.h"
+
+static const char *const error_type_names[] = { "note", "warning", "error" };
+
+namespace gmx
+{
+
+/********************************************************************
+ * EmptyErrorReporter
+ */
+
+void EmptyErrorReporter::startContext(const char * /*name*/)
+{
+}
+
+void EmptyErrorReporter::add(ErrorType type, const char * /*reason*/)
+{
+    incrementCount(type);
+}
+
+void EmptyErrorReporter::finishContext()
+{
+}
+
+/********************************************************************
+ * StandardErrorReporter::Impl
+ */
+
+StandardErrorReporter::Impl::Impl()
+    : _prevContext(-1)
+{
+}
+
+/********************************************************************
+ * StandardErrorReporter
+ */
+
+StandardErrorReporter::StandardErrorReporter()
+    : _impl(new Impl)
+{
+}
+
+StandardErrorReporter::~StandardErrorReporter()
+{
+    delete _impl;
+}
+
+void StandardErrorReporter::startContext(const char *name)
+{
+    _impl->_contexts.push_back(name);
+}
+
+void StandardErrorReporter::add(ErrorType type, const char *reason)
+{
+    incrementCount(type);
+    int indent = (_impl->_prevContext + 1) * 2;
+    if (!_impl->_contexts.empty())
+    {
+        std::vector<std::string>::const_iterator ci;
+        for (ci = _impl->_contexts.begin() + _impl->_prevContext + 1;
+             ci != _impl->_contexts.end(); ++ci)
+        {
+            std::fprintf(stderr, "%*s%s\n", indent, "", ci->c_str());
+            indent += 2;
+        }
+    }
+    _impl->_prevContext = _impl->_contexts.size() - 1;
+    std::fprintf(stderr, "%*s%s: %s\n", indent, "",
+                 error_type_names[type], reason);
+}
+
+void StandardErrorReporter::finishContext()
+{
+    _impl->_contexts.pop_back();
+    if (_impl->_prevContext >= static_cast<int>(_impl->_contexts.size()))
+    {
+        _impl->_prevContext = _impl->_contexts.size() - 1;
+    }
+}
+
+} // namespace gmx
diff --git a/src/gromacs/errorreporting/standarderrorreporter-impl.h b/src/gromacs/errorreporting/standarderrorreporter-impl.h
new file mode 100644 (file)
index 0000000..84137a9
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * Declares private implementation class for ::gmx::StandardErrorReporter.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_errorreporting
+ */
+#ifndef GMX_ERRORREPORTING_STANDARDERRORREPORTER_IMPL_HPP
+#define GMX_ERRORREPORTING_STANDARDERRORREPORTER_IMPL_HPP
+
+#include <string>
+#include <vector>
+
+#include "standarderrorreporter.h"
+
+namespace gmx
+{
+
+/*! \internal \brief
+ * Private implementation class for StandardErrorReporter.
+ */
+class StandardErrorReporter::Impl
+{
+    public:
+        //! Initializes a reporter without any context.
+        Impl();
+
+        //! Stack of context strings.
+        std::vector<std::string>  _contexts;
+        //! Location of the last error in the context stack.
+        int                       _prevContext;
+};
+
+} // namespace gmx
+
+#endif
diff --git a/src/gromacs/errorreporting/standarderrorreporter.h b/src/gromacs/errorreporting/standarderrorreporter.h
new file mode 100644 (file)
index 0000000..4cb2e52
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \file
+ * \brief
+ * Declares ::gmx::StandardErrorReporter.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \inpublicapi
+ * \ingroup module_errorreporting
+ */
+#ifndef GMX_ERRORREPORTING_STANDARDERRORREPORTER_H
+#define GMX_ERRORREPORTING_STANDARDERRORREPORTER_H
+
+#include "abstracterrorreporter.h"
+
+namespace gmx
+{
+
+/*! \brief
+ * Error reporter that writes error descriptions to standard error.
+ *
+ * \inpublicapi
+ * \ingroup module_errorreporting
+ */
+class StandardErrorReporter : public AbstractErrorReporter
+{
+    public:
+        StandardErrorReporter();
+        virtual ~StandardErrorReporter();
+
+        virtual void startContext(const char *name);
+        virtual void add(ErrorType type, const char *reason);
+        virtual void finishContext();
+
+    private:
+        class Impl;
+
+        Impl                   *_impl;
+};
+
+} // namespace gmx
+
+#endif
diff --git a/src/gromacs/fatalerror.h b/src/gromacs/fatalerror.h
new file mode 100644 (file)
index 0000000..e5be5bd
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \defgroup module_fatalerror Handling of Fatal Errors
+ * \ingroup group_utilitymodules
+ * \brief
+ * Provides functions for handling fatal errors.
+ *
+ * Facilities for handling fatal errors are provided by the fatalerror.h header
+ * file.  It provides a set of error codes (the enum ::ErrorCode) that should
+ * be used for return codes in functions.  It also provides function fatalError()
+ * for reporting the cause of the error to the user, and convenience macros
+ * ::GMX_ERROR and ::GMX_ERROR_NORET for calling fatalError().  If the reason
+ * string needs formatting, fatalErrorFormatted() is also provided.
+ *
+ * For users of the library, setFatalErrorHandler() is provided to alter the
+ * behavior of fatalError() and fatalErrorFormatted().  fatalError() simply
+ * calls the provided handler, while fatalErrorFormatted() does the formatting
+ * internally and then calls the same handler.  The default handler prints the
+ * reason of the error to standard error and aborts the execution.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ */
+/*! \file
+ * \brief
+ * Public API convenience header for fatal error handling.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \inpublicapi
+ * \ingroup module_fatalerror
+ */
+#ifndef GMX_FATALERROR_H
+#define GMX_FATALERROR_H
+
+#include "fatalerror/fatalerror.h"
+
+#endif
diff --git a/src/gromacs/fatalerror/CMakeLists.txt b/src/gromacs/fatalerror/CMakeLists.txt
new file mode 100644 (file)
index 0000000..46c1756
--- /dev/null
@@ -0,0 +1,8 @@
+file(GLOB FATALERROR_SOURCES *.cpp)
+set(LIBGROMACS_SOURCES ${LIBGROMACS_SOURCES} ${FATALERROR_SOURCES} PARENT_SCOPE)
+
+set(FATALERROR_PUBLIC_HEADERS
+    fatalerror.h)
+install(FILES ${FATALERROR_PUBLIC_HEADERS}
+        DESTINATION ${INCL_INSTALL_DIR}/gromacs/fatalerror
+        COMPONENT development)
diff --git a/src/gromacs/fatalerror/fatalerror.cpp b/src/gromacs/fatalerror/fatalerror.cpp
new file mode 100644 (file)
index 0000000..8e2de56
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * Implements functions in fatalerror.h.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_fatalerror
+ */
+#include "gromacs/fatalerror/fatalerror.h"
+
+#include <cstdarg>
+#include <cstdio>
+#include <cstdlib>
+
+static const char *const error_names[] =
+{
+    "No error",
+    "Out of memory",
+    "File not found",
+    "System I/O error",
+    "Error in user input",
+    "Inconsistency in user input",
+    "Simulation instability detected",
+
+    "Feature not implemented",
+    "Invalid value (bug)",
+    "Invalid call (bug)",
+    "Internal error (bug)",
+    "Range checking error (possible bug)",
+    "Communication error (possible bug)",
+
+    "Unknown error",
+};
+
+namespace gmx
+{
+
+static void standardErrorHandler(int retcode, const char *msg,
+                                 const char *file, int line)
+{
+    using std::fprintf;
+
+    fprintf(stderr, "\n-------------------------------------------------------\n");
+    fprintf(stderr, "Program %s, %s\n", "TEST", "VERSION 0.1");
+    fprintf(stderr, "In source file %s, line %d\n\n", file, line);
+    if (retcode < 0 || retcode >= eeUnknownError)
+    {
+        retcode = eeUnknownError;
+    }
+    fprintf(stderr, "%s:\n", error_names[retcode]);
+    fprintf(stderr, "%s\n", msg);
+    fprintf(stderr, "For more information and tips for troubleshooting, please check the GROMACS\n"
+                    "website at http://www.gromacs.org/Documentation/Errors");
+    fprintf(stderr, "\n-------------------------------------------------------\n");
+    std::exit(1);
+}
+
+static ErrorHandlerFunc error_handler = standardErrorHandler;
+
+ErrorHandlerFunc setFatalErrorHandler(ErrorHandlerFunc handler)
+{
+    // TODO: Acquire a mutex here
+    ErrorHandlerFunc old_handler = error_handler;
+    error_handler = handler;
+    // TODO: Release the mutex here
+    return old_handler;
+}
+
+void fatalError(int retcode, const char *msg, const char *file, int line)
+{
+    // TODO: Acquire a mutex here
+    ErrorHandlerFunc handler = error_handler;
+    // TODO: Release the mutex here
+    if (handler != NULL)
+    {
+        handler(retcode, msg, file, line);
+    }
+}
+
+void fatalErrorFormatted(int retcode, const char *file, int line,
+                         const char *fmt, ...)
+{
+    // TODO: Acquire a mutex here
+    ErrorHandlerFunc handler = error_handler;
+    // TODO: Release the mutex here
+    if (handler != NULL)
+    {
+        char    errorbuf[10000];
+        va_list va;
+
+        va_start(va, fmt);
+        // FIXME: vsnprintf should really be used here
+        std::vsprintf(errorbuf, fmt, va);
+        va_end(va);
+        handler(retcode, errorbuf, file, line);
+    }
+}
+
+} // namespace gmx
diff --git a/src/gromacs/fatalerror/fatalerror.h b/src/gromacs/fatalerror/fatalerror.h
new file mode 100644 (file)
index 0000000..40b71a8
--- /dev/null
@@ -0,0 +1,197 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \file
+ * \brief
+ * Declares common return codes and functions for fatal error handling.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \inpublicapi
+ * \ingroup module_fatalerror
+ */
+#ifndef GMX_FATALERROR_FATALERROR_H
+#define GMX_FATALERROR_FATALERROR_H
+
+namespace gmx
+{
+
+/*! \addtopublicapi
+ * \{
+ */
+
+/*! \brief
+ * Possible error return codes from Gromacs functions.
+ */
+enum ErrorCode
+{
+    //! Zero for successful return.
+    eeOK,
+    //! Not enough memory to complete operation.
+    eeOutOfMemory,
+    //! Provided file could not be opened.
+    eeFileNotFound,
+    //! System I/O error.
+    eeFileIO,
+    //! Invalid user input (could not be understood).
+    eeInvalidInput,
+    //! Invalid user input (conflicting or unsupported settings).
+    eeInconsistentInput,
+    //! Simulation instability detected.
+    eeInstability,
+
+    // Error codes below are for internal error checking; if triggered, they
+    // should indicate a bug in the code.
+    //! Requested feature not yet implemented.
+    eeNotImplemented,
+    //! Input value violates API specification.
+    eeInvalidValue,
+    //! Invalid routine called or wrong calling sequence detected.
+    eeInvalidCall,
+    //! Internal consistency check failed.
+    eeInternalError,
+    //! Range consistency check failed.
+    eeRange,
+    //! Communication consistency check failed.
+    eeCommunication,
+
+    eeUnknownError,
+};
+
+/*! \brief
+ * Callback function pointer type for error handlers.
+ *
+ * \param[in] retcode Code of the error that has occurred.
+ * \param[in] msg     More detailed description of the error.
+ * \param[in] file    Name of the file where the error occurred.
+ * \param[in] line    Line in \p file on which the error occurred.
+ */
+typedef void (*ErrorHandlerFunc)(int retcode, const char *msg,
+                                 const char *file, int line);
+
+/*! \brief
+ * Sets callback function for handling errors.
+ *
+ * \param[in] handler New error handler function.
+ * \returns   Old error handler function.
+ *
+ * The default error handler prints out the location and reason of the error to
+ * stderr, and then calls abort().
+ */
+ErrorHandlerFunc setFatalErrorHandler(ErrorHandlerFunc handler);
+
+/*! \brief
+ * Raises a fatal error.
+ *
+ * \param[in] retcode Error code to raise.
+ * \param[in] msg     More detailed description of the error.
+ * \param[in] file    Name of the source file where the error occurred.
+ * \param[in] line    Line in \p file on which the error occurred.
+ */
+void fatalError(int retcode, const char *msg, const char *file, int line);
+/*! \brief
+ * Raises an error with a formatted message.
+ *
+ * Use like this:
+ * \code
+::gmx::fatalErrorFormatted(::gmx::eeInvalidInput, GMX_ERRORLOC,
+    "Invalid command-line argument: %s", argname);
+ * \endcode
+ *
+ * \param[in] retcode Error code to raise.
+ * \param[in] file    Name of the source file where the error occurred.
+ * \param[in] line    Line in \p file on which the error occurred.
+ * \param[in] fmt     printf format string.
+ */
+void fatalErrorFormatted(int retcode, const char *file, int line,
+                         const char *fmt, ...);
+
+/*! \brief
+ * Helper macro for fatalErrorFormatted().
+ *
+ * \see fatalErrorFormatted()
+ */
+#define GMX_ERRORLOC   __FILE__, __LINE__
+
+/*! \brief
+ * Macro for raising an error and returning from a function.
+ *
+ * The function should return \c int ; if it doesn't, use GMX_ERROR_NORET.
+ */
+#define GMX_ERROR(retcode, msg) \
+    do { \
+        int _rc_internal = (retcode); \
+        ::gmx::fatalError(_rc_internal, msg, __FILE__, __LINE__); \
+        return _rc_internal; \
+    } while (0)
+
+/*! \brief
+ * Macro for raising an error in a function that does not return \c int.
+ *
+ * \see GMX_ERROR
+ */
+#define GMX_ERROR_NORET(retcode, msg) \
+        ::gmx::fatalError(retcode, msg, __FILE__, __LINE__)
+
+/*! \def GMX_ERROR_DEBUG
+ * \brief
+ * Macro for raising a debugging error and returning from a function.
+ *
+ * If NDEBUG is defined, this macro only returns the given error code.
+ * If it is not defined, behaves exactly like GMX_ERROR.
+ *
+ * The function should return \c int ; if it doesn't, use GMX_ERROR_DEBUG_NORET.
+ */
+/*! \def GMX_ERROR_DEBUG_NORET
+ * \brief
+ * Macro for raising a debugging error in a function that does not return \c int.
+ *
+ * If NDEBUG is defined, this macro does nothing.  If it is not defined,
+ * behaves exactly like GMX_ERROR_NORET.
+ */
+#ifdef NDEBUG
+#define GMX_ERROR_DEBUG(retcode, msg) \
+        return (retcode)
+#define GMX_ERROR_DEBUG_NORET(retcode, msg)
+#else
+#define GMX_ERROR_DEBUG(retcode, msg) \
+    do { \
+        int _rc_internal = (retcode); \
+        ::gmx::fatalError(_rc_internal, msg, __FILE__, __LINE__); \
+        return _rc_internal; \
+    } while (0)
+#define GMX_ERROR_DEBUG_NORET(retcode, msg) \
+        ::gmx::fatalError(retcode, msg, __FILE__, __LINE__)
+#endif
+
+/*!\}*/
+
+} // namespace gmx
+
+#endif
diff --git a/src/gromacs/gmxlib/CMakeLists.txt b/src/gromacs/gmxlib/CMakeLists.txt
new file mode 100644 (file)
index 0000000..17cea60
--- /dev/null
@@ -0,0 +1,79 @@
+include_directories(${CMAKE_CURRENT_SOURCE_DIR})
+
+# The nonbonded directory contains subdirectories that are only
+# conditionally built, so we cannot use a GLOB_RECURSE here.
+file(GLOB GMXLIB_SOURCES *.c 
+     statistics/*.c nonbonded/*.c nonbonded/nb_kernel_c/*.c)
+
+if(GMX_DOUBLE)
+  set(SSETYPE sse2)
+else()
+  set(SSETYPE sse)
+endif()
+
+if(GMX_IA32_ASM)
+  file(GLOB GMX_SSEKERNEL_C_SRC   nonbonded/nb_kernel_ia32_${SSETYPE}/*.c)
+  if(GMX_ASM_USEASM-NASM)
+    file(GLOB GMX_SSEKERNEL_ASM_SRC nonbonded/nb_kernel_ia32_${SSETYPE}/*intel_syntax*.s)    
+  else()
+    file(GLOB GMX_SSEKERNEL_ASM_SRC nonbonded/nb_kernel_ia32_${SSETYPE}/*${SSETYPE}.s nonbonded/nb_kernel_ia32_${SSETYPE}/*asm.s)
+  endif()
+endif(GMX_IA32_ASM)
+
+if(GMX_X86_64_ASM)
+  file(GLOB GMX_SSEKERNEL_C_SRC   nonbonded/nb_kernel_x86_64_${SSETYPE}/*.c)
+  if(GMX_ASM_USEASM-NASM)
+    file(GLOB GMX_SSEKERNEL_ASM_SRC nonbonded/nb_kernel_x86_64_${SSETYPE}/*intel_syntax*.s)
+  else()
+    file(GLOB GMX_SSEKERNEL_ASM_SRC nonbonded/nb_kernel_x86_64_${SSETYPE}/*${SSETYPE}.s nonbonded/nb_kernel_x86_64_${SSETYPE}/*asm.s)
+  endif()
+endif(GMX_X86_64_ASM)
+
+if(GMX_FORTRAN)
+  if (GMX_DOUBLE)
+    file(GLOB FORTRAN_SOURCES nonbonded/nb_kernel_f77_double/*.[cf])
+  else(GMX_DOUBLE)
+    file(GLOB FORTRAN_SOURCES nonbonded/nb_kernel_f77_single/*.[cf])
+  endif(GMX_DOUBLE)
+endif(GMX_FORTRAN)
+
+if(GMX_POWER6)
+  file(GLOB FORTRAN_SOURCES nonbonded/nb_kernel_power6/*.[cF])
+endif(GMX_POWER6)
+
+if(GMX_BLUEGENE)
+  file(GLOB GMX_BLUEGENE_C_SRC nonbonded/nb_kernel_bluegene/*.c)
+endif(GMX_BLUEGENE)
+
+if(GMX_PPC_ALTIVEC)
+  file(GLOB GMX_PPC_ALTIVEC_SRC nonbonded/nb_kernel_ppc_altivec/*.c)
+endif(GMX_PPC_ALTIVEC)
+
+if(NOT GMX_EXTERNAL_BLAS)
+  file(GLOB BLAS_SOURCES gmx_blas/*.c)
+endif(NOT GMX_EXTERNAL_BLAS)
+
+if(NOT GMX_EXTERNAL_LAPACK)
+  file(GLOB LAPACK_SOURCES gmx_lapack/*.c)
+endif(NOT GMX_EXTERNAL_LAPACK)
+
+# This would be the standard way to include thread_mpi, but we want libgmx
+# to link the functions directly
+#if(GMX_THREADS)
+#    add_subdirectory(thread_mpi)
+#endif(GMX_THREADS)
+#target_link_libraries(gmx ${GMX_EXTRA_LIBRARIES} ${THREAD_MPI_LIB})
+
+# Files called xxx_test.c are test drivers with a main() function for module xxx.c,
+# so they should not be included in the library
+file(GLOB_RECURSE NOT_GMXLIB_SOURCES *_test.c *\#*)
+list(REMOVE_ITEM GMXLIB_SOURCES ${NOT_GMXLIB_SOURCES})  
+
+# An ugly hack to get absolute paths...
+file(GLOB THREAD_MPI_SOURCES ${THREAD_MPI_SRC})
+
+set(GMX_SSEKERNEL_ASM_SRC ${GMX_SSEKERNEL_ASM_SRC} PARENT_SCOPE)
+set(GMXLIB_SOURCES ${GMXLIB_SOURCES} ${BLAS_SOURCES} ${LAPACK_SOURCES}
+    ${GMX_SSEKERNEL_C_SRC} ${FORTRAN_SOURCES}
+    ${GMX_BLUEGENE_C_SRC} ${GMX_PPC_ALTIVEC_SRC} ${THREAD_MPI_SOURCES}
+    PARENT_SCOPE)
similarity index 100%
rename from src/gmxlib/dlb.h
rename to src/gromacs/gmxlib/dlb.h
similarity index 100%
rename from src/gmxlib/main.c
rename to src/gromacs/gmxlib/main.c
similarity index 100%
rename from src/gmxlib/md5.c
rename to src/gromacs/gmxlib/md5.c
diff --git a/src/gromacs/gmxlib/mvdata.c b/src/gromacs/gmxlib/mvdata.c
new file mode 100644 (file)
index 0000000..5b2df26
--- /dev/null
@@ -0,0 +1,593 @@
+/* -*- 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
+ * 
+ *                        VERSION 3.2.0
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * 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.
+
+ * 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:
+ * GROningen Mixture of Alchemy and Childrens' Stories
+ */
+/* This file is completely threadsafe - keep it that way! */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <sysstuff.h>
+#include <string.h>
+#include "typedefs.h"
+#include "main.h"
+#include "mvdata.h"
+#include "network.h"
+#include "smalloc.h"
+#include "gmx_fatal.h"
+#include "symtab.h"
+#include "vec.h"
+#include "tgroup.h"
+
+#define   block_bc(cr,   d) gmx_bcast(     sizeof(d),     &(d),(cr))
+/* Probably the test for (nr) > 0 in the next macro is only needed
+ * on BlueGene(/L), where IBM's MPI_Bcast will segfault after
+ * dereferencing a null pointer, even when no data is to be transferred. */
+#define  nblock_bc(cr,nr,d) { if ((nr) > 0) gmx_bcast((nr)*sizeof((d)[0]), (d),(cr)); }
+#define    snew_bc(cr,d,nr) { if (!MASTER(cr)) snew((d),(nr)); }
+/* Dirty macro with bAlloc not as an argument */
+#define nblock_abc(cr,nr,d) { if (bAlloc) snew((d),(nr)); nblock_bc(cr,(nr),(d)); }
+
+static void bc_string(const t_commrec *cr,t_symtab *symtab,char ***s)
+{
+  int handle;
+  
+  if (MASTER(cr)) {
+    handle = lookup_symtab(symtab,*s);
+  }
+  block_bc(cr,handle);
+  if (!MASTER(cr)) {
+    *s = get_symtab_handle(symtab,handle);
+  }
+}
+
+static void bc_strings(const t_commrec *cr,t_symtab *symtab,int nr,char ****nm)
+{
+  int  i;
+  int  *handle;
+  char ***NM;
+
+  snew(handle,nr);
+  if (MASTER(cr)) {
+    NM = *nm;
+    for(i=0; (i<nr); i++)
+      handle[i] = lookup_symtab(symtab,NM[i]);
+  }
+  nblock_bc(cr,nr,handle);
+
+  if (!MASTER(cr)) {
+    snew_bc(cr,*nm,nr);
+    NM = *nm;
+    for (i=0; (i<nr); i++) 
+      (*nm)[i] = get_symtab_handle(symtab,handle[i]);
+  }
+  sfree(handle);
+}
+
+static void bc_strings_resinfo(const t_commrec *cr,t_symtab *symtab,
+                              int nr,t_resinfo *resinfo)
+{
+  int  i;
+  int  *handle;
+
+  snew(handle,nr);
+  if (MASTER(cr)) {
+    for(i=0; (i<nr); i++)
+      handle[i] = lookup_symtab(symtab,resinfo[i].name);
+  }
+  nblock_bc(cr,nr,handle);
+
+  if (!MASTER(cr)) {
+    for (i=0; (i<nr); i++) 
+      resinfo[i].name = get_symtab_handle(symtab,handle[i]);
+  }
+  sfree(handle);
+}
+
+static void bc_symtab(const t_commrec *cr,t_symtab *symtab)
+{
+  int i,nr,len;
+  t_symbuf *symbuf;
+
+  block_bc(cr,symtab->nr);
+  nr = symtab->nr;
+  snew_bc(cr,symtab->symbuf,1);
+  symbuf = symtab->symbuf;
+  symbuf->bufsize = nr;
+  snew_bc(cr,symbuf->buf,nr);
+  for (i=0; i<nr; i++) {
+    if (MASTER(cr))
+      len = strlen(symbuf->buf[i]) + 1;
+    block_bc(cr,len);
+    snew_bc(cr,symbuf->buf[i],len);
+    nblock_bc(cr,len,symbuf->buf[i]);
+  }
+}
+
+static void bc_block(const t_commrec *cr,t_block *block)
+{
+  block_bc(cr,block->nr);
+  snew_bc(cr,block->index,block->nr+1);
+  nblock_bc(cr,block->nr+1,block->index);
+}
+
+static void bc_blocka(const t_commrec *cr,t_blocka *block)
+{
+  block_bc(cr,block->nr);
+  snew_bc(cr,block->index,block->nr+1);
+  nblock_bc(cr,block->nr+1,block->index);
+  block_bc(cr,block->nra);
+  if (block->nra) {
+    snew_bc(cr,block->a,block->nra);
+    nblock_bc(cr,block->nra,block->a);
+  }
+}
+
+static void bc_grps(const t_commrec *cr,t_grps grps[])
+{
+  int i;
+  
+  for(i=0; (i<egcNR); i++) {
+    block_bc(cr,grps[i].nr);
+    snew_bc(cr,grps[i].nm_ind,grps[i].nr);
+    nblock_bc(cr,grps[i].nr,grps[i].nm_ind);
+  }
+}
+
+static void bc_atoms(const t_commrec *cr,t_symtab *symtab,t_atoms *atoms)
+{
+  int dummy;
+
+  block_bc(cr,atoms->nr);
+  snew_bc(cr,atoms->atom,atoms->nr);
+  nblock_bc(cr,atoms->nr,atoms->atom);
+  bc_strings(cr,symtab,atoms->nr,&atoms->atomname);
+  block_bc(cr,atoms->nres);
+  snew_bc(cr,atoms->resinfo,atoms->nres);
+  nblock_bc(cr,atoms->nres,atoms->resinfo);
+  bc_strings_resinfo(cr,symtab,atoms->nres,atoms->resinfo);
+  /* QMMM requires atomtypes to be known on all nodes as well */
+  bc_strings(cr,symtab,atoms->nr,&atoms->atomtype);
+  bc_strings(cr,symtab,atoms->nr,&atoms->atomtypeB);
+}
+
+static void bc_groups(const t_commrec *cr,t_symtab *symtab,
+                     int natoms,gmx_groups_t *groups)
+{
+  int dummy;
+  int g,n;
+
+  bc_grps(cr,groups->grps);
+  block_bc(cr,groups->ngrpname);
+  bc_strings(cr,symtab,groups->ngrpname,&groups->grpname);
+  for(g=0; g<egcNR; g++) {
+    if (MASTER(cr)) {
+      if (groups->grpnr[g]) {
+       n = natoms;
+      } else {
+       n = 0;
+      }
+    }
+    block_bc(cr,n);
+    if (n == 0) {
+      groups->grpnr[g] = NULL;
+    } else {
+      snew_bc(cr,groups->grpnr[g],n);
+      nblock_bc(cr,n,groups->grpnr[g]);
+    }
+  }
+  if (debug) fprintf(debug,"after bc_groups\n");
+}
+
+void bcast_state_setup(const t_commrec *cr,t_state *state)
+{
+  block_bc(cr,state->natoms);
+  block_bc(cr,state->ngtc);
+  block_bc(cr,state->nnhpres);
+  block_bc(cr,state->nhchainlength);
+  block_bc(cr,state->nrng);
+  block_bc(cr,state->nrngi);
+  block_bc(cr,state->flags);
+}
+
+void bcast_state(const t_commrec *cr,t_state *state,gmx_bool bAlloc)
+{
+  int i,nnht,nnhtp;
+
+  bcast_state_setup(cr,state);
+
+  nnht = (state->ngtc)*(state->nhchainlength); 
+  nnhtp = (state->nnhpres)*(state->nhchainlength); 
+
+  if (MASTER(cr)) {
+    bAlloc = FALSE;
+  }
+  if (bAlloc) {
+    state->nalloc = state->natoms;
+  }
+  for(i=0; i<estNR; i++) {
+    if (state->flags & (1<<i)) {
+      switch (i) {
+      case estLAMBDA:  block_bc(cr,state->lambda); break;
+      case estBOX:     block_bc(cr,state->box); break;
+      case estBOX_REL: block_bc(cr,state->box_rel); break;
+      case estBOXV:    block_bc(cr,state->boxv); break;
+      case estPRES_PREV: block_bc(cr,state->pres_prev); break;
+      case estSVIR_PREV: block_bc(cr,state->svir_prev); break;
+      case estFVIR_PREV: block_bc(cr,state->fvir_prev); break;
+      case estNH_XI:   nblock_abc(cr,nnht,state->nosehoover_xi); break;
+      case estNH_VXI:  nblock_abc(cr,nnht,state->nosehoover_vxi); break;
+      case estNHPRES_XI:   nblock_abc(cr,nnhtp,state->nhpres_xi); break;
+      case estNHPRES_VXI:  nblock_abc(cr,nnhtp,state->nhpres_vxi); break;
+      case estTC_INT:  nblock_abc(cr,state->ngtc,state->therm_integral); break;
+      case estVETA:    block_bc(cr,state->veta); break;
+      case estVOL0:    block_bc(cr,state->vol0); break;
+      case estX:       nblock_abc(cr,state->natoms,state->x); break;
+      case estV:       nblock_abc(cr,state->natoms,state->v); break;
+      case estSDX:     nblock_abc(cr,state->natoms,state->sd_X); break;
+      case estCGP:     nblock_abc(cr,state->natoms,state->cg_p); break;
+         case estLD_RNG:  if(state->nrngi == 1) nblock_abc(cr,state->nrng,state->ld_rng); break;
+         case estLD_RNGI: if(state->nrngi == 1) nblock_abc(cr,state->nrngi,state->ld_rngi); break;
+      case estDISRE_INITF: block_bc(cr,state->hist.disre_initf); break;
+      case estDISRE_RM3TAV:
+          block_bc(cr,state->hist.ndisrepairs);
+          nblock_abc(cr,state->hist.ndisrepairs,state->hist.disre_rm3tav);
+          break;
+      case estORIRE_INITF: block_bc(cr,state->hist.orire_initf); break;
+      case estORIRE_DTAV:
+          block_bc(cr,state->hist.norire_Dtav);
+          nblock_abc(cr,state->hist.norire_Dtav,state->hist.orire_Dtav);
+          break;
+      default:
+          gmx_fatal(FARGS,
+                    "Communication is not implemented for %s in bcast_state",
+                    est_names[i]);
+      }
+    }
+  }
+}
+
+static void bc_ilists(const t_commrec *cr,t_ilist *ilist)
+{
+  int ftype;
+
+  /* Here we only communicate the non-zero length ilists */
+  if (MASTER(cr)) {
+    for(ftype=0; ftype<F_NRE; ftype++) {
+      if (ilist[ftype].nr > 0) {
+       block_bc(cr,ftype);
+       block_bc(cr,ilist[ftype].nr);
+       nblock_bc(cr,ilist[ftype].nr,ilist[ftype].iatoms);
+      }
+    }
+    ftype = -1;
+    block_bc(cr,ftype);
+  } else {
+    for(ftype=0; ftype<F_NRE; ftype++) {
+      ilist[ftype].nr = 0;
+    }
+    do {
+      block_bc(cr,ftype);
+      if (ftype >= 0) {
+       block_bc(cr,ilist[ftype].nr);
+       snew_bc(cr,ilist[ftype].iatoms,ilist[ftype].nr);
+       nblock_bc(cr,ilist[ftype].nr,ilist[ftype].iatoms);
+      }
+    } while (ftype >= 0);
+  }
+
+  if (debug) fprintf(debug,"after bc_ilists\n");
+}
+
+static void bc_idef(const t_commrec *cr,t_idef *idef)
+{
+  block_bc(cr,idef->ntypes);
+  block_bc(cr,idef->atnr);
+  snew_bc(cr,idef->functype,idef->ntypes);
+  snew_bc(cr,idef->iparams,idef->ntypes);
+  nblock_bc(cr,idef->ntypes,idef->functype);
+  nblock_bc(cr,idef->ntypes,idef->iparams);
+  block_bc(cr,idef->fudgeQQ);
+  bc_ilists(cr,idef->il);
+  block_bc(cr,idef->ilsort);
+}
+
+static void bc_cmap(const t_commrec *cr, gmx_cmap_t *cmap_grid)
+{
+       int i,j,nelem,ngrid;
+       
+       block_bc(cr,cmap_grid->ngrid);
+       block_bc(cr,cmap_grid->grid_spacing);
+       
+       ngrid = cmap_grid->ngrid;
+       nelem = cmap_grid->grid_spacing * cmap_grid->grid_spacing;
+       
+       if(ngrid>0)
+       {
+               snew_bc(cr,cmap_grid->cmapdata,ngrid);
+               
+               for(i=0;i<ngrid;i++)
+               {
+                       snew_bc(cr,cmap_grid->cmapdata[i].cmap,4*nelem);
+                       nblock_bc(cr,4*nelem,cmap_grid->cmapdata[i].cmap);
+               }
+       }
+}
+
+static void bc_ffparams(const t_commrec *cr,gmx_ffparams_t *ffp)
+{
+  int i;
+  
+  block_bc(cr,ffp->ntypes);
+  block_bc(cr,ffp->atnr);
+  snew_bc(cr,ffp->functype,ffp->ntypes);
+  snew_bc(cr,ffp->iparams,ffp->ntypes);
+  nblock_bc(cr,ffp->ntypes,ffp->functype);
+  nblock_bc(cr,ffp->ntypes,ffp->iparams);
+  block_bc(cr,ffp->reppow);
+  block_bc(cr,ffp->fudgeQQ);
+  bc_cmap(cr,&ffp->cmap_grid);
+}
+
+static void bc_grpopts(const t_commrec *cr,t_grpopts *g)
+{
+    int i,n;
+    
+    block_bc(cr,g->ngtc);
+    block_bc(cr,g->ngacc);
+    block_bc(cr,g->ngfrz);
+    block_bc(cr,g->ngener);
+    snew_bc(cr,g->nrdf,g->ngtc);
+    snew_bc(cr,g->tau_t,g->ngtc);
+    snew_bc(cr,g->ref_t,g->ngtc);
+    snew_bc(cr,g->acc,g->ngacc);
+    snew_bc(cr,g->nFreeze,g->ngfrz);
+    snew_bc(cr,g->egp_flags,g->ngener*g->ngener);
+    
+    nblock_bc(cr,g->ngtc,g->nrdf);
+    nblock_bc(cr,g->ngtc,g->tau_t);
+    nblock_bc(cr,g->ngtc,g->ref_t);
+    nblock_bc(cr,g->ngacc,g->acc);
+    nblock_bc(cr,g->ngfrz,g->nFreeze);
+    nblock_bc(cr,g->ngener*g->ngener,g->egp_flags);
+    snew_bc(cr,g->annealing,g->ngtc);
+    snew_bc(cr,g->anneal_npoints,g->ngtc);
+    snew_bc(cr,g->anneal_time,g->ngtc);
+    snew_bc(cr,g->anneal_temp,g->ngtc);
+    nblock_bc(cr,g->ngtc,g->annealing);
+    nblock_bc(cr,g->ngtc,g->anneal_npoints);
+    for(i=0;(i<g->ngtc); i++) {
+        n = g->anneal_npoints[i];
+        if (n > 0) {
+         snew_bc(cr,g->anneal_time[i],n);
+         snew_bc(cr,g->anneal_temp[i],n);
+         nblock_bc(cr,n,g->anneal_time[i]);
+         nblock_bc(cr,n,g->anneal_temp[i]);
+        }
+    }
+    
+    /* QMMM stuff, see inputrec */
+    block_bc(cr,g->ngQM);
+    snew_bc(cr,g->QMmethod,g->ngQM);
+    snew_bc(cr,g->QMbasis,g->ngQM);
+    snew_bc(cr,g->QMcharge,g->ngQM);
+    snew_bc(cr,g->QMmult,g->ngQM);
+    snew_bc(cr,g->bSH,g->ngQM);
+    snew_bc(cr,g->CASorbitals,g->ngQM);
+    snew_bc(cr,g->CASelectrons,g->ngQM);
+    snew_bc(cr,g->SAon,g->ngQM);
+    snew_bc(cr,g->SAoff,g->ngQM);
+    snew_bc(cr,g->SAsteps,g->ngQM);
+    
+    if (g->ngQM)
+    {
+        nblock_bc(cr,g->ngQM,g->QMmethod);
+        nblock_bc(cr,g->ngQM,g->QMbasis);
+        nblock_bc(cr,g->ngQM,g->QMcharge);
+        nblock_bc(cr,g->ngQM,g->QMmult);
+        nblock_bc(cr,g->ngQM,g->bSH);
+        nblock_bc(cr,g->ngQM,g->CASorbitals);
+        nblock_bc(cr,g->ngQM,g->CASelectrons);
+        nblock_bc(cr,g->ngQM,g->SAon);
+        nblock_bc(cr,g->ngQM,g->SAoff);
+        nblock_bc(cr,g->ngQM,g->SAsteps);
+        /* end of QMMM stuff */
+    }
+}
+
+static void bc_cosines(const t_commrec *cr,t_cosines *cs)
+{
+  block_bc(cr,cs->n);
+  snew_bc(cr,cs->a,cs->n);
+  snew_bc(cr,cs->phi,cs->n);
+  if (cs->n > 0) {
+    nblock_bc(cr,cs->n,cs->a);
+    nblock_bc(cr,cs->n,cs->phi);
+  }
+}
+
+static void bc_pullgrp(const t_commrec *cr,t_pullgrp *pgrp)
+{
+  block_bc(cr,*pgrp);
+  if (pgrp->nat > 0) {
+    snew_bc(cr,pgrp->ind,pgrp->nat);
+    nblock_bc(cr,pgrp->nat,pgrp->ind);
+  }
+  if (pgrp->nweight > 0) {
+    snew_bc(cr,pgrp->weight,pgrp->nweight);
+    nblock_bc(cr,pgrp->nweight,pgrp->weight);
+  }
+}
+
+static void bc_pull(const t_commrec *cr,t_pull *pull)
+{
+  int g;
+
+  block_bc(cr,*pull);
+  snew_bc(cr,pull->grp,pull->ngrp+1);
+  for(g=0; g<pull->ngrp+1; g++)
+  {
+      bc_pullgrp(cr,&pull->grp[g]);
+  }
+}
+
+static void bc_rotgrp(const t_commrec *cr,t_rotgrp *rotg)
+{
+  block_bc(cr,*rotg);
+  if (rotg->nat > 0) {
+    snew_bc(cr,rotg->ind,rotg->nat);
+    nblock_bc(cr,rotg->nat,rotg->ind);
+    snew_bc(cr,rotg->x_ref,rotg->nat);
+    nblock_bc(cr,rotg->nat,rotg->x_ref);
+  }
+}
+
+static void bc_rot(const t_commrec *cr,t_rot *rot)
+{
+  int g;
+
+  block_bc(cr,*rot);
+  snew_bc(cr,rot->grp,rot->ngrp);
+  for(g=0; g<rot->ngrp; g++)
+    bc_rotgrp(cr,&rot->grp[g]);
+}
+
+static void bc_inputrec(const t_commrec *cr,t_inputrec *inputrec)
+{
+  gmx_bool bAlloc=TRUE;
+  int i;
+  
+  block_bc(cr,*inputrec);
+  snew_bc(cr,inputrec->flambda,inputrec->n_flambda);
+  nblock_bc(cr,inputrec->n_flambda,inputrec->flambda);
+  bc_grpopts(cr,&(inputrec->opts));
+  if (inputrec->ePull != epullNO) {
+    snew_bc(cr,inputrec->pull,1);
+    bc_pull(cr,inputrec->pull);
+  }
+  if (inputrec->bRot) {
+    snew_bc(cr,inputrec->rot,1);
+    bc_rot(cr,inputrec->rot);
+  }
+  for(i=0; (i<DIM); i++) {
+    bc_cosines(cr,&(inputrec->ex[i]));
+    bc_cosines(cr,&(inputrec->et[i]));
+  }
+}
+
+static void bc_moltype(const t_commrec *cr,t_symtab *symtab,
+                      gmx_moltype_t *moltype)
+{
+  bc_string(cr,symtab,&moltype->name);
+  bc_atoms(cr,symtab,&moltype->atoms);
+  if (debug) fprintf(debug,"after bc_atoms\n");
+
+  bc_ilists(cr,moltype->ilist);
+  bc_block(cr,&moltype->cgs);
+  bc_blocka(cr,&moltype->excls);
+}
+
+static void bc_molblock(const t_commrec *cr,gmx_molblock_t *molb)
+{
+  gmx_bool bAlloc=TRUE;
+  
+  block_bc(cr,molb->type);
+  block_bc(cr,molb->nmol);
+  block_bc(cr,molb->natoms_mol);
+  block_bc(cr,molb->nposres_xA);
+  if (molb->nposres_xA > 0) {
+    snew_bc(cr,molb->posres_xA,molb->nposres_xA);
+    nblock_bc(cr,molb->nposres_xA*DIM,molb->posres_xA[0]);
+  }
+  block_bc(cr,molb->nposres_xB);
+  if (molb->nposres_xB > 0) {
+    snew_bc(cr,molb->posres_xB,molb->nposres_xB);
+    nblock_bc(cr,molb->nposres_xB*DIM,molb->posres_xB[0]);
+  }
+  if (debug) fprintf(debug,"after bc_molblock\n");
+}
+
+static void bc_atomtypes(const t_commrec *cr, t_atomtypes *atomtypes)
+{
+  int nr;
+
+  block_bc(cr,atomtypes->nr);
+
+  nr = atomtypes->nr;
+
+  snew_bc(cr,atomtypes->radius,nr);
+  snew_bc(cr,atomtypes->vol,nr);
+  snew_bc(cr,atomtypes->surftens,nr);
+  snew_bc(cr,atomtypes->gb_radius,nr);
+  snew_bc(cr,atomtypes->S_hct,nr);
+
+  nblock_bc(cr,nr,atomtypes->radius);
+  nblock_bc(cr,nr,atomtypes->vol);
+  nblock_bc(cr,nr,atomtypes->surftens);
+  nblock_bc(cr,nr,atomtypes->gb_radius);
+  nblock_bc(cr,nr,atomtypes->S_hct);
+}
+
+
+void bcast_ir_mtop(const t_commrec *cr,t_inputrec *inputrec,gmx_mtop_t *mtop)
+{
+  int i; 
+  if (debug) fprintf(debug,"in bc_data\n");
+  bc_inputrec(cr,inputrec);
+  if (debug) fprintf(debug,"after bc_inputrec\n");
+  bc_symtab(cr,&mtop->symtab);
+  if (debug) fprintf(debug,"after bc_symtab\n");
+  bc_string(cr,&mtop->symtab,&mtop->name);
+  if (debug) fprintf(debug,"after bc_name\n");
+
+  bc_ffparams(cr,&mtop->ffparams);
+
+  block_bc(cr,mtop->nmoltype);
+  snew_bc(cr,mtop->moltype,mtop->nmoltype);
+  for(i=0; i<mtop->nmoltype; i++) {
+    bc_moltype(cr,&mtop->symtab,&mtop->moltype[i]);
+  }
+
+  block_bc(cr,mtop->nmolblock);
+  snew_bc(cr,mtop->molblock,mtop->nmolblock);
+  for(i=0; i<mtop->nmolblock; i++) {
+    bc_molblock(cr,&mtop->molblock[i]);
+  }
+
+  block_bc(cr,mtop->natoms);
+
+  bc_atomtypes(cr,&mtop->atomtypes);
+
+  bc_block(cr,&mtop->mols);
+  bc_groups(cr,&mtop->symtab,mtop->natoms,&mtop->groups);
+}
diff --git a/src/gromacs/gmxlib/names.c b/src/gromacs/gmxlib/names.c
new file mode 100644 (file)
index 0000000..df1ad2f
--- /dev/null
@@ -0,0 +1,219 @@
+/*
+ * 
+ *                This source code is part of
+ * 
+ *                 G   R   O   M   A   C   S
+ * 
+ *          GROningen MAchine for Chemical Simulations
+ * 
+ *                        VERSION 3.2.0
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * 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.
+
+ * 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:
+ * GROningen Mixture of Alchemy and Childrens' Stories
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "typedefs.h"
+#include "names.h"
+
+/* note: these arrays should correspond to enums in include/types/enums.h */
+
+const char *epbc_names[epbcNR+1]=
+{
+  "xyz", "no", "xy", "screw", NULL
+};
+
+const char *ens_names[ensNR+1]=
+{
+  "Grid","Simple", NULL
+};
+
+const char *ei_names[eiNR+1]=
+{
+  "md", "steep", "cg", "bd", "sd", "nm", "l-bfgs", "tpi", "tpic", "sd1", "md-vv", "md-vv-avek",NULL 
+};
+
+const char *bool_names[BOOL_NR+1]=
+{
+  "FALSE","TRUE", NULL
+};
+
+const char *yesno_names[BOOL_NR+1]=
+{
+  "no","yes", NULL
+};
+
+const char *ptype_str[eptNR+1] = {
+  "Atom", "Nucleus", "Shell", "Bond", "VSite", NULL
+};
+
+const char *eel_names[eelNR+1] = {
+  "Cut-off", "Reaction-Field", "Generalized-Reaction-Field",
+  "PME", "Ewald", "PPPM", "Poisson", "Switch", "Shift", "User", 
+  "Generalized-Born", "Reaction-Field-nec", "Encad-shift", 
+  "PME-User", "PME-Switch", "PME-User-Switch", 
+  "Reaction-Field-zero", NULL
+};
+
+const char *eewg_names[eewgNR+1] = {
+  "3d", "3dc", NULL
+};
+
+const char *evdw_names[evdwNR+1] = {
+  "Cut-off", "Switch", "Shift", "User", "Encad-shift", NULL
+};
+
+const char *econstr_names[econtNR+1] = {
+  "Lincs", "Shake", NULL
+};
+
+const char *egrp_nm[egNR+1] = { 
+  "Coul-SR","LJ-SR","Buck-SR", "Coul-LR", "LJ-LR", "Buck-LR",
+  "Coul-14", "LJ-14", NULL
+};
+
+const char *etcoupl_names[etcNR+1] = {
+  "No", "Berendsen", "Nose-Hoover", "yes", "Andersen", "Andersen-interval", "V-rescale", NULL
+}; /* yes is alias for berendsen */
+
+const char *epcoupl_names[epcNR+1] = {
+  "No", "Berendsen", "Parrinello-Rahman", "Isotropic", "MTTK", NULL
+}; /* isotropic is alias for berendsen */
+
+const char *epcoupltype_names[epctNR+1] = {
+  "Isotropic", "Semiisotropic", "Anisotropic", "Surface-Tension", NULL
+};
+
+const char *erefscaling_names[erscNR+1] = {
+  "No", "All", "COM", NULL
+};
+
+const char *edisre_names[edrNR+1] = {
+  "No", "Simple", "Ensemble", NULL
+};
+
+const char *edisreweighting_names[edrwNR+1] = {
+  "Conservative", "Equal", NULL
+};
+
+const char *enbf_names[eNBF_NR+1] = {
+  "", "LJ", "Buckingham", NULL
+};
+
+const char *ecomb_names[eCOMB_NR+1] = {
+  "", "Geometric", "Arithmetic", "GeomSigEps", NULL
+};
+
+const char *gtypes[egcNR+1] = {
+  "T-Coupling", "Energy Mon.", "Acceleration", "Freeze",
+  "User1", "User2", "VCM", "XTC", "Or. Res. Fit", "QMMM", NULL
+};
+
+const char *efep_names[efepNR+1] = {
+  "no", "yes", NULL
+};
+
+const char *separate_dhdl_file_names[sepdhdlfileNR+1] = {
+  "yes", "no", NULL
+};
+
+const char *dhdl_derivatives_names[dhdlderivativesNR+1] = {
+  "yes", "no", NULL
+};
+
+const char *esol_names[esolNR+1] = {
+  "No", "SPC", "TIP4p", NULL
+};
+
+const char *enlist_names[enlistNR+1] = {
+  "Atom-Atom", "SPC-Atom", "SPC-SPC", "TIP4p-Atom", "TIP4p-TIP4p", "CG-CG", NULL
+};
+
+const char *edispc_names[edispcNR+1] = {
+  "No", "EnerPres", "Ener", "AllEnerPres", "AllEner", NULL
+};
+
+const char *ecm_names[ecmNR+1] = { 
+  "Linear", "Angular", "None", NULL 
+};
+
+const char *eann_names[eannNR+1] = {
+  "No", "Single", "Periodic", NULL
+};
+
+const char *eis_names[eisNR+1] = {
+       "No", "GBSA", NULL
+};
+
+const char *egb_names[egbNR+1] = {
+  "Still", "HCT", "OBC", NULL
+};
+
+const char *esa_names[esaNR+1] = {
+  "Ace-approximation", "None", "Still", NULL
+};
+
+const char *ewt_names[ewtNR+1] = {
+  "9-3", "10-4", "table", "12-6", NULL
+};
+
+const char *epull_names[epullNR+1] = { 
+  "no", "umbrella", "constraint", "constant_force", NULL
+};
+
+const char *epullg_names[epullgNR+1] = { 
+  "distance", "direction", "cylinder", "position", "direction_periodic", NULL
+};
+
+const char *erotg_names[erotgNR+1] = { 
+  "iso", "iso-pf", "pm", "pm-pf", "rm", "rm-pf", "rm2", "rm2-pf", "flex", "flex-t", "flex2", "flex2-t", NULL
+};
+
+const char *erotg_fitnames[erotgFitNR+1] = { 
+  "rmsd", "norm", NULL
+};
+
+const char *eQMmethod_names[eQMmethodNR+1] = {
+  "AM1", "PM3", "RHF",
+  "UHF", "DFT", "B3LYP", "MP2", "CASSCF","B3LYPLAN",
+  "DIRECT", NULL
+};
+
+const char *eQMbasis_names[eQMbasisNR+1] = {
+  "STO3G", "STO-3G", "3-21G",
+  "3-21G*", "3-21+G*", "6-21G",
+  "6-31G", "6-31G*", "6-31+G*",
+  "6-311G", NULL
+};
+
+const char *eQMMMscheme_names[eQMMMschemeNR+1] = {
+  "normal", "ONIOM", NULL
+};
+
+const char *eMultentOpt_names[eMultentOptNR+1] = {
+  "multiple_entries", "no", "use_last", NULL
+};
+
diff --git a/src/gromacs/gmxlib/network.c b/src/gromacs/gmxlib/network.c
new file mode 100644 (file)
index 0000000..2a7138f
--- /dev/null
@@ -0,0 +1,698 @@
+/*
+ * 
+ *                This source code is part of
+ * 
+ *                 G   R   O   M   A   C   S
+ * 
+ *          GROningen MAchine for Chemical Simulations
+ * 
+ *                        VERSION 3.2.0
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * 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.
+
+ * 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:
+ * GROningen Mixture of Alchemy and Childrens' Stories
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include "gmx_fatal.h"
+#include "main.h"
+#include "smalloc.h"
+#include "network.h"
+#include "copyrite.h"
+#include "statutil.h"
+#include "ctype.h"
+#include "macros.h"
+
+#ifdef GMX_LIB_MPI
+#include <mpi.h>
+#endif
+
+#ifdef GMX_THREADS
+#include "tmpi.h"
+#endif
+
+#include "mpelogging.h"
+
+/* The source code in this file should be thread-safe. 
+      Please keep it that way. */
+
+gmx_bool gmx_mpi_initialized(void)
+{
+  int n;
+#ifndef GMX_MPI
+  return 0;
+#else
+  MPI_Initialized(&n);
+  
+  return n;
+#endif
+}
+
+int gmx_setup(int *argc,char **argv,int *nnodes)
+{
+#ifndef GMX_MPI
+  gmx_call("gmx_setup");
+  return 0;
+#else
+  char   buf[256];
+  int    resultlen;               /* actual length of node name      */
+  int    i,flag;
+  int  mpi_num_nodes;
+  int  mpi_my_rank;
+  char mpi_hostname[MPI_MAX_PROCESSOR_NAME];
+
+  /* Call the MPI routines */
+#ifdef GMX_LIB_MPI
+#ifdef GMX_FAHCORE
+  (void) fah_MPI_Init(argc,&argv);
+#else
+  (void) MPI_Init(argc,&argv);
+#endif
+#endif
+  (void) MPI_Comm_size( MPI_COMM_WORLD, &mpi_num_nodes );
+  (void) MPI_Comm_rank( MPI_COMM_WORLD, &mpi_my_rank );
+  (void) MPI_Get_processor_name( mpi_hostname, &resultlen );
+
+
+#ifdef USE_MPE
+  /* MPE logging routines. Get event IDs from MPE: */
+  /* General events */
+  ev_timestep1               = MPE_Log_get_event_number( );
+  ev_timestep2               = MPE_Log_get_event_number( );
+  ev_force_start             = MPE_Log_get_event_number( );
+  ev_force_finish            = MPE_Log_get_event_number( );
+  ev_do_fnbf_start           = MPE_Log_get_event_number( );
+  ev_do_fnbf_finish          = MPE_Log_get_event_number( );
+  ev_ns_start                = MPE_Log_get_event_number( );
+  ev_ns_finish               = MPE_Log_get_event_number( );
+  ev_calc_bonds_start        = MPE_Log_get_event_number( );
+  ev_calc_bonds_finish       = MPE_Log_get_event_number( );
+  ev_global_stat_start       = MPE_Log_get_event_number( );
+  ev_global_stat_finish      = MPE_Log_get_event_number( );
+  ev_virial_start            = MPE_Log_get_event_number( );
+  ev_virial_finish           = MPE_Log_get_event_number( );
+  
+  /* Enforced rotation */
+  ev_flexll_start            = MPE_Log_get_event_number( );
+  ev_flexll_finish           = MPE_Log_get_event_number( );
+  ev_add_rot_forces_start    = MPE_Log_get_event_number( );
+  ev_add_rot_forces_finish   = MPE_Log_get_event_number( );
+  ev_rotcycles_start         = MPE_Log_get_event_number( );
+  ev_rotcycles_finish        = MPE_Log_get_event_number( );
+  ev_forcecycles_start       = MPE_Log_get_event_number( );
+  ev_forcecycles_finish      = MPE_Log_get_event_number( );
+
+  /* Shift related events */
+  ev_shift_start             = MPE_Log_get_event_number( );
+  ev_shift_finish            = MPE_Log_get_event_number( );
+  ev_unshift_start           = MPE_Log_get_event_number( );
+  ev_unshift_finish          = MPE_Log_get_event_number( );
+  ev_mk_mshift_start         = MPE_Log_get_event_number( );
+  ev_mk_mshift_finish        = MPE_Log_get_event_number( );
+  
+  /* PME related events */
+  ev_pme_start               = MPE_Log_get_event_number( );
+  ev_pme_finish              = MPE_Log_get_event_number( );
+  ev_spread_on_grid_start    = MPE_Log_get_event_number( );
+  ev_spread_on_grid_finish   = MPE_Log_get_event_number( );
+  ev_sum_qgrid_start         = MPE_Log_get_event_number( );
+  ev_sum_qgrid_finish        = MPE_Log_get_event_number( );
+  ev_gmxfft3d_start          = MPE_Log_get_event_number( );
+  ev_gmxfft3d_finish         = MPE_Log_get_event_number( );
+  ev_solve_pme_start         = MPE_Log_get_event_number( );
+  ev_solve_pme_finish        = MPE_Log_get_event_number( );
+  ev_gather_f_bsplines_start = MPE_Log_get_event_number( );
+  ev_gather_f_bsplines_finish= MPE_Log_get_event_number( );
+  ev_reduce_start            = MPE_Log_get_event_number( );
+  ev_reduce_finish           = MPE_Log_get_event_number( );
+  ev_rscatter_start          = MPE_Log_get_event_number( );
+  ev_rscatter_finish         = MPE_Log_get_event_number( );
+  ev_alltoall_start          = MPE_Log_get_event_number( );
+  ev_alltoall_finish         = MPE_Log_get_event_number( );
+  ev_pmeredist_start         = MPE_Log_get_event_number( );
+  ev_pmeredist_finish        = MPE_Log_get_event_number( );
+  ev_init_pme_start          = MPE_Log_get_event_number( );      
+  ev_init_pme_finish         = MPE_Log_get_event_number( );
+  ev_send_coordinates_start  = MPE_Log_get_event_number( );
+  ev_send_coordinates_finish = MPE_Log_get_event_number( );
+  ev_update_fr_start         = MPE_Log_get_event_number( );
+  ev_update_fr_finish        = MPE_Log_get_event_number( );
+  ev_clear_rvecs_start       = MPE_Log_get_event_number( );
+  ev_clear_rvecs_finish      = MPE_Log_get_event_number( ); 
+  ev_update_start            = MPE_Log_get_event_number( ); 
+  ev_update_finish           = MPE_Log_get_event_number( ); 
+  ev_output_start            = MPE_Log_get_event_number( ); 
+  ev_output_finish           = MPE_Log_get_event_number( ); 
+  ev_sum_lrforces_start      = MPE_Log_get_event_number( ); 
+  ev_sum_lrforces_finish     = MPE_Log_get_event_number( ); 
+  ev_sort_start              = MPE_Log_get_event_number( );
+  ev_sort_finish             = MPE_Log_get_event_number( );
+  ev_sum_qgrid_start         = MPE_Log_get_event_number( );
+  ev_sum_qgrid_finish        = MPE_Log_get_event_number( );
+  
+  /* Essential dynamics related events */
+  ev_edsam_start             = MPE_Log_get_event_number( );
+  ev_edsam_finish            = MPE_Log_get_event_number( );
+  ev_get_coords_start        = MPE_Log_get_event_number( );
+  ev_get_coords_finish       = MPE_Log_get_event_number( );
+  ev_ed_apply_cons_start     = MPE_Log_get_event_number( );
+  ev_ed_apply_cons_finish    = MPE_Log_get_event_number( );
+  ev_fit_to_reference_start  = MPE_Log_get_event_number( );
+  ev_fit_to_reference_finish = MPE_Log_get_event_number( );
+  
+  /* describe events: */
+  if ( mpi_my_rank == 0 ) 
+  {
+    /* General events */
+    MPE_Describe_state(ev_timestep1,               ev_timestep2,                "timestep START",  "magenta" );
+    MPE_Describe_state(ev_force_start,             ev_force_finish,             "force",           "cornflower blue" );
+    MPE_Describe_state(ev_do_fnbf_start,           ev_do_fnbf_finish,           "do_fnbf",         "navy" );
+    MPE_Describe_state(ev_ns_start,                ev_ns_finish,                "neighbor search", "tomato" );
+    MPE_Describe_state(ev_calc_bonds_start,        ev_calc_bonds_finish,        "bonded forces",   "slate blue" );
+    MPE_Describe_state(ev_global_stat_start,       ev_global_stat_finish,       "global stat",     "firebrick3");
+    MPE_Describe_state(ev_update_fr_start,         ev_update_fr_finish,         "update forcerec", "goldenrod");
+    MPE_Describe_state(ev_clear_rvecs_start,       ev_clear_rvecs_finish,       "clear rvecs",     "bisque");
+    MPE_Describe_state(ev_update_start,            ev_update_finish,            "update",          "cornsilk");
+    MPE_Describe_state(ev_output_start,            ev_output_finish,            "output",          "black");
+    MPE_Describe_state(ev_virial_start,            ev_virial_finish,            "calc_virial",     "thistle4");
+    
+    /* Enforced rotation */
+    MPE_Describe_state(ev_flexll_start,            ev_flexll_finish,            "flex lowlevel",   "navajo white");
+    MPE_Describe_state(ev_add_rot_forces_start,    ev_add_rot_forces_finish,    "add rot forces",  "green");
+    MPE_Describe_state(ev_rotcycles_start,         ev_rotcycles_finish,         "count rot cyc",   "moccasin");
+    MPE_Describe_state(ev_forcecycles_start,       ev_forcecycles_finish,       "count force cyc", "powder blue");
+
+    /* PME related events */
+    MPE_Describe_state(ev_pme_start,               ev_pme_finish,               "doing PME",       "grey" );
+    MPE_Describe_state(ev_spread_on_grid_start,    ev_spread_on_grid_finish,    "spread",          "dark orange" );   
+    MPE_Describe_state(ev_sum_qgrid_start,         ev_sum_qgrid_finish,         "sum qgrid",       "slate blue");
+    MPE_Describe_state(ev_gmxfft3d_start,          ev_gmxfft3d_finish,          "fft3d",           "snow2" );   
+    MPE_Describe_state(ev_solve_pme_start,         ev_solve_pme_finish,         "solve PME",       "indian red" );   
+    MPE_Describe_state(ev_gather_f_bsplines_start, ev_gather_f_bsplines_finish, "bsplines",        "light sea green" );   
+    MPE_Describe_state(ev_reduce_start,            ev_reduce_finish,            "reduce",          "cyan1" );
+    MPE_Describe_state(ev_rscatter_start,          ev_rscatter_finish,          "rscatter",        "cyan3" );
+    MPE_Describe_state(ev_alltoall_start,          ev_alltoall_finish,          "alltoall",        "LightCyan4" );
+    MPE_Describe_state(ev_pmeredist_start,         ev_pmeredist_finish,         "pmeredist",       "thistle" );
+    MPE_Describe_state(ev_init_pme_start,          ev_init_pme_finish,          "init PME",        "snow4");
+    MPE_Describe_state(ev_send_coordinates_start,  ev_send_coordinates_finish,  "send_coordinates","blue");
+    MPE_Describe_state(ev_sum_lrforces_start,      ev_sum_lrforces_finish,      "sum_LRforces",    "lime green");
+    MPE_Describe_state(ev_sort_start,              ev_sort_finish,              "sort pme atoms",  "brown");
+    MPE_Describe_state(ev_sum_qgrid_start,         ev_sum_qgrid_finish,         "sum charge grid", "medium orchid");
+    
+    /* Shift related events */
+    MPE_Describe_state(ev_shift_start,             ev_shift_finish,             "shift",           "orange");
+    MPE_Describe_state(ev_unshift_start,           ev_unshift_finish,           "unshift",         "dark orange");    
+    MPE_Describe_state(ev_mk_mshift_start,         ev_mk_mshift_finish,         "mk_mshift",       "maroon");
+        
+    /* Essential dynamics related events */
+    MPE_Describe_state(ev_edsam_start,             ev_edsam_finish,             "EDSAM",           "deep sky blue");
+    MPE_Describe_state(ev_get_coords_start,        ev_get_coords_finish,        "ED get coords",   "steel blue");
+    MPE_Describe_state(ev_ed_apply_cons_start,     ev_ed_apply_cons_finish,     "ED apply constr", "forest green");
+    MPE_Describe_state(ev_fit_to_reference_start,  ev_fit_to_reference_finish,  "ED fit to ref",   "lavender");
+       
+  }
+  MPE_Init_log();
+#endif
+#ifdef GMX_LIB_MPI 
+  fprintf(stderr,"NNODES=%d, MYRANK=%d, HOSTNAME=%s\n",
+         mpi_num_nodes,mpi_my_rank,mpi_hostname);
+#endif
+  
+  *nnodes=mpi_num_nodes;
+  
+  return mpi_my_rank;
+#endif
+}
+
+int  gmx_node_num(void)
+{
+#ifndef GMX_MPI
+  return 1;
+#else
+  int i;
+  (void) MPI_Comm_size(MPI_COMM_WORLD, &i);
+  return i;
+#endif
+}
+
+int gmx_node_rank(void)
+{
+#ifndef GMX_MPI
+  return 0;
+#else
+  int i;
+  (void) MPI_Comm_rank(MPI_COMM_WORLD, &i);
+  return i;
+#endif
+}
+
+void gmx_setup_nodecomm(FILE *fplog,t_commrec *cr)
+{
+  gmx_nodecomm_t *nc;
+  int  n,rank,resultlen,hostnum,i,j,ng,ni;
+#ifdef GMX_MPI
+  char mpi_hostname[MPI_MAX_PROCESSOR_NAME],num[MPI_MAX_PROCESSOR_NAME];
+#endif
+
+  /* Many MPI implementations do not optimize MPI_Allreduce
+   * (and probably also other global communication calls)
+   * for multi-core nodes connected by a network.
+   * We can optimize such communication by using one MPI call
+   * within each node and one between the nodes.
+   * For MVAPICH2 and Intel MPI this reduces the time for
+   * the global_stat communication by 25%
+   * for 2x2-core 3 GHz Woodcrest connected by mixed DDR/SDR Infiniband.
+   * B. Hess, November 2007
+   */
+
+  nc = &cr->nc;
+
+  nc->bUse = FALSE;
+#ifndef GMX_THREADS
+  if (getenv("GMX_NO_NODECOMM") == NULL) {
+#ifdef GMX_MPI
+    MPI_Comm_size(cr->mpi_comm_mygroup,&n);
+    MPI_Comm_rank(cr->mpi_comm_mygroup,&rank);
+    MPI_Get_processor_name(mpi_hostname,&resultlen);
+    /* This procedure can only differentiate nodes with host names
+     * that end on unique numbers.
+     */
+    i = 0;
+    j = 0;
+    /* Only parse the host name up to the first dot */
+    while(i < resultlen && mpi_hostname[i] != '.') {
+      if (isdigit(mpi_hostname[i])) {
+       num[j++] = mpi_hostname[i];
+      }
+      i++;
+    }
+    num[j] = '\0';
+    if (j == 0) {
+      hostnum = 0;
+    } else {
+      /* Use only the last 9 decimals, so we don't overflow an int */
+      hostnum = strtol(num + max(0,j-9), NULL, 10); 
+    }
+
+    if (debug) {
+      fprintf(debug,
+             "In gmx_setup_nodecomm: splitting communicator of size %d\n",
+             n);
+      fprintf(debug,"In gmx_setup_nodecomm: hostname '%s', hostnum %d\n",
+             mpi_hostname,hostnum);
+    }
+
+    /* The intra-node communicator, split on node number */
+    MPI_Comm_split(cr->mpi_comm_mygroup,hostnum,rank,&nc->comm_intra);
+    MPI_Comm_rank(nc->comm_intra,&nc->rank_intra);
+    if (debug) {
+      fprintf(debug,"In gmx_setup_nodecomm: node rank %d rank_intra %d\n",
+             rank,nc->rank_intra);
+    }
+    /* The inter-node communicator, split on rank_intra.
+     * We actually only need the one for rank=0,
+     * but it is easier to create them all.
+     */
+    MPI_Comm_split(cr->mpi_comm_mygroup,nc->rank_intra,rank,&nc->comm_inter);
+    /* Check if this really created two step communication */
+    MPI_Comm_size(nc->comm_inter,&ng);
+    MPI_Comm_size(nc->comm_intra,&ni);
+    if (debug) {
+      fprintf(debug,"In gmx_setup_nodecomm: groups %d, my group size %d\n",
+             ng,ni);
+    }
+    if ((ng > 1 && ng < n) || (ni > 1 && ni < n)) {
+      nc->bUse = TRUE;
+      if (fplog)
+       fprintf(fplog,"Using two step summing over %d groups of on average %.1f processes\n\n",ng,(real)n/(real)ng);
+      if (nc->rank_intra > 0)
+       MPI_Comm_free(&nc->comm_inter);
+    } else {
+      /* One group or all processes in a separate group, use normal summing */
+      MPI_Comm_free(&nc->comm_inter);
+      MPI_Comm_free(&nc->comm_intra);
+    }
+#endif
+  }
+#endif
+}
+
+void gmx_barrier(const t_commrec *cr)
+{
+#ifndef GMX_MPI
+  gmx_call("gmx_barrier");
+#else
+  MPI_Barrier(cr->mpi_comm_mygroup);
+#endif
+}
+
+void gmx_abort(int noderank,int nnodes,int errorno)
+{
+#ifndef GMX_MPI
+  gmx_call("gmx_abort");
+#else
+#ifdef GMX_THREADS
+  fprintf(stderr,"Halting program %s\n",ShortProgram());
+  thanx(stderr);
+  exit(1);
+#else
+  if (nnodes > 1)
+  {
+      fprintf(stderr,"Halting parallel program %s on CPU %d out of %d\n",
+              ShortProgram(),noderank,nnodes);
+  }
+  else
+  {
+      fprintf(stderr,"Halting program %s\n",ShortProgram());
+  }
+
+  thanx(stderr);
+  MPI_Abort(MPI_COMM_WORLD,errorno);
+  exit(1);
+#endif
+#endif
+}
+
+void gmx_bcast(int nbytes,void *b,const t_commrec *cr)
+{
+#ifndef GMX_MPI
+  gmx_call("gmx_bast");
+#else
+  MPI_Bcast(b,nbytes,MPI_BYTE,MASTERRANK(cr),cr->mpi_comm_mygroup);
+#endif
+}
+
+void gmx_bcast_sim(int nbytes,void *b,const t_commrec *cr)
+{
+#ifndef GMX_MPI
+  gmx_call("gmx_bast");
+#else
+  MPI_Bcast(b,nbytes,MPI_BYTE,MASTERRANK(cr),cr->mpi_comm_mysim);
+#endif
+}
+
+void gmx_sumd(int nr,double r[],const t_commrec *cr)
+{
+#ifndef GMX_MPI
+    gmx_call("gmx_sumd");
+#else
+#if defined(MPI_IN_PLACE_EXISTS) || defined(GMX_THREADS)
+    if (cr->nc.bUse) {
+        if (cr->nc.rank_intra == 0)
+        {
+            /* Use two step summing. */
+            MPI_Reduce(MPI_IN_PLACE,r,nr,MPI_DOUBLE,MPI_SUM,0,
+                       cr->nc.comm_intra);
+            /* Sum the roots of the internal (intra) buffers. */
+            MPI_Allreduce(MPI_IN_PLACE,r,nr,MPI_DOUBLE,MPI_SUM,
+                          cr->nc.comm_inter);
+        }
+        else
+        {
+            /* This is here because of the silly MPI specification
+                that MPI_IN_PLACE should be put in sendbuf instead of recvbuf */
+            MPI_Reduce(r,NULL,nr,MPI_DOUBLE,MPI_SUM,0,cr->nc.comm_intra);
+        }
+        MPI_Bcast(r,nr,MPI_DOUBLE,0,cr->nc.comm_intra);
+    } 
+    else 
+    {
+        MPI_Allreduce(MPI_IN_PLACE,r,nr,MPI_DOUBLE,MPI_SUM, 
+                      cr->mpi_comm_mygroup);
+    }
+#else
+    int i;
+
+    if (nr > cr->mpb->dbuf_alloc) {
+        cr->mpb->dbuf_alloc = nr;
+        srenew(cr->mpb->dbuf,cr->mpb->dbuf_alloc);
+    }
+    if (cr->nc.bUse) {
+        /* Use two step summing */
+        MPI_Allreduce(r,cr->mpb->dbuf,nr,MPI_DOUBLE,MPI_SUM,cr->nc.comm_intra);
+        if (cr->nc.rank_intra == 0) {
+            /* Sum with the buffers reversed */
+            MPI_Allreduce(cr->mpb->dbuf,r,nr,MPI_DOUBLE,MPI_SUM, 
+                          cr->nc.comm_inter);
+        }
+        MPI_Bcast(r,nr,MPI_DOUBLE,0,cr->nc.comm_intra);
+    } else {
+        MPI_Allreduce(r,cr->mpb->dbuf,nr,MPI_DOUBLE,MPI_SUM,
+                      cr->mpi_comm_mygroup);
+        for(i=0; i<nr; i++)
+            r[i] = cr->mpb->dbuf[i];
+    }
+#endif
+#endif
+}
+
+void gmx_sumf(int nr,float r[],const t_commrec *cr)
+{
+#ifndef GMX_MPI
+    gmx_call("gmx_sumf");
+#else
+#if defined(MPI_IN_PLACE_EXISTS) || defined(GMX_THREADS)
+    if (cr->nc.bUse) {
+        /* Use two step summing.  */
+        if (cr->nc.rank_intra == 0)
+        {
+            MPI_Reduce(MPI_IN_PLACE,r,nr,MPI_FLOAT,MPI_SUM,0,
+                       cr->nc.comm_intra);
+            /* Sum the roots of the internal (intra) buffers */
+            MPI_Allreduce(MPI_IN_PLACE,r,nr,MPI_FLOAT,MPI_SUM,
+                          cr->nc.comm_inter);
+        }
+        else
+        {
+            /* This is here because of the silly MPI specification
+                that MPI_IN_PLACE should be put in sendbuf instead of recvbuf */
+            MPI_Reduce(r,NULL,nr,MPI_FLOAT,MPI_SUM,0,cr->nc.comm_intra);
+        }
+        MPI_Bcast(r,nr,MPI_FLOAT,0,cr->nc.comm_intra);
+    } 
+    else 
+    {
+        MPI_Allreduce(MPI_IN_PLACE,r,nr,MPI_FLOAT,MPI_SUM,cr->mpi_comm_mygroup);
+    }
+#else
+    int i;
+
+    if (nr > cr->mpb->fbuf_alloc) {
+        cr->mpb->fbuf_alloc = nr;
+        srenew(cr->mpb->fbuf,cr->mpb->fbuf_alloc);
+    }
+    if (cr->nc.bUse) {
+        /* Use two step summing */
+        MPI_Allreduce(r,cr->mpb->fbuf,nr,MPI_FLOAT,MPI_SUM,cr->nc.comm_intra);
+        if (cr->nc.rank_intra == 0) {
+            /* Sum with the buffers reversed */
+            MPI_Allreduce(cr->mpb->fbuf,r,nr,MPI_FLOAT,MPI_SUM, 
+                          cr->nc.comm_inter);
+        }
+        MPI_Bcast(r,nr,MPI_FLOAT,0,cr->nc.comm_intra);
+    } else {
+        MPI_Allreduce(r,cr->mpb->fbuf,nr,MPI_FLOAT,MPI_SUM,
+                      cr->mpi_comm_mygroup);
+        for(i=0; i<nr; i++)
+            r[i] = cr->mpb->fbuf[i];
+    }
+#endif
+#endif
+}
+
+void gmx_sumi(int nr,int r[],const t_commrec *cr)
+{
+#ifndef GMX_MPI
+    gmx_call("gmx_sumi");
+#else
+#if defined(MPI_IN_PLACE_EXISTS) || defined(GMX_THREADS)
+    if (cr->nc.bUse) {
+        /* Use two step summing */
+        if (cr->nc.rank_intra == 0) 
+        {
+            MPI_Reduce(MPI_IN_PLACE,r,nr,MPI_INT,MPI_SUM,0,cr->nc.comm_intra);
+            /* Sum with the buffers reversed */
+            MPI_Allreduce(MPI_IN_PLACE,r,nr,MPI_INT,MPI_SUM,cr->nc.comm_inter);
+        }
+        else
+        {
+            /* This is here because of the silly MPI specification
+                that MPI_IN_PLACE should be put in sendbuf instead of recvbuf */
+            MPI_Reduce(r,NULL,nr,MPI_INT,MPI_SUM,0,cr->nc.comm_intra);
+        }
+        MPI_Bcast(r,nr,MPI_INT,0,cr->nc.comm_intra);
+    } 
+    else 
+    {
+        MPI_Allreduce(MPI_IN_PLACE,r,nr,MPI_INT,MPI_SUM,cr->mpi_comm_mygroup);
+    }
+#else
+    int i;
+
+    if (nr > cr->mpb->ibuf_alloc) {
+        cr->mpb->ibuf_alloc = nr;
+        srenew(cr->mpb->ibuf,cr->mpb->ibuf_alloc);
+    }
+    if (cr->nc.bUse) {
+        /* Use two step summing */
+        MPI_Allreduce(r,cr->mpb->ibuf,nr,MPI_INT,MPI_SUM,cr->nc.comm_intra);
+        if (cr->nc.rank_intra == 0) {
+            /* Sum with the buffers reversed */
+            MPI_Allreduce(cr->mpb->ibuf,r,nr,MPI_INT,MPI_SUM,cr->nc.comm_inter);
+        }
+        MPI_Bcast(r,nr,MPI_INT,0,cr->nc.comm_intra);
+    } else {
+        MPI_Allreduce(r,cr->mpb->ibuf,nr,MPI_INT,MPI_SUM,cr->mpi_comm_mygroup);
+        for(i=0; i<nr; i++)
+            r[i] = cr->mpb->ibuf[i];
+    }
+#endif
+#endif
+}
+
+#ifdef GMX_MPI
+void gmx_sumd_comm(int nr,double r[],MPI_Comm mpi_comm)
+{
+#if defined(MPI_IN_PLACE_EXISTS) || defined(GMX_THREADS)
+    MPI_Allreduce(MPI_IN_PLACE,r,nr,MPI_DOUBLE,MPI_SUM,mpi_comm);
+#else
+    /* this function is only used in code that is not performance critical,
+       (during setup, when comm_rec is not the appropriate communication  
+       structure), so this isn't as bad as it looks. */
+    double *buf;
+    int i;
+
+    snew(buf, nr);
+    MPI_Allreduce(r,buf,nr,MPI_DOUBLE,MPI_SUM,mpi_comm);
+    for(i=0; i<nr; i++)
+        r[i] = buf[i];
+    sfree(buf);
+#endif
+}
+#endif
+
+#ifdef GMX_MPI
+void gmx_sumf_comm(int nr,float r[],MPI_Comm mpi_comm)
+{
+#if defined(MPI_IN_PLACE_EXISTS) || defined(GMX_THREADS)
+    MPI_Allreduce(MPI_IN_PLACE,r,nr,MPI_FLOAT,MPI_SUM,mpi_comm);
+#else
+    /* this function is only used in code that is not performance critical,
+       (during setup, when comm_rec is not the appropriate communication  
+       structure), so this isn't as bad as it looks. */
+    float *buf;
+    int i;
+
+    snew(buf, nr);
+    MPI_Allreduce(r,buf,nr,MPI_FLOAT,MPI_SUM,mpi_comm);
+    for(i=0; i<nr; i++)
+        r[i] = buf[i];
+    sfree(buf);
+#endif
+}
+#endif
+
+void gmx_sumd_sim(int nr,double r[],const gmx_multisim_t *ms)
+{
+#ifndef GMX_MPI
+  gmx_call("gmx_sumd");
+#else
+  gmx_sumd_comm(nr,r,ms->mpi_comm_masters);
+#endif
+}
+
+void gmx_sumf_sim(int nr,float r[],const gmx_multisim_t *ms)
+{
+#ifndef GMX_MPI
+  gmx_call("gmx_sumf");
+#else
+  gmx_sumf_comm(nr,r,ms->mpi_comm_masters);
+#endif
+}
+
+void gmx_sumi_sim(int nr,int r[], const gmx_multisim_t *ms)
+{
+#ifndef GMX_MPI
+    gmx_call("gmx_sumd");
+#else
+#if defined(MPI_IN_PLACE_EXISTS) || defined(GMX_THREADS)
+    MPI_Allreduce(MPI_IN_PLACE,r,nr,MPI_INT,MPI_SUM,ms->mpi_comm_masters);
+#else
+    /* this is thread-unsafe, but it will do for now: */
+    int i;
+
+    if (nr > ms->mpb->ibuf_alloc) {
+        ms->mpb->ibuf_alloc = nr;
+        srenew(ms->mpb->ibuf,ms->mpb->ibuf_alloc);
+    }
+    MPI_Allreduce(r,ms->mpb->ibuf,nr,MPI_INT,MPI_SUM,ms->mpi_comm_masters);
+    for(i=0; i<nr; i++)
+        r[i] = ms->mpb->ibuf[i];
+#endif
+#endif
+}
+
+void gmx_finalize(void)
+{
+#ifndef GMX_MPI
+  gmx_call("gmx_finalize");
+#else
+  int ret;
+
+  /* just as a check; we don't want to finalize twice */
+  int finalized;
+  MPI_Finalized(&finalized);
+  if (finalized)
+      return;
+
+  /* We sync the processes here to try to avoid problems
+   * with buggy MPI implementations that could cause
+   * unfinished processes to terminate.
+   */
+  MPI_Barrier(MPI_COMM_WORLD);
+
+  /*
+  if (DOMAINDECOMP(cr)) {
+    if (cr->npmenodes > 0 || cr->dd->bCartesian) 
+      MPI_Comm_free(&cr->mpi_comm_mygroup);
+    if (cr->dd->bCartesian)
+      MPI_Comm_free(&cr->mpi_comm_mysim);
+  }
+  */
+
+  /* Apparently certain mpich implementations cause problems
+   * with MPI_Finalize. In that case comment out MPI_Finalize.
+   */
+  if (debug)
+    fprintf(debug,"Will call MPI_Finalize now\n");
+
+  ret = MPI_Finalize();
+  if (debug)
+    fprintf(debug,"Return code from MPI_Finalize = %d\n",ret);
+#endif
+}
+
similarity index 100%
rename from src/gmxlib/nrnb.c
rename to src/gromacs/gmxlib/nrnb.c
similarity index 100%
rename from src/gmxlib/oenv.c
rename to src/gromacs/gmxlib/oenv.c
similarity index 100%
rename from src/gmxlib/pbc.c
rename to src/gromacs/gmxlib/pbc.c
diff --git a/src/gromacs/gmxlib/physics.c b/src/gromacs/gmxlib/physics.c
new file mode 100644 (file)
index 0000000..33ffdab
--- /dev/null
@@ -0,0 +1,127 @@
+/* -*- mode: c; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; c-file-style: "stroustrup"; -*-
+ * $Id: molprop_util.c,v 1.51 2009/06/01 06:13:18 spoel Exp $
+ * 
+ *                This source code is part of
+ * 
+ *                 G   R   O   M   A   C   S
+ * 
+ *          GROningen MAchine for Chemical Simulations
+ * 
+ *                        VERSION 4.0.99
+ * 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:
+ * Groningen Machine for Chemical Simulation
+ */
+#include <stdio.h>
+#include "string2.h"
+#include "physics.h"
+       
+double convert2gmx(double x,int unit)
+{
+    switch (unit) 
+    {
+    case eg2cAngstrom:
+        return x*A2NM;
+    case eg2cNm:
+        return x;
+    case eg2cBohr:
+        return x*BOHR2NM;
+    case eg2cKcal_Mole:
+        return x/CAL2JOULE;
+    case eg2cHartree:
+        return x*ONE_4PI_EPS0/BOHR2NM;
+    case eg2cHartree_e:
+        return x*ONE_4PI_EPS0/BOHR2NM;
+    case eg2cAngstrom3:
+        return x*A2NM*A2NM*A2NM;
+    case eg2cCoulomb:
+        return x/E_CHARGE;
+    case eg2cDebye:
+        return x*DEBYE2ENM;
+    case eg2cElectron:
+        return x;
+    case eg2cBuckingham:
+        return x*A2NM*DEBYE2ENM;
+    default:
+        fprintf(stderr,"Unknown unit %d, not converting.\n",unit);
+    }  
+    return x;
+}
+
+double gmx2convert(double x,int unit)
+{
+    switch (unit) 
+    {
+    case eg2cAngstrom:
+        return x/A2NM;
+    case eg2cNm:
+        return x;
+    case eg2cBohr:
+        return x/BOHR2NM;
+    case eg2cKcal_Mole:
+        return x*CAL2JOULE;
+    case eg2cHartree:
+        return x/(ONE_4PI_EPS0/BOHR2NM);
+    case eg2cHartree_e:
+        return x/(ONE_4PI_EPS0/BOHR2NM);
+    case eg2cAngstrom3:
+        return x/(A2NM*A2NM*A2NM);
+    case eg2cCoulomb:
+        return x*E_CHARGE;
+    case eg2cDebye:
+        return x/DEBYE2ENM;
+    case eg2cElectron:
+        return x;
+    case eg2cBuckingham:
+        return x/(A2NM*DEBYE2ENM);
+    default:
+        fprintf(stderr,"Unknown unit %d, not converting.\n",unit);
+    }  
+    return x;
+}
+
+/* This has to have the same order as the enums. */
+static const char *eg2c_names[eg2cNR] = {
+    "Angstrom", "Nm", "Bohr", "Kcal_Mole", 
+    "Hartree", "Hartree_e", "Angstrom3", "Coulomb",
+    "Debye", "Electron", "Buckingham" 
+};
+
+int string2unit(char *string)
+{
+    int i;
+    
+    for(i=0; (i<eg2cNR); i++)
+        if (strcasecmp(string,eg2c_names[i]) == 0)
+            return i;
+    return -1;
+}
+
+const char *unit2string(int unit)
+{
+    if ((unit >= 0) && (unit < eg2cNR))
+        return eg2c_names[unit];
+        
+    return NULL;
+}
diff --git a/src/gromacs/gmxlib/physics_test.c b/src/gromacs/gmxlib/physics_test.c
new file mode 100644 (file)
index 0000000..323c54e
--- /dev/null
@@ -0,0 +1,16 @@
+#include <stdio.h>
+#include "physics.h"
+
+int main(int argc,char *argv[])
+{
+  int i;
+  double x,y,z;
+  
+  x = 3.25; 
+  for(i=0; (i<eg2cNR); i++) {
+    y = gmx2convert(x,i);
+    z = convert2gmx(y,i);
+    printf("Converted %g [type %d] to %g and back to %g. Diff %g\n",
+          x,i,y,z,x-z);
+  }
+}
similarity index 100%
rename from src/gmxlib/rbin.c
rename to src/gromacs/gmxlib/rbin.c
diff --git a/src/gromacs/gmxlib/statistics/gmx_statistics.c b/src/gromacs/gmxlib/statistics/gmx_statistics.c
new file mode 100644 (file)
index 0000000..339c2df
--- /dev/null
@@ -0,0 +1,800 @@
+/* -*- 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
+ * 
+ *                        VERSION 3.2.0
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * 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.
+
+ * 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:
+ * Green Red Orange Magenta Azure Cyan Skyblue
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <math.h>
+#include "typedefs.h"
+#include "smalloc.h"
+#include "gmx_statistics.h"
+
+static double sqr(double x)
+{
+    return x*x;
+}
+
+static int gmx_nint(double x)
+{
+    return (int) (x+0.5);
+}
+
+typedef struct gmx_stats {
+    double aa,a,b,sigma_aa,sigma_a,sigma_b,aver,sigma_aver,error;
+    double rmsd,Rdata,Rfit,Rfitaa,chi2,chi2aa;
+    double *x,*y,*dx,*dy;
+    int    computed;
+    int    np,np_c,nalloc;
+} gmx_stats;
+
+gmx_stats_t gmx_stats_init()
+{
+    gmx_stats *stats;
+  
+    snew(stats,1);
+  
+    return (gmx_stats_t) stats;
+}
+
+int gmx_stats_get_npoints(gmx_stats_t gstats, int *N)
+{
+    gmx_stats *stats = (gmx_stats *) gstats;
+  
+    *N = stats->np;
+  
+    return estatsOK;
+}
+
+int gmx_stats_done(gmx_stats_t gstats)
+{
+    gmx_stats *stats = (gmx_stats *) gstats;
+  
+    sfree(stats->x);
+    stats->x = NULL;
+    sfree(stats->y);
+    stats->y = NULL;
+    sfree(stats->dx);
+    stats->dx = NULL;
+    sfree(stats->dy);
+    stats->dy = NULL;
+  
+    return estatsOK;
+}
+
+int gmx_stats_add_point(gmx_stats_t gstats,double x,double y,
+                        double dx,double dy)
+{
+    gmx_stats *stats = (gmx_stats *) gstats;
+    int i;
+  
+    if (stats->np+1 >= stats->nalloc) 
+    {
+        if (stats->nalloc == 0) 
+            stats->nalloc = 1024;
+        else
+            stats->nalloc *= 2;
+        srenew(stats->x,stats->nalloc);
+        srenew(stats->y,stats->nalloc);
+        srenew(stats->dx,stats->nalloc);
+        srenew(stats->dy,stats->nalloc);
+        for(i=stats->np; (i<stats->nalloc); i++) 
+        {
+            stats->x[i]  = 0;
+            stats->y[i]  = 0;
+            stats->dx[i] = 0;
+            stats->dy[i] = 0;
+        }
+    }
+    stats->x[stats->np]  = x;
+    stats->y[stats->np]  = y;
+    stats->dx[stats->np] = dx;
+    stats->dy[stats->np] = dy;
+    stats->np++;
+    stats->computed = 0;
+  
+    return estatsOK;
+}
+
+int gmx_stats_get_point(gmx_stats_t gstats,real *x,real *y,
+                        real *dx,real *dy,real level)
+{
+    gmx_stats *stats = (gmx_stats *) gstats;
+    int  ok,outlier;
+    real rmsd,r;
+    
+    if ((ok = gmx_stats_get_rmsd(gstats,&rmsd)) != estatsOK)
+    {
+        return ok;
+    }
+    outlier = 0;
+    while ((outlier == 0) && (stats->np_c < stats->np))
+    {
+        r = fabs(stats->x[stats->np_c] - stats->y[stats->np_c]);
+        outlier = (r > rmsd*level);
+        if (outlier)
+        {
+            if (NULL != x)  *x  = stats->x[stats->np_c];
+            if (NULL != y)  *y  = stats->y[stats->np_c];
+            if (NULL != dx) *dx = stats->dx[stats->np_c];
+            if (NULL != dy) *dy = stats->dy[stats->np_c];
+        }
+        stats->np_c++;
+        
+        if (outlier)    
+            return estatsOK;
+    }
+    
+    stats->np_c = 0;
+  
+    return estatsNO_POINTS;
+}
+
+int gmx_stats_add_points(gmx_stats_t gstats,int n,real *x,real *y,
+                         real *dx,real *dy)
+{
+    int i,ok;
+  
+    for(i=0; (i<n); i++) 
+    {
+        if ((ok = gmx_stats_add_point(gstats,x[i],y[i],
+                                      (NULL != dx) ? dx[i] : 0,
+                                      (NULL != dy) ? dy[i] : 0)) != estatsOK)
+        {
+            return ok;
+        }
+    }
+    return estatsOK;
+}
+
+static int gmx_stats_compute(gmx_stats *stats,int weight)
+{
+    double yy,yx,xx,sx,sy,dy,chi2,chi2aa,d2;
+    double ssxx,ssyy,ssxy;
+    double w,wtot,yx_nw,sy_nw,sx_nw,yy_nw,xx_nw,dx2,dy2;
+    int i,N;
+  
+    N = stats->np;
+    if (stats->computed == 0) 
+    {
+        if (N < 1)
+        {
+            return estatsNO_POINTS;
+        }
+      
+        xx = xx_nw = 0;
+        yy = yy_nw = 0;
+        yx = yx_nw = 0;
+        sx = sx_nw = 0;
+        sy = sy_nw = 0;
+        wtot = 0;
+        d2   = 0;
+        for(i=0; (i<N); i++) 
+        {
+            d2 += sqr(stats->x[i]-stats->y[i]);
+            if ((stats->dy[i]) && (weight == elsqWEIGHT_Y))
+            {
+                w = 1/sqr(stats->dy[i]);
+            }
+            else
+            {
+                w = 1;
+            }
+            
+            wtot  += w;
+            
+            xx    += w*sqr(stats->x[i]);
+            xx_nw += sqr(stats->x[i]);
+            
+            yy    += w*sqr(stats->y[i]);
+            yy_nw += sqr(stats->y[i]);
+            
+            yx    += w*stats->y[i]*stats->x[i];
+            yx_nw += stats->y[i]*stats->x[i];
+            
+            sx    += w*stats->x[i];
+            sx_nw += stats->x[i];
+            
+            sy    += w*stats->y[i];
+            sy_nw += stats->y[i];
+        }
+      
+        /* Compute average, sigma and error */
+        stats->aver       = sy_nw/N;
+        stats->sigma_aver = sqrt(yy_nw/N - sqr(sy_nw/N));
+        stats->error      = stats->sigma_aver/sqrt(N);
+
+        /* Compute RMSD between x and y */
+        stats->rmsd = sqrt(d2/N);
+       
+        /* Correlation coefficient for data */
+        yx_nw /= N;
+        xx_nw /= N;
+        yy_nw /= N;
+        sx_nw /= N;
+        sy_nw /= N;
+        ssxx = N*(xx_nw - sqr(sx_nw));
+        ssyy = N*(yy_nw - sqr(sy_nw));
+        ssxy = N*(yx_nw - (sx_nw*sy_nw));
+        stats->Rdata = sqrt(sqr(ssxy)/(ssxx*ssyy)); 
+        
+        /* Compute straight line through datapoints, either with intercept
+           zero (result in aa) or with intercept variable (results in a
+           and b) */
+        yx = yx/wtot;
+        xx = xx/wtot;
+        sx = sx/wtot;
+        sy = sy/wtot;
+  
+        stats->aa = (yx/xx);  
+        stats->a  = (yx-sx*sy)/(xx-sx*sx);
+        stats->b  = (sy)-(stats->a)*(sx);
+    
+        /* Compute chi2, deviation from a line y = ax+b. Also compute
+           chi2aa which returns the deviation from a line y = ax. */
+        chi2   = 0;
+        chi2aa = 0;
+        for(i=0; (i<N); i++) 
+        {
+            if (stats->dy[i] > 0)
+            {
+                dy = stats->dy[i];
+            }
+            else
+            {
+                dy = 1;
+            }
+            chi2aa += sqr((stats->y[i]-(stats->aa*stats->x[i]))/dy);
+            chi2   += sqr((stats->y[i]-(stats->a*stats->x[i]+stats->b))/dy);
+        }
+        if (N > 2) 
+        {
+            stats->chi2   = sqrt(chi2/(N-2));
+            stats->chi2aa = sqrt(chi2aa/(N-2));
+            
+            /* Look up equations! */
+            dx2 = (xx-sx*sx);
+            dy2 = (yy-sy*sy);
+            stats->sigma_a = sqrt(stats->chi2/((N-2)*dx2));
+            stats->sigma_b = stats->sigma_a*sqrt(xx);
+            stats->Rfit    = fabs(ssxy)/sqrt(ssxx*ssyy);
+                /*stats->a*sqrt(dx2/dy2);*/
+            stats->Rfitaa  = stats->aa*sqrt(dx2/dy2);  
+        }
+        else
+        {
+            stats->chi2    = 0;
+            stats->chi2aa  = 0;
+            stats->sigma_a = 0;
+            stats->sigma_b = 0;
+            stats->Rfit    = 0;
+            stats->Rfitaa  = 0;
+        }    
+
+        stats->computed = 1;
+    }
+  
+    return estatsOK;
+}
+
+int gmx_stats_get_ab(gmx_stats_t gstats,int weight,
+                     real *a,real *b,real *da,real *db,
+                     real *chi2,real *Rfit)
+{
+    gmx_stats *stats = (gmx_stats *) gstats;
+    int ok;
+  
+    if ((ok = gmx_stats_compute(stats,weight)) != estatsOK)
+        return ok;
+    if (NULL != a)
+    {
+        *a    = stats->a;
+    }
+    if (NULL != b)   
+    {
+        *b    = stats->b;
+    }
+    if (NULL != da)  
+    {
+        *da   = stats->sigma_a;
+    }
+    if (NULL != db)  
+    {
+        *db   = stats->sigma_b;
+    }
+    if (NULL != chi2) 
+    {
+        *chi2 = stats->chi2;
+    }
+    if (NULL != Rfit) 
+    {
+        *Rfit = stats->Rfit;
+    }
+    
+    return estatsOK;
+}
+
+int gmx_stats_get_a(gmx_stats_t gstats,int weight,real *a,real *da,
+                    real *chi2,real *Rfit)
+{
+    gmx_stats *stats = (gmx_stats *) gstats;
+    int ok;
+  
+    if ((ok = gmx_stats_compute(stats,weight)) != estatsOK)
+        return ok;
+    if (NULL != a)    *a    = stats->aa;
+    if (NULL != da)   *da   = stats->sigma_aa;
+    if (NULL != chi2) *chi2 = stats->chi2aa;
+    if (NULL != Rfit) *Rfit = stats->Rfitaa;
+  
+    return estatsOK;
+}
+
+int gmx_stats_get_average(gmx_stats_t gstats,real *aver)
+{
+    gmx_stats *stats = (gmx_stats *) gstats;
+    int ok;
+  
+    if ((ok = gmx_stats_compute(stats,elsqWEIGHT_NONE)) != estatsOK)
+    {
+        return ok;
+    }
+    
+    *aver = stats->aver;
+  
+    return estatsOK;
+}
+
+int gmx_stats_get_ase(gmx_stats_t gstats,real *aver,real *sigma,real *error)
+{
+    gmx_stats *stats = (gmx_stats *) gstats;
+    int ok;
+  
+    if ((ok = gmx_stats_compute(stats,elsqWEIGHT_NONE)) != estatsOK)
+    {
+        return ok;
+    }
+    
+    if (NULL != aver)
+    {
+        *aver  = stats->aver;
+    }
+    if (NULL != sigma) 
+    {
+        *sigma = stats->sigma_aver;
+    }
+    if (NULL != error) 
+    {
+        *error = stats->error;
+    }
+    
+    return estatsOK;
+}
+
+int gmx_stats_get_sigma(gmx_stats_t gstats,real *sigma)
+{
+    gmx_stats *stats = (gmx_stats *) gstats;
+    int ok;
+  
+    if ((ok = gmx_stats_compute(stats,elsqWEIGHT_NONE)) != estatsOK)
+        return ok;
+
+    *sigma = stats->sigma_aver;
+    
+    return estatsOK;
+}
+
+int gmx_stats_get_error(gmx_stats_t gstats,real *error)
+{
+    gmx_stats *stats = (gmx_stats *) gstats;
+    int ok;
+  
+    if ((ok = gmx_stats_compute(stats,elsqWEIGHT_NONE)) != estatsOK)
+        return ok;
+
+    *error = stats->error;
+  
+    return estatsOK;
+}
+
+int gmx_stats_get_corr_coeff(gmx_stats_t gstats,real *R)
+{
+    gmx_stats *stats = (gmx_stats *) gstats;
+    int ok;
+  
+    if ((ok = gmx_stats_compute(stats,elsqWEIGHT_NONE)) != estatsOK)
+        return ok;
+
+    *R = stats->Rdata;
+  
+    return estatsOK;
+}
+
+int gmx_stats_get_rmsd(gmx_stats_t gstats,real *rmsd)
+{
+    gmx_stats *stats = (gmx_stats *) gstats;
+    int ok;
+  
+    if ((ok = gmx_stats_compute(stats,elsqWEIGHT_NONE)) != estatsOK)
+    {
+        return ok;
+    }
+    
+    *rmsd = stats->rmsd;
+  
+    return estatsOK;
+}
+
+int gmx_stats_dump_xy(gmx_stats_t gstats,FILE *fp)
+{
+    gmx_stats *stats = (gmx_stats *) gstats;
+    int i,ok;
+  
+    for(i=0; (i<stats->np); i++) 
+    {
+        fprintf(fp,"%12g  %12g  %12g  %12g\n",stats->x[i],stats->y[i],
+                stats->dx[i],stats->dy[i]);
+    }
+    
+    return estatsOK;
+}
+
+int gmx_stats_remove_outliers(gmx_stats_t gstats,double level)
+{
+    gmx_stats *stats = (gmx_stats *) gstats;
+    int  i,iter=1,done=0,ok;
+    real rmsd,r;
+  
+    while ((stats->np >= 10) && !done) 
+    {
+        if ((ok = gmx_stats_get_rmsd(gstats,&rmsd)) != estatsOK)
+        {
+            return ok;
+        }
+        done = 1;
+        for(i=0; (i<stats->np); ) 
+        {
+            r = fabs(stats->x[i]-stats->y[i]);
+            if (r > level*rmsd) 
+            {
+                fprintf(stderr,"Removing outlier, iter = %d, rmsd = %g, x = %g, y = %g\n",
+                        iter,rmsd,stats->x[i],stats->y[i]);
+                if (i < stats->np-1) 
+                {
+                    stats->x[i]  = stats->x[stats->np-1];
+                    stats->y[i]  = stats->y[stats->np-1];
+                    stats->dx[i] = stats->dx[stats->np-1];
+                    stats->dy[i] = stats->dy[stats->np-1];
+                }
+                stats->np--;
+                done = 0;
+            }
+            else 
+            {
+                i++;
+            }
+        }
+        iter++;
+    }
+    
+    return estatsOK;
+}
+
+int gmx_stats_make_histogram(gmx_stats_t gstats,real binwidth,int *nb,
+                             int ehisto,int normalized,real **x,real **y)
+{
+    gmx_stats *stats = (gmx_stats *) gstats;
+    int    i,ok,index=0,nbins=*nb,*nindex;
+    double minx,maxx,maxy,miny,delta,dd,minh;
+  
+    if (((binwidth <= 0) && (nbins <= 0)) ||
+        ((binwidth > 0) && (nbins > 0)))
+    {
+        return estatsINVALID_INPUT;
+    }
+    if (stats->np <= 2)
+    {
+        return estatsNO_POINTS;
+    }
+    minx = maxx = stats->x[0];
+    miny = maxy = stats->y[0];
+    for(i=1; (i<stats->np); i++) 
+    {
+        miny = (stats->y[i] < miny) ? stats->y[i] : miny;
+        maxy = (stats->y[i] > maxy) ? stats->y[i] : maxy;
+        minx = (stats->x[i] < minx) ? stats->x[i] : minx;
+        maxx = (stats->x[i] > maxx) ? stats->x[i] : maxx;
+    }
+    if (ehisto == ehistoX)
+    {
+        delta = maxx-minx;
+        minh = minx;
+    }
+    else if (ehisto == ehistoY)
+    {
+        delta = maxy-miny;
+        minh = miny;
+    }
+    else
+        return estatsINVALID_INPUT;
+        
+    if (binwidth == 0)
+    {
+        binwidth = (delta)/nbins;
+    }
+    else
+    {
+        nbins = gmx_nint((delta)/binwidth + 0.5);
+    }
+    snew(*x,nbins);
+    snew(nindex,nbins);
+    for(i=0; (i<nbins); i++) 
+    {
+        (*x)[i] = minh + binwidth*(i+0.5);
+    }
+    if (normalized == 0)
+    {
+        dd = 1;
+    }
+    else
+    {
+        dd = 1.0/(binwidth*stats->np);
+    }
+    
+    snew(*y,nbins);
+    for(i=0; (i<stats->np); i++) 
+    {
+        if (ehisto == ehistoY)
+            index = (stats->y[i]-miny)/binwidth;
+               else if (ehisto == ehistoX)
+            index = (stats->x[i]-minx)/binwidth;
+               if (index<0)
+               {
+                       index = 0;
+               }
+               if (index>nbins-1)
+               {
+                       index = nbins-1;
+               }
+        (*y)[index] += dd;
+        nindex[index]++;
+    }
+    if (*nb == 0)
+        *nb = nbins;
+    for(i=0; (i<nbins); i++)
+        if (nindex[i] > 0)
+            (*y)[i] /= nindex[i];
+            
+    sfree(nindex);
+    
+    return estatsOK;
+}
+
+static const char *stats_error[estatsNR] = 
+{
+    "All well in STATS land",
+    "No points",
+    "Not enough memory",
+    "Invalid histogram input",
+    "Unknown error",
+    "Not implemented yet"
+};
+
+const char *gmx_stats_message(int estats)
+{
+    if ((estats >= 0) && (estats < estatsNR))
+    {
+        return stats_error[estats];
+    }
+    else
+    {
+        return stats_error[estatsERROR];
+    }
+}
+    
+/* Old convenience functions, should be merged with the core
+   statistics above. */
+int lsq_y_ax(int n, real x[], real y[], real *a)
+{
+    gmx_stats_t lsq = gmx_stats_init();
+    int  ok;
+    real da,chi2,Rfit;
+  
+    gmx_stats_add_points(lsq,n,x,y,0,0);
+    if ((ok = gmx_stats_get_a(lsq,elsqWEIGHT_NONE,a,&da,&chi2,&Rfit)) != estatsOK)
+    {
+        return ok;
+    }
+    
+    /*  int    i;
+        double xx,yx;
+  
+        yx=xx=0.0;
+        for (i=0; i<n; i++) {
+        yx+=y[i]*x[i];
+        xx+=x[i]*x[i];
+        }
+        *a=yx/xx;
+        */
+    return estatsOK;
+}
+
+static int low_lsq_y_ax_b(int n, real *xr, double *xd, real yr[],
+                          real *a, real *b,real *r,real *chi2)
+{
+    int    i,ok;
+    gmx_stats_t lsq;
+  
+    lsq = gmx_stats_init();
+    for(i=0; (i<n); i++) 
+    {
+        if ((ok = gmx_stats_add_point(lsq,(NULL != xd) ? xd[i] : xr[i],yr[i],0,0)) 
+            != estatsOK)
+        {
+            return ok;
+        }
+    }
+    if ((ok = gmx_stats_get_ab(lsq,elsqWEIGHT_NONE,a,b,NULL,NULL,chi2,r)) != estatsOK)
+    {
+        return ok;
+    }
+    
+    return estatsOK;
+    /*
+      double x,y,yx,xx,yy,sx,sy,chi2;
+
+      yx=xx=yy=sx=sy=0.0;
+      for (i=0; i<n; i++) {
+      if (xd != NULL) {
+      x = xd[i];
+      } else {
+      x = xr[i];
+      }
+      y =   yr[i];
+
+      yx += y*x;
+      xx += x*x;
+      yy += y*y;
+      sx += x;
+      sy += y;
+      }
+      *a = (n*yx-sy*sx)/(n*xx-sx*sx);
+      *b = (sy-(*a)*sx)/n;
+      *r = sqrt((xx-sx*sx)/(yy-sy*sy));
+  
+      chi2 = 0;
+      if (xd != NULL) {
+      for(i=0; i<n; i++)
+      chi2 += sqr(yr[i] - ((*a)*xd[i] + (*b)));
+      } else {
+      for(i=0; i<n; i++)
+      chi2 += sqr(yr[i] - ((*a)*xr[i] + (*b)));
+      }
+  
+      if (n > 2)
+      return sqrt(chi2/(n-2));
+      else
+      return 0;
+    */
+}
+
+int lsq_y_ax_b(int n, real x[], real y[], real *a, real *b,real *r,real *chi2)
+{
+    return low_lsq_y_ax_b(n,x,NULL,y,a,b,r,chi2);
+}
+
+int lsq_y_ax_b_xdouble(int n, double x[], real y[], real *a, real *b,
+                       real *r,real *chi2)
+{
+    return low_lsq_y_ax_b(n,NULL,x,y,a,b,r,chi2);
+}
+
+int lsq_y_ax_b_error(int n, real x[], real y[], real dy[],
+                     real *a, real *b, real *da, real *db,
+                     real *r,real *chi2)
+{
+    gmx_stats_t lsq;
+    int    i,ok;
+  
+    lsq = gmx_stats_init();
+    for(i=0; (i<n); i++)
+    {
+        if ((ok = gmx_stats_add_point(lsq,x[i],y[i],0,dy[i])) != estatsOK)
+        {
+            return ok;
+        }
+    }
+    if ((ok = gmx_stats_get_ab(lsq,elsqWEIGHT_Y,a,b,da,db,chi2,r)) != estatsOK)
+    {
+        return ok;
+    }
+    if ((ok = gmx_stats_done(lsq)) != estatsOK)
+    {
+        return ok;
+    }
+    sfree(lsq);
+
+    return estatsOK;
+    /*
+      double sxy,sxx,syy,sx,sy,w,s_2,dx2,dy2,mins;
+
+      sxy=sxx=syy=sx=sy=w=0.0;
+      mins = dy[0];
+      for(i=1; (i<n); i++)
+      mins = min(mins,dy[i]);
+      if (mins <= 0)
+      gmx_fatal(FARGS,"Zero or negative weigths in linear regression analysis");
+    
+      for (i=0; i<n; i++) {
+      s_2  = sqr(1.0/dy[i]);
+      sxx += s_2*sqr(x[i]);
+      sxy += s_2*y[i]*x[i];
+      syy += s_2*sqr(y[i]);
+      sx  += s_2*x[i];
+      sy  += s_2*y[i];
+      w   += s_2;
+      }
+      sxx = sxx/w;
+      sxy = sxy/w;
+      syy = syy/w;
+      sx  = sx/w;
+      sy  = sy/w;
+      dx2 = (sxx-sx*sx);
+      dy2 = (syy-sy*sy);
+      *a=(sxy-sy*sx)/dx2;
+      *b=(sy-(*a)*sx);
+  
+      *chi2=0;
+      for(i=0; i<n; i++)
+      *chi2+=sqr((y[i]-((*a)*x[i]+(*b)))/dy[i]);
+      *chi2 = *chi2/w;
+  
+      *da = sqrt(*chi2/((n-2)*dx2));
+      *db = *da*sqrt(sxx);
+      *r  = *a*sqrt(dx2/dy2);
+  
+      if (debug)
+      fprintf(debug,"sx = %g, sy = %g, sxy = %g, sxx = %g, w = %g\n"
+      "chi2 = %g, dx2 = %g\n",
+      sx,sy,sxy,sxx,w,*chi2,dx2);
+  
+      if (n > 2)
+      *chi2 = sqrt(*chi2/(n-2));
+      else
+      *chi2 = 0;
+      */
+}
+
+
diff --git a/src/gromacs/gmxlib/string2.c b/src/gromacs/gmxlib/string2.c
new file mode 100644 (file)
index 0000000..1e91cb8
--- /dev/null
@@ -0,0 +1,602 @@
+/*
+ * 
+ *                This source code is part of
+ * 
+ *                 G   R   O   M   A   C   S
+ * 
+ *          GROningen MAchine for Chemical Simulations
+ * 
+ *                        VERSION 3.2.0
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * 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.
+
+ * 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:
+ * GROningen Mixture of Alchemy and Childrens' Stories
+ */
+/* This file is completely threadsafe - keep it that way! */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef GMX_CRAY_XT3
+#undef HAVE_PWD_H
+#endif
+
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <time.h>
+
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+
+#ifdef HAVE_PWD_H
+#include <pwd.h>
+#endif
+#include <time.h>
+
+#include "typedefs.h"
+#include "smalloc.h"
+#include "gmx_fatal.h"
+#include "macros.h"
+#include "string2.h"
+#include "futil.h"
+
+int continuing(char *s)
+/* strip trailing spaces and if s ends with a CONTINUE remove that too.
+ * returns TRUE if s ends with a CONTINUE, FALSE otherwise.
+ */
+{
+  int sl;
+
+  rtrim(s);
+  sl = strlen(s);
+  if ((sl > 0) && (s[sl-1] == CONTINUE)) {
+    s[sl-1] = 0;
+    return TRUE;
+  }
+  else
+    return FALSE;
+}
+
+
+
+char *fgets2(char *line, int n, FILE *stream)
+/* This routine reads a string from stream of max length n
+ * and zero terminated, without newlines
+ * line should be long enough (>= n)
+ */
+{
+  char *c;
+  if (fgets(line,n,stream) == NULL) {
+    return NULL;
+  }
+  if ((c=strchr(line,'\n')) != NULL) {
+    *c = '\0';
+  } else {
+    /* A line not ending in a newline can only occur at the end of a file,
+     * or because of n being too small.
+     * Since both cases occur very infrequently, we can check for EOF.
+     */
+    if (!gmx_eof(stream)) {
+      gmx_fatal(FARGS,"An input file contains a line longer than %d characters, while the buffer passed to fgets2 has size %d. The line starts with: '%20.20s'",n,n,line);
+    }
+  }
+  if ((c=strchr(line,'\r')) != NULL) {
+    *c = '\0';
+  }
+
+  return line;
+}
+
+void strip_comment (char *line)
+{
+  char *c;
+
+  if (!line)
+    return;
+
+  /* search for a comment mark and replace it by a zero */
+  if ((c = strchr(line,COMMENTSIGN)) != NULL) 
+    (*c) = 0;
+}
+
+void upstring (char *str)
+{
+  int i;
+
+  for (i=0; (i < (int)strlen(str)); i++) 
+    str[i] = toupper(str[i]);
+}
+
+void ltrim (char *str)
+{
+  char *tr;
+  int i,c;
+
+  if (NULL == str)
+    return;
+
+  c = 0;
+  while (('\0' != str[c]) && isspace(str[c]))
+    c++;
+  if (c > 0) 
+    {
+      for(i=c; ('\0' != str[i]); i++)
+       str[i-c] = str[i];
+      str[i-c] = '\0';
+    }
+}
+
+void rtrim (char *str)
+{
+  int nul;
+
+  if (NULL == str)
+    return;
+
+  nul = strlen(str)-1;
+  while ((nul > 0) && ((str[nul] == ' ') || (str[nul] == '\t')) ) {
+    str[nul] = '\0';
+    nul--;
+  }
+}
+
+void trim (char *str)
+{
+  ltrim (str);
+  rtrim (str);
+}
+
+char *
+gmx_ctime_r(const time_t *clock,char *buf, int n)
+{
+    char tmpbuf[STRLEN];
+  
+#if ((defined WIN32 || defined _WIN32 || defined WIN64 || defined _WIN64) && !defined __CYGWIN__ && !defined __CYGWIN32__)
+    /* Windows */
+    ctime_s( tmpbuf, STRLEN, clock );
+#else
+    ctime_r(clock,tmpbuf);
+#endif
+    strncpy(buf,tmpbuf,n-1);
+    buf[n-1]='\0';
+    
+    return buf;
+}
+          
+void nice_header (FILE *out,const char *fn)
+{
+  const char *unk = "onbekend";
+  time_t clock;
+  char   *user=NULL;
+  int    gh;
+  uid_t  uid;
+  char   buf[256];
+  char   timebuf[STRLEN];
+#ifdef HAVE_PWD_H
+  struct passwd *pw;
+#endif
+
+  /* Print a nice header above the file */
+  time(&clock);
+  fprintf (out,"%c\n",COMMENTSIGN);
+  fprintf (out,"%c\tFile '%s' was generated\n",COMMENTSIGN,fn ? fn : unk);
+  
+#ifdef HAVE_PWD_H
+  uid = getuid();
+  pw  = getpwuid(uid);
+  gh  = gethostname(buf,255);
+  user= pw->pw_name;
+#else
+  uid = 0;
+  gh  = -1;
+#endif
+  
+  gmx_ctime_r(&clock,timebuf,STRLEN);
+  fprintf (out,"%c\tBy user: %s (%d)\n",COMMENTSIGN,
+          user ? user : unk,(int) uid);
+  fprintf(out,"%c\tOn host: %s\n",COMMENTSIGN,(gh == 0) ? buf : unk);
+
+  fprintf (out,"%c\tAt date: %s",COMMENTSIGN,timebuf);
+  fprintf (out,"%c\n",COMMENTSIGN);
+}
+
+int gmx_strcasecmp_min(const char *str1, const char *str2)
+{
+  char ch1,ch2;
+  
+  do
+    {
+      do
+       ch1=toupper(*(str1++));
+      while ((ch1=='-') || (ch1=='_'));
+      do 
+       ch2=toupper(*(str2++));
+      while ((ch2=='-') || (ch2=='_'));
+      if (ch1!=ch2) return (ch1-ch2);
+    }
+  while (ch1);
+  return 0; 
+}
+
+int gmx_strncasecmp_min(const char *str1, const char *str2, int n)
+{
+  char ch1,ch2;
+  char *stri1, *stri2;
+
+  stri1=(char *)str1;
+  stri2=(char *)str2;  
+  do
+    {
+      do
+       ch1=toupper(*(str1++));
+      while ((ch1=='-') || (ch1=='_'));
+      do 
+       ch2=toupper(*(str2++));
+      while ((ch2=='-') || (ch2=='_'));
+      if (ch1!=ch2) return (ch1-ch2);
+    }
+  while (ch1 && (str1-stri1<n) && (str2-stri2<n));
+  return 0; 
+}
+
+int gmx_strcasecmp(const char *str1, const char *str2)
+{
+  char ch1,ch2;
+  
+  do
+    {
+      ch1=toupper(*(str1++));
+      ch2=toupper(*(str2++));
+      if (ch1!=ch2) return (ch1-ch2);
+    }
+  while (ch1);
+  return 0; 
+}
+
+int gmx_strncasecmp(const char *str1, const char *str2, int n)
+{
+  char ch1,ch2;
+  if(n==0) 
+    return 0;
+
+  do
+    {
+      ch1=toupper(*(str1++));
+      ch2=toupper(*(str2++));
+      if (ch1!=ch2) return (ch1-ch2);
+      n--;
+    }
+  while (ch1 && n);
+  return 0; 
+}
+
+char *gmx_strdup(const char *src)
+{
+  char *dest;
+
+  snew(dest,strlen(src)+1);
+  strcpy(dest,src);
+  
+  return dest;
+}
+
+char *
+gmx_strndup(const char *src, int n)
+{
+    int   len;
+    char *dest;
+
+    len = strlen(src);
+    if (len > n) 
+    {
+        len = n;
+    }
+    snew(dest, len+1);
+    strncpy(dest, src, len);
+    dest[len] = 0;
+    return dest;
+}
+
+/*!
+ * \param[in] pattern  Pattern to match against.
+ * \param[in] str      String to match.
+ * \returns   0 on match, GMX_NO_WCMATCH if there is no match.
+ *
+ * Matches \p str against \p pattern, which may contain * and ? wildcards.
+ * All other characters are matched literally.
+ * Currently, it is not possible to match literal * or ?.
+ */
+int
+gmx_wcmatch(const char *pattern, const char *str)
+{
+    while (*pattern)
+    {
+        if (*pattern == '*')
+        {
+            /* Skip multiple wildcards in a sequence */
+            while (*pattern == '*' || *pattern == '?')
+            {
+                ++pattern;
+                /* For ?, we need to check that there are characters left
+                 * in str. */
+                if (*pattern == '?')
+                {
+                    if (*str == 0)
+                    {
+                        return GMX_NO_WCMATCH;
+                    }
+                    else
+                    {
+                        ++str;
+                    }
+                }
+            }
+            /* If the pattern ends after the star, we have a match */
+            if (*pattern == 0)
+            {
+                return 0;
+            }
+            /* Match the rest against each possible suffix of str */
+            while (*str)
+            {
+                /* Only do the recursive call if the first character
+                 * matches. We don't have to worry about wildcards here,
+                 * since we have processed them above. */
+                if (*pattern == *str)
+                {
+                    int rc;
+                    /* Match the suffix, and return if a match or an error */
+                    rc = gmx_wcmatch(pattern, str);
+                    if (rc != GMX_NO_WCMATCH)
+                    {
+                        return rc;
+                    }
+                }
+                ++str;
+            }
+            /* If no suffix of str matches, we don't have a match */
+            return GMX_NO_WCMATCH;
+        }
+        else if ((*pattern == '?' && *str != 0) || *pattern == *str)
+        {
+            ++str;
+        }
+        else
+        {
+            return GMX_NO_WCMATCH;
+        }
+        ++pattern;
+    }
+    /* When the pattern runs out, we have a match if the string has ended. */
+    return (*str == 0) ? 0 : GMX_NO_WCMATCH;
+}
+
+char *wrap_lines(const char *buf,int line_width, int indent,gmx_bool bIndentFirst)
+{
+  char *b2;
+  int i,i0,i2,j,b2len,lspace=0,l2space=0;
+  gmx_bool bFirst,bFitsOnLine;
+
+  /* characters are copied from buf to b2 with possible spaces changed
+   * into newlines and extra space added for indentation.
+   * i indexes buf (source buffer) and i2 indexes b2 (destination buffer)
+   * i0 points to the beginning of the current line (in buf, source)
+   * lspace and l2space point to the last space on the current line
+   * bFirst is set to prevent indentation of first line
+   * bFitsOnLine says if the first space occurred before line_width, if 
+   * that is not the case, we have a word longer than line_width which 
+   * will also not fit on the next line, so we might as well keep it on 
+   * the current line (where it also won't fit, but looks better)
+   */
+  
+  b2=NULL;
+  b2len=strlen(buf)+1+indent;
+  snew(b2,b2len);
+  i0=i2=0;
+  if (bIndentFirst)
+    for(i2=0; (i2<indent); i2++)
+      b2[i2] = ' ';
+  bFirst=TRUE;
+  do {
+    l2space = -1;
+    /* find the last space before end of line */
+    for(i=i0; ((i-i0 < line_width) || (l2space==-1)) && (buf[i]); i++) {
+      b2[i2++] = buf[i];
+      /* remember the position of a space */
+      if (buf[i] == ' ') {
+        lspace = i;
+       l2space = i2-1;
+      }
+      /* if we have a newline before the line is full, reset counters */
+      if (buf[i]=='\n' && buf[i+1]) { 
+       i0=i+1;
+       b2len+=indent;
+       srenew(b2, b2len);
+       /* add indentation after the newline */
+       for(j=0; (j<indent); j++)
+         b2[i2++]=' ';
+      }
+    }
+    /* If we are at the last newline, copy it */
+    if (buf[i]=='\n' && !buf[i+1]) {
+      b2[i2++] = buf[i++];
+    }
+    /* if we're not at the end of the string */
+    if (buf[i]) {
+      /* check if one word does not fit on the line */
+      bFitsOnLine = (i-i0 <= line_width);
+      /* reset line counters to just after the space */
+      i0 = lspace+1;
+      i2 = l2space+1;
+      /* if the words fit on the line, and we're beyond the indentation part */
+      if ( (bFitsOnLine) && (l2space >= indent) ) {
+       /* start a new line */
+       b2[l2space] = '\n';
+       /* and add indentation */
+       if (indent) {
+         if (bFirst) {
+           line_width-=indent;
+           bFirst=FALSE;
+         }
+         b2len+=indent;
+         srenew(b2, b2len);
+         for(j=0; (j<indent); j++)
+           b2[i2++]=' ';
+         /* no extra spaces after indent; */
+         while(buf[i0]==' ')
+           i0++;
+       }
+      }
+    }
+  } while (buf[i]);
+  b2[i2] = '\0';
+  
+  return b2;
+}
+
+char **split(char sep,const char *str)
+{
+  char **ptr = NULL;
+  int  n,nn,nptr = 0;
+  
+  if (str == NULL)
+    return NULL;
+  nn = strlen(str);
+  for(n=0; (n<nn); n++)
+    if (str[n] == sep)
+      nptr++;
+  snew(ptr,nptr+2);
+  nptr = 0;
+  while (*str != '\0') {
+    while ((*str != '\0') && (*str == sep))
+      str++;
+    if (*str != '\0') {
+      snew(ptr[nptr],1+strlen(str));
+      n = 0;
+      while ((*str != '\0') && (*str != sep)) {
+       ptr[nptr][n] = *str;
+       str++;
+       n++;
+      }
+      ptr[nptr][n] = '\0';
+      nptr++;
+    }
+  }
+  ptr[nptr] = NULL;
+  
+  return ptr;
+}
+
+
+gmx_large_int_t
+str_to_large_int_t(const char *str, char **endptr)
+{
+       int         sign = 1;
+       gmx_large_int_t  val  = 0;
+       char        ch;
+       const char  *p;
+       
+       p = str;
+       if(p==NULL)
+       {
+               *endptr=NULL;
+               return 0;
+       }
+       
+       /* Strip off initial white space */
+       while(isspace(*p))
+       {
+               p++;
+       }
+       /* Conform to ISO C99 - return original pointer if string does not contain a number */
+       if(*str=='\0')
+       {
+               *endptr=(char *)str;
+       }
+       
+       if(*p=='-')
+       {
+               p++;
+               sign *= -1;
+       }
+       
+       while( ((ch=*p) != '\0') && isdigit(ch) )
+       {
+               /* Important to add sign here, so we dont overflow in final multiplication */
+               ch = (ch-'0')*sign; 
+               val = val*10 + ch;
+               if(ch != val%10) 
+               {
+                       /* Some sort of overflow has occured, set endptr to original string */
+                       *endptr=(char *)str;
+                       errno = ERANGE;
+                       return(0);
+               }
+               p++;
+       }
+       
+       *endptr=(char *)p;
+       
+       return val;
+}
+
+char *gmx_strsep(char **stringp, const char *delim)
+{
+    char *ret;
+    int len=strlen(delim);
+    int i,j=0;
+    int found=0;
+
+    if (! *stringp)
+        return NULL;
+    ret=*stringp;
+    do
+    {
+        if ( (*stringp)[j] == '\0')
+        {
+            found=1;
+            *stringp=NULL;
+            break;
+        }
+        for (i=0;i<len;i++)
+        {
+            if ( (*stringp)[j]==delim[i])
+            {
+                (*stringp)[j]='\0';
+                *stringp=*stringp+j+1;
+                found=1;
+                break;
+            }
+        }
+        j++;
+    } while (!found);
+
+    return ret;
+}
+
diff --git a/src/gromacs/gmxlib/tpxio.c b/src/gromacs/gmxlib/tpxio.c
new file mode 100644 (file)
index 0000000..f220efb
--- /dev/null
@@ -0,0 +1,2477 @@
+/* -*- 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
+ * 
+ *                        VERSION 3.2.0
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * 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.
+
+ * 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:
+ * GROningen Mixture of Alchemy and Childrens' Stories
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/* This file is completely threadsafe - keep it that way! */
+#ifdef GMX_THREADS
+#include <thread_mpi.h>
+#endif
+
+
+#include <ctype.h>
+#include "sysstuff.h"
+#include "smalloc.h"
+#include "string2.h"
+#include "gmx_fatal.h"
+#include "macros.h"
+#include "names.h"
+#include "symtab.h"
+#include "futil.h"
+#include "filenm.h"
+#include "gmxfio.h"
+#include "topsort.h"
+#include "tpxio.h"
+#include "txtdump.h"
+#include "confio.h"
+#include "atomprop.h"
+#include "copyrite.h"
+#include "vec.h"
+#include "mtop_util.h"
+
+/* This number should be increased whenever the file format changes! */
+static const int tpx_version = 74;
+
+/* This number should only be increased when you edit the TOPOLOGY section
+ * of the tpx format. This way we can maintain forward compatibility too
+ * for all analysis tools and/or external programs that only need to
+ * know the atom/residue names, charges, and bond connectivity.
+ *  
+ * It first appeared in tpx version 26, when I also moved the inputrecord
+ * to the end of the tpx file, so we can just skip it if we only
+ * want the topology.
+ */
+static const int tpx_generation = 23;
+
+/* This number should be the most recent backwards incompatible version 
+ * I.e., if this number is 9, we cannot read tpx version 9 with this code.
+ */
+static const int tpx_incompatible_version = 9;
+
+
+
+/* Struct used to maintain tpx compatibility when function types are added */
+typedef struct {
+  int fvnr; /* file version number in which the function type first appeared */
+  int ftype; /* function type */
+} t_ftupd;
+
+/* 
+ *The entries should be ordered in:
+ * 1. ascending file version number
+ * 2. ascending function type number
+ */
+/*static const t_ftupd ftupd[] = {
+  { 20, F_CUBICBONDS        },
+  { 20, F_CONNBONDS         },
+  { 20, F_HARMONIC          },
+  { 20, F_EQM,              },
+  { 22, F_DISRESVIOL        },
+  { 22, F_ORIRES            },
+  { 22, F_ORIRESDEV         },
+  { 26, F_FOURDIHS          },
+  { 26, F_PIDIHS            },
+  { 26, F_DIHRES            },
+  { 26, F_DIHRESVIOL        },
+  { 30, F_CROSS_BOND_BONDS  },
+  { 30, F_CROSS_BOND_ANGLES },
+  { 30, F_UREY_BRADLEY      },
+  { 30, F_POLARIZATION      }
+  };*/
+  
+/* 
+ *The entries should be ordered in:
+ * 1. ascending function type number
+ * 2. ascending file version number
+ */
+static const t_ftupd ftupd[] = {
+  { 20, F_CUBICBONDS        },
+  { 20, F_CONNBONDS         },
+  { 20, F_HARMONIC          },
+  { 34, F_FENEBONDS         },
+  { 43, F_TABBONDS          },
+  { 43, F_TABBONDSNC        },
+  { 70, F_RESTRBONDS        },
+  { 30, F_CROSS_BOND_BONDS  },
+  { 30, F_CROSS_BOND_ANGLES },
+  { 30, F_UREY_BRADLEY      },
+  { 34, F_QUARTIC_ANGLES    },
+  { 43, F_TABANGLES         },
+  { 26, F_FOURDIHS          },
+  { 26, F_PIDIHS            },
+  { 43, F_TABDIHS           },
+  { 65, F_CMAP              },
+  { 60, F_GB12              },
+  { 61, F_GB13              },
+  { 61, F_GB14              }, 
+  { 72, F_GBPOL             },
+  { 72, F_NPSOLVATION       },
+  { 41, F_LJC14_Q           },
+  { 41, F_LJC_PAIRS_NB      },
+  { 32, F_BHAM_LR           },
+  { 32, F_RF_EXCL           },
+  { 32, F_COUL_RECIP        },
+  { 46, F_DPD               },
+  { 30, F_POLARIZATION      },
+  { 36, F_THOLE_POL         },
+  { 22, F_DISRESVIOL        },
+  { 22, F_ORIRES            },
+  { 22, F_ORIRESDEV         },
+  { 26, F_DIHRES            },
+  { 26, F_DIHRESVIOL        },
+  { 49, F_VSITE4FDN         },
+  { 50, F_VSITEN            },
+  { 46, F_COM_PULL          },
+  { 20, F_EQM               },
+  { 46, F_ECONSERVED        },
+  { 69, F_VTEMP             },
+  { 66, F_PDISPCORR         },
+  { 54, F_DHDL_CON          },
+};
+#define NFTUPD asize(ftupd)
+
+/* Needed for backward compatibility */
+#define MAXNODES 256
+
+static void _do_section(t_fileio *fio,int key,gmx_bool bRead,const char *src,
+                        int line)
+{
+  char buf[STRLEN];
+  gmx_bool bDbg;
+
+  if (gmx_fio_getftp(fio) == efTPA) {
+    if (!bRead) {
+      gmx_fio_write_string(fio,itemstr[key]);
+      bDbg       = gmx_fio_getdebug(fio);
+      gmx_fio_setdebug(fio,FALSE);
+      gmx_fio_write_string(fio,comment_str[key]);
+      gmx_fio_setdebug(fio,bDbg);
+    }
+    else {
+      if (gmx_fio_getdebug(fio))
+       fprintf(stderr,"Looking for section %s (%s, %d)",
+               itemstr[key],src,line);
+      
+      do {
+       gmx_fio_do_string(fio,buf);
+      } while ((gmx_strcasecmp(buf,itemstr[key]) != 0));
+      
+      if (gmx_strcasecmp(buf,itemstr[key]) != 0) 
+       gmx_fatal(FARGS,"\nCould not find section heading %s",itemstr[key]);
+      else if (gmx_fio_getdebug(fio))
+       fprintf(stderr," and found it\n");
+    }
+  }
+}
+
+#define do_section(fio,key,bRead) _do_section(fio,key,bRead,__FILE__,__LINE__)
+
+/**************************************************************
+ *
+ * Now the higer level routines that do io of the structures and arrays
+ *
+ **************************************************************/
+static void do_pullgrp(t_fileio *fio, t_pullgrp *pgrp, gmx_bool bRead, 
+                       int file_version)
+{
+  gmx_bool bDum=TRUE;
+  int  i;
+
+  gmx_fio_do_int(fio,pgrp->nat);
+  if (bRead)
+    snew(pgrp->ind,pgrp->nat);
+  bDum=gmx_fio_ndo_int(fio,pgrp->ind,pgrp->nat);
+  gmx_fio_do_int(fio,pgrp->nweight);
+  if (bRead)
+    snew(pgrp->weight,pgrp->nweight);
+  bDum=gmx_fio_ndo_real(fio,pgrp->weight,pgrp->nweight);
+  gmx_fio_do_int(fio,pgrp->pbcatom);
+  gmx_fio_do_rvec(fio,pgrp->vec);
+  gmx_fio_do_rvec(fio,pgrp->init);
+  gmx_fio_do_real(fio,pgrp->rate);
+  gmx_fio_do_real(fio,pgrp->k);
+  if (file_version >= 56) {
+    gmx_fio_do_real(fio,pgrp->kB);
+  } else {
+    pgrp->kB = pgrp->k;
+  }
+}
+
+static void do_pull(t_fileio *fio, t_pull *pull,gmx_bool bRead, int file_version)
+{
+  int g;
+
+  gmx_fio_do_int(fio,pull->ngrp);
+  gmx_fio_do_int(fio,pull->eGeom);
+  gmx_fio_do_ivec(fio,pull->dim);
+  gmx_fio_do_real(fio,pull->cyl_r1);
+  gmx_fio_do_real(fio,pull->cyl_r0);
+  gmx_fio_do_real(fio,pull->constr_tol);
+  gmx_fio_do_int(fio,pull->nstxout);
+  gmx_fio_do_int(fio,pull->nstfout);
+  if (bRead)
+    snew(pull->grp,pull->ngrp+1);
+  for(g=0; g<pull->ngrp+1; g++)
+    do_pullgrp(fio,&pull->grp[g],bRead,file_version);
+}
+
+
+static void do_rotgrp(t_fileio *fio, t_rotgrp *rotg,gmx_bool bRead, int file_version)
+{
+  gmx_bool bDum=TRUE;
+  int  i;
+
+  gmx_fio_do_int(fio,rotg->eType);
+  gmx_fio_do_int(fio,rotg->bMassW);
+  gmx_fio_do_int(fio,rotg->nat);
+  if (bRead)
+    snew(rotg->ind,rotg->nat);
+  gmx_fio_ndo_int(fio,rotg->ind,rotg->nat);
+  if (bRead)
+      snew(rotg->x_ref,rotg->nat);
+  gmx_fio_ndo_rvec(fio,rotg->x_ref,rotg->nat);
+  gmx_fio_do_rvec(fio,rotg->vec);
+  gmx_fio_do_rvec(fio,rotg->pivot);
+  gmx_fio_do_real(fio,rotg->rate);
+  gmx_fio_do_real(fio,rotg->k);
+  gmx_fio_do_real(fio,rotg->slab_dist);
+  gmx_fio_do_real(fio,rotg->min_gaussian);
+  gmx_fio_do_real(fio,rotg->eps);
+  gmx_fio_do_int(fio,rotg->eFittype);
+}
+
+static void do_rot(t_fileio *fio, t_rot *rot,gmx_bool bRead, int file_version)
+{
+  int g;
+
+  gmx_fio_do_int(fio,rot->ngrp);
+  gmx_fio_do_int(fio,rot->nstrout);
+  gmx_fio_do_int(fio,rot->nstsout);
+  if (bRead)
+    snew(rot->grp,rot->ngrp);
+  for(g=0; g<rot->ngrp; g++)
+    do_rotgrp(fio, &rot->grp[g],bRead,file_version);
+}
+
+
+static void do_inputrec(t_fileio *fio, t_inputrec *ir,gmx_bool bRead, 
+                        int file_version, real *fudgeQQ)
+{
+    int  i,j,k,*tmp,idum=0; 
+    gmx_bool bDum=TRUE;
+    real rdum,bd_temp;
+    rvec vdum;
+    gmx_bool bSimAnn;
+    real zerotemptime,finish_t,init_temp,finish_temp;
+    
+    if (file_version != tpx_version)
+    {
+        /* Give a warning about features that are not accessible */
+        fprintf(stderr,"Note: tpx file_version %d, software version %d\n",
+                file_version,tpx_version);
+    }
+
+    if (bRead)
+    {
+        init_inputrec(ir);
+    }
+
+    if (file_version == 0)
+    {
+        return;
+    }
+
+    /* Basic inputrec stuff */  
+    gmx_fio_do_int(fio,ir->eI); 
+    if (file_version >= 62) {
+      gmx_fio_do_gmx_large_int(fio, ir->nsteps);
+    } else {
+      gmx_fio_do_int(fio,idum);
+      ir->nsteps = idum;
+    }
+    if(file_version > 25) {
+      if (file_version >= 62) {
+       gmx_fio_do_gmx_large_int(fio, ir->init_step);
+      } else {
+       gmx_fio_do_int(fio,idum);
+       ir->init_step = idum;
+      }
+    }  else {
+      ir->init_step=0;
+    }
+
+       if(file_version >= 58)
+         gmx_fio_do_int(fio,ir->simulation_part);
+       else
+         ir->simulation_part=1;
+         
+    if (file_version >= 67) {
+      gmx_fio_do_int(fio,ir->nstcalcenergy);
+    } else {
+      ir->nstcalcenergy = 1;
+    }
+    if (file_version < 53) {
+      /* The pbc info has been moved out of do_inputrec,
+       * since we always want it, also without reading the inputrec.
+       */
+      gmx_fio_do_int(fio,ir->ePBC);
+      if ((file_version <= 15) && (ir->ePBC == 2))
+       ir->ePBC = epbcNONE;
+      if (file_version >= 45) {
+       gmx_fio_do_int(fio,ir->bPeriodicMols);
+      } else {
+       if (ir->ePBC == 2) {
+         ir->ePBC = epbcXYZ;
+         ir->bPeriodicMols = TRUE;
+       } else {
+       ir->bPeriodicMols = FALSE;
+       }
+      }
+    }
+    gmx_fio_do_int(fio,ir->ns_type);
+    gmx_fio_do_int(fio,ir->nstlist);
+    gmx_fio_do_int(fio,ir->ndelta);
+    if (file_version < 41) {
+      gmx_fio_do_int(fio,idum);
+      gmx_fio_do_int(fio,idum);
+    }
+    if (file_version >= 45)
+      gmx_fio_do_real(fio,ir->rtpi);
+    else
+      ir->rtpi = 0.05;
+    gmx_fio_do_int(fio,ir->nstcomm); 
+    if (file_version > 34)
+      gmx_fio_do_int(fio,ir->comm_mode);
+    else if (ir->nstcomm < 0) 
+      ir->comm_mode = ecmANGULAR;
+    else
+      ir->comm_mode = ecmLINEAR;
+    ir->nstcomm = abs(ir->nstcomm);
+    
+    if(file_version > 25)
+      gmx_fio_do_int(fio,ir->nstcheckpoint);
+    else
+      ir->nstcheckpoint=0;
+    
+    gmx_fio_do_int(fio,ir->nstcgsteep); 
+
+    if(file_version>=30)
+      gmx_fio_do_int(fio,ir->nbfgscorr); 
+    else if (bRead)
+      ir->nbfgscorr = 10;
+
+    gmx_fio_do_int(fio,ir->nstlog); 
+    gmx_fio_do_int(fio,ir->nstxout); 
+    gmx_fio_do_int(fio,ir->nstvout); 
+    gmx_fio_do_int(fio,ir->nstfout); 
+    gmx_fio_do_int(fio,ir->nstenergy); 
+    gmx_fio_do_int(fio,ir->nstxtcout); 
+    if (file_version >= 59) {
+      gmx_fio_do_double(fio,ir->init_t);
+      gmx_fio_do_double(fio,ir->delta_t);
+    } else {
+      gmx_fio_do_real(fio,rdum);
+      ir->init_t = rdum;
+      gmx_fio_do_real(fio,rdum);
+      ir->delta_t = rdum;
+    }
+    gmx_fio_do_real(fio,ir->xtcprec); 
+    if (file_version < 19) {
+      gmx_fio_do_int(fio,idum); 
+      gmx_fio_do_int(fio,idum);
+    }
+    if(file_version < 18)
+      gmx_fio_do_int(fio,idum); 
+    gmx_fio_do_real(fio,ir->rlist); 
+    if (file_version >= 67) {
+      gmx_fio_do_real(fio,ir->rlistlong);
+    }
+    gmx_fio_do_int(fio,ir->coulombtype); 
+    if (file_version < 32 && ir->coulombtype == eelRF)
+      ir->coulombtype = eelRF_NEC;      
+    gmx_fio_do_real(fio,ir->rcoulomb_switch); 
+    gmx_fio_do_real(fio,ir->rcoulomb); 
+    gmx_fio_do_int(fio,ir->vdwtype);
+    gmx_fio_do_real(fio,ir->rvdw_switch); 
+    gmx_fio_do_real(fio,ir->rvdw); 
+    if (file_version < 67) {
+      ir->rlistlong = max_cutoff(ir->rlist,max_cutoff(ir->rvdw,ir->rcoulomb));
+    }
+    gmx_fio_do_int(fio,ir->eDispCorr); 
+    gmx_fio_do_real(fio,ir->epsilon_r);
+    if (file_version >= 37) {
+      gmx_fio_do_real(fio,ir->epsilon_rf);
+    } else {
+      if (EEL_RF(ir->coulombtype)) {
+       ir->epsilon_rf = ir->epsilon_r;
+       ir->epsilon_r  = 1.0;
+      } else {
+       ir->epsilon_rf = 1.0;
+      }
+    }
+    if (file_version >= 29)
+      gmx_fio_do_real(fio,ir->tabext);
+    else
+      ir->tabext=1.0;
+    if(file_version > 25) {
+      gmx_fio_do_int(fio,ir->gb_algorithm);
+      gmx_fio_do_int(fio,ir->nstgbradii);
+      gmx_fio_do_real(fio,ir->rgbradii);
+      gmx_fio_do_real(fio,ir->gb_saltconc);
+      gmx_fio_do_int(fio,ir->implicit_solvent);
+    } else {
+      ir->gb_algorithm=egbSTILL;
+      ir->nstgbradii=1;
+      ir->rgbradii=1.0;
+      ir->gb_saltconc=0;
+      ir->implicit_solvent=eisNO;
+    }
+       if(file_version>=55)
+       {
+               gmx_fio_do_real(fio,ir->gb_epsilon_solvent);
+               gmx_fio_do_real(fio,ir->gb_obc_alpha);
+               gmx_fio_do_real(fio,ir->gb_obc_beta);
+               gmx_fio_do_real(fio,ir->gb_obc_gamma);
+               if(file_version>=60)
+               {
+                       gmx_fio_do_real(fio,ir->gb_dielectric_offset);
+                       gmx_fio_do_int(fio,ir->sa_algorithm);
+               }
+               else
+               {
+                       ir->gb_dielectric_offset = 0.009;
+                       ir->sa_algorithm = esaAPPROX;
+               }
+               gmx_fio_do_real(fio,ir->sa_surface_tension);
+
+    /* Override sa_surface_tension if it is not changed in the mpd-file */
+    if(ir->sa_surface_tension<0)
+    {
+      if(ir->gb_algorithm==egbSTILL)
+      {
+        ir->sa_surface_tension = 0.0049 * 100 * CAL2JOULE;
+      }
+      else if(ir->gb_algorithm==egbHCT || ir->gb_algorithm==egbOBC)
+      {
+        ir->sa_surface_tension = 0.0054 * 100 * CAL2JOULE;
+      }
+    }
+    
+       }
+       else
+       {
+               /* Better use sensible values than insane (0.0) ones... */
+               ir->gb_epsilon_solvent = 80;
+               ir->gb_obc_alpha       = 1.0;
+               ir->gb_obc_beta        = 0.8;
+               ir->gb_obc_gamma       = 4.85;
+               ir->sa_surface_tension = 2.092;
+       }
+
+         
+    gmx_fio_do_int(fio,ir->nkx); 
+    gmx_fio_do_int(fio,ir->nky); 
+    gmx_fio_do_int(fio,ir->nkz);
+    gmx_fio_do_int(fio,ir->pme_order);
+    gmx_fio_do_real(fio,ir->ewald_rtol);
+
+    if (file_version >=24) 
+      gmx_fio_do_int(fio,ir->ewald_geometry);
+    else
+      ir->ewald_geometry=eewg3D;
+
+    if (file_version <=17) {
+      ir->epsilon_surface=0;
+      if (file_version==17)
+       gmx_fio_do_int(fio,idum);
+    } 
+    else
+      gmx_fio_do_real(fio,ir->epsilon_surface);
+    
+    gmx_fio_do_gmx_bool(fio,ir->bOptFFT);
+
+    gmx_fio_do_gmx_bool(fio,ir->bContinuation); 
+    gmx_fio_do_int(fio,ir->etc);
+    /* before version 18, ir->etc was a gmx_bool (ir->btc),
+     * but the values 0 and 1 still mean no and
+     * berendsen temperature coupling, respectively.
+     */
+    if (file_version >= 71)
+    {
+        gmx_fio_do_int(fio,ir->nsttcouple);
+    }
+    else
+    {
+        ir->nsttcouple = ir->nstcalcenergy;
+    }
+    if (file_version <= 15)
+    {
+        gmx_fio_do_int(fio,idum);
+    }
+    if (file_version <=17)
+    {
+        gmx_fio_do_int(fio,ir->epct); 
+        if (file_version <= 15)
+        {
+            if (ir->epct == 5)
+            {
+                ir->epct = epctSURFACETENSION;
+            }
+            gmx_fio_do_int(fio,idum);
+        }
+        ir->epct -= 1;
+        /* we have removed the NO alternative at the beginning */
+        if(ir->epct==-1)
+        {
+            ir->epc=epcNO;
+            ir->epct=epctISOTROPIC;
+        } 
+        else
+        {
+            ir->epc=epcBERENDSEN;
+        }
+    } 
+    else
+    {
+        gmx_fio_do_int(fio,ir->epc);
+        gmx_fio_do_int(fio,ir->epct);
+    }
+    if (file_version >= 71)
+    {
+        gmx_fio_do_int(fio,ir->nstpcouple);
+    }
+    else
+    {
+        ir->nstpcouple = ir->nstcalcenergy;
+    }
+    gmx_fio_do_real(fio,ir->tau_p); 
+    if (file_version <= 15) {
+      gmx_fio_do_rvec(fio,vdum);
+      clear_mat(ir->ref_p);
+      for(i=0; i<DIM; i++)
+       ir->ref_p[i][i] = vdum[i];
+    } else {
+      gmx_fio_do_rvec(fio,ir->ref_p[XX]);
+      gmx_fio_do_rvec(fio,ir->ref_p[YY]);
+      gmx_fio_do_rvec(fio,ir->ref_p[ZZ]);
+    }
+    if (file_version <= 15) {
+      gmx_fio_do_rvec(fio,vdum);
+      clear_mat(ir->compress);
+      for(i=0; i<DIM; i++)
+       ir->compress[i][i] = vdum[i];
+    } 
+    else {
+      gmx_fio_do_rvec(fio,ir->compress[XX]);
+      gmx_fio_do_rvec(fio,ir->compress[YY]);
+      gmx_fio_do_rvec(fio,ir->compress[ZZ]);
+    }
+    if (file_version >= 47) {
+      gmx_fio_do_int(fio,ir->refcoord_scaling);
+      gmx_fio_do_rvec(fio,ir->posres_com);
+      gmx_fio_do_rvec(fio,ir->posres_comB);
+    } else {
+      ir->refcoord_scaling = erscNO;
+      clear_rvec(ir->posres_com);
+      clear_rvec(ir->posres_comB);
+    }
+    if(file_version > 25)
+      gmx_fio_do_int(fio,ir->andersen_seed);
+    else
+      ir->andersen_seed=0;
+    
+    if(file_version < 26) {
+      gmx_fio_do_gmx_bool(fio,bSimAnn); 
+      gmx_fio_do_real(fio,zerotemptime);
+    }
+    
+    if (file_version < 37)
+      gmx_fio_do_real(fio,rdum); 
+
+    gmx_fio_do_real(fio,ir->shake_tol);
+    if (file_version < 54)
+      gmx_fio_do_real(fio,*fudgeQQ);
+    gmx_fio_do_int(fio,ir->efep);
+    if (file_version <= 14 && ir->efep > efepNO)
+      ir->efep = efepYES;
+    if (file_version >= 59) {
+      gmx_fio_do_double(fio, ir->init_lambda); 
+      gmx_fio_do_double(fio, ir->delta_lambda);
+    } else {
+      gmx_fio_do_real(fio,rdum);
+      ir->init_lambda = rdum;
+      gmx_fio_do_real(fio,rdum);
+      ir->delta_lambda = rdum;
+    }
+    if (file_version >= 64) {
+      gmx_fio_do_int(fio,ir->n_flambda);
+      if (bRead) {
+       snew(ir->flambda,ir->n_flambda);
+      }
+      bDum=gmx_fio_ndo_double(fio,ir->flambda,ir->n_flambda);
+    } else {
+      ir->n_flambda = 0;
+      ir->flambda   = NULL;
+    }
+    if (file_version >= 13)
+      gmx_fio_do_real(fio,ir->sc_alpha);
+    else
+      ir->sc_alpha = 0;
+    if (file_version >= 38)
+      gmx_fio_do_int(fio,ir->sc_power);
+    else
+      ir->sc_power = 2;
+    if (file_version >= 15)
+      gmx_fio_do_real(fio,ir->sc_sigma);
+    else
+      ir->sc_sigma = 0.3;
+    if (bRead)
+    {
+        if (file_version >= 71)
+        {
+            ir->sc_sigma_min = ir->sc_sigma;
+        }
+        else
+        {
+            ir->sc_sigma_min = 0;
+        }
+    }
+    if (file_version >= 64) {
+      gmx_fio_do_int(fio,ir->nstdhdl);
+    } else {
+      ir->nstdhdl = 1;
+    }
+
+    if (file_version >= 73)
+    {
+        gmx_fio_do_int(fio, ir->separate_dhdl_file);
+        gmx_fio_do_int(fio, ir->dhdl_derivatives);
+    }
+    else
+    {
+        ir->separate_dhdl_file = sepdhdlfileYES;
+        ir->dhdl_derivatives = dhdlderivativesYES;
+    }
+
+    if (file_version >= 71)
+    {
+        gmx_fio_do_int(fio,ir->dh_hist_size);
+        gmx_fio_do_double(fio,ir->dh_hist_spacing);
+    }
+    else
+    {
+        ir->dh_hist_size    = 0;
+        ir->dh_hist_spacing = 0.1;
+    }
+    if (file_version >= 57) {
+      gmx_fio_do_int(fio,ir->eDisre); 
+    }
+    gmx_fio_do_int(fio,ir->eDisreWeighting); 
+    if (file_version < 22) {
+      if (ir->eDisreWeighting == 0)
+       ir->eDisreWeighting = edrwEqual;
+      else
+       ir->eDisreWeighting = edrwConservative;
+    }
+    gmx_fio_do_gmx_bool(fio,ir->bDisreMixed); 
+    gmx_fio_do_real(fio,ir->dr_fc); 
+    gmx_fio_do_real(fio,ir->dr_tau); 
+    gmx_fio_do_int(fio,ir->nstdisreout);
+    if (file_version >= 22) {
+      gmx_fio_do_real(fio,ir->orires_fc);
+      gmx_fio_do_real(fio,ir->orires_tau);
+      gmx_fio_do_int(fio,ir->nstorireout);
+    } else {
+      ir->orires_fc = 0;
+      ir->orires_tau = 0;
+      ir->nstorireout = 0;
+    }
+    if(file_version >= 26) {
+      gmx_fio_do_real(fio,ir->dihre_fc);
+      if (file_version < 56) {
+       gmx_fio_do_real(fio,rdum);
+       gmx_fio_do_int(fio,idum);
+      }
+    } else {
+      ir->dihre_fc=0;
+    }
+
+    gmx_fio_do_real(fio,ir->em_stepsize); 
+    gmx_fio_do_real(fio,ir->em_tol); 
+    if (file_version >= 22) 
+      gmx_fio_do_gmx_bool(fio,ir->bShakeSOR);
+    else if (bRead)
+      ir->bShakeSOR = TRUE;
+    if (file_version >= 11)
+      gmx_fio_do_int(fio,ir->niter);
+    else if (bRead) {
+      ir->niter = 25;
+      fprintf(stderr,"Note: niter not in run input file, setting it to %d\n",
+             ir->niter);
+    }
+    if (file_version >= 21)
+      gmx_fio_do_real(fio,ir->fc_stepsize);
+    else
+      ir->fc_stepsize = 0;
+    gmx_fio_do_int(fio,ir->eConstrAlg);
+    gmx_fio_do_int(fio,ir->nProjOrder);
+    gmx_fio_do_real(fio,ir->LincsWarnAngle);
+    if (file_version <= 14)
+      gmx_fio_do_int(fio,idum);
+    if (file_version >=26)
+      gmx_fio_do_int(fio,ir->nLincsIter);
+    else if (bRead) {
+      ir->nLincsIter = 1;
+      fprintf(stderr,"Note: nLincsIter not in run input file, setting it to %d\n",
+             ir->nLincsIter);
+    }
+    if (file_version < 33)
+      gmx_fio_do_real(fio,bd_temp);
+    gmx_fio_do_real(fio,ir->bd_fric);
+    gmx_fio_do_int(fio,ir->ld_seed);
+    if (file_version >= 33) {
+      for(i=0; i<DIM; i++)
+       gmx_fio_do_rvec(fio,ir->deform[i]);
+    } else {
+      for(i=0; i<DIM; i++)
+       clear_rvec(ir->deform[i]);
+    }
+    if (file_version >= 14)
+      gmx_fio_do_real(fio,ir->cos_accel);
+    else if (bRead)
+      ir->cos_accel = 0;
+    gmx_fio_do_int(fio,ir->userint1); 
+    gmx_fio_do_int(fio,ir->userint2); 
+    gmx_fio_do_int(fio,ir->userint3); 
+    gmx_fio_do_int(fio,ir->userint4); 
+    gmx_fio_do_real(fio,ir->userreal1); 
+    gmx_fio_do_real(fio,ir->userreal2); 
+    gmx_fio_do_real(fio,ir->userreal3); 
+    gmx_fio_do_real(fio,ir->userreal4); 
+    
+    /* pull stuff */
+    if (file_version >= 48) {
+      gmx_fio_do_int(fio,ir->ePull);
+      if (ir->ePull != epullNO) {
+       if (bRead)
+         snew(ir->pull,1);
+       do_pull(fio, ir->pull,bRead,file_version);
+      }
+    } else {
+      ir->ePull = epullNO;
+    }
+    
+    /* Enforced rotation */
+    if (file_version >= 74) {
+        gmx_fio_do_int(fio,ir->bRot);
+        if (ir->bRot == TRUE) {
+            if (bRead)
+                snew(ir->rot,1);
+            do_rot(fio, ir->rot,bRead,file_version);
+        }
+    } else {
+        ir->bRot = FALSE;
+    }
+    
+    /* grpopts stuff */
+    gmx_fio_do_int(fio,ir->opts.ngtc); 
+    if (file_version >= 69) {
+      gmx_fio_do_int(fio,ir->opts.nhchainlength);
+    } else {
+      ir->opts.nhchainlength = 1;
+    }
+    gmx_fio_do_int(fio,ir->opts.ngacc); 
+    gmx_fio_do_int(fio,ir->opts.ngfrz); 
+    gmx_fio_do_int(fio,ir->opts.ngener);
+    
+    if (bRead) {
+      snew(ir->opts.nrdf,   ir->opts.ngtc); 
+      snew(ir->opts.ref_t,  ir->opts.ngtc); 
+      snew(ir->opts.annealing, ir->opts.ngtc); 
+      snew(ir->opts.anneal_npoints, ir->opts.ngtc); 
+      snew(ir->opts.anneal_time, ir->opts.ngtc); 
+      snew(ir->opts.anneal_temp, ir->opts.ngtc); 
+      snew(ir->opts.tau_t,  ir->opts.ngtc); 
+      snew(ir->opts.nFreeze,ir->opts.ngfrz); 
+      snew(ir->opts.acc,    ir->opts.ngacc); 
+      snew(ir->opts.egp_flags,ir->opts.ngener*ir->opts.ngener);
+    } 
+    if (ir->opts.ngtc > 0) {
+      if (bRead && file_version<13) {
+       snew(tmp,ir->opts.ngtc);
+       bDum=gmx_fio_ndo_int(fio,tmp, ir->opts.ngtc);
+       for(i=0; i<ir->opts.ngtc; i++)
+         ir->opts.nrdf[i] = tmp[i];
+       sfree(tmp);
+      } else {
+       bDum=gmx_fio_ndo_real(fio,ir->opts.nrdf, ir->opts.ngtc);
+      }
+      bDum=gmx_fio_ndo_real(fio,ir->opts.ref_t,ir->opts.ngtc); 
+      bDum=gmx_fio_ndo_real(fio,ir->opts.tau_t,ir->opts.ngtc); 
+      if (file_version<33 && ir->eI==eiBD) {
+       for(i=0; i<ir->opts.ngtc; i++)
+         ir->opts.tau_t[i] = bd_temp;
+      }
+    }
+    if (ir->opts.ngfrz > 0) 
+      bDum=gmx_fio_ndo_ivec(fio,ir->opts.nFreeze,ir->opts.ngfrz);
+    if (ir->opts.ngacc > 0) 
+      gmx_fio_ndo_rvec(fio,ir->opts.acc,ir->opts.ngacc); 
+    if (file_version >= 12)
+      bDum=gmx_fio_ndo_int(fio,ir->opts.egp_flags,
+                           ir->opts.ngener*ir->opts.ngener);
+
+    if(bRead && file_version < 26) {
+      for(i=0;i<ir->opts.ngtc;i++) {
+       if(bSimAnn) {
+         ir->opts.annealing[i] = eannSINGLE;
+         ir->opts.anneal_npoints[i] = 2;
+         snew(ir->opts.anneal_time[i],2);
+         snew(ir->opts.anneal_temp[i],2);
+         /* calculate the starting/ending temperatures from reft, zerotemptime, and nsteps */
+         finish_t = ir->init_t + ir->nsteps * ir->delta_t;
+         init_temp = ir->opts.ref_t[i]*(1-ir->init_t/zerotemptime);
+         finish_temp = ir->opts.ref_t[i]*(1-finish_t/zerotemptime);
+         ir->opts.anneal_time[i][0] = ir->init_t;
+         ir->opts.anneal_time[i][1] = finish_t;
+         ir->opts.anneal_temp[i][0] = init_temp;
+         ir->opts.anneal_temp[i][1] = finish_temp;
+       } else {
+         ir->opts.annealing[i] = eannNO;
+         ir->opts.anneal_npoints[i] = 0;
+       }
+      }
+    } else {
+      /* file version 26 or later */
+      /* First read the lists with annealing and npoints for each group */
+      bDum=gmx_fio_ndo_int(fio,ir->opts.annealing,ir->opts.ngtc);
+      bDum=gmx_fio_ndo_int(fio,ir->opts.anneal_npoints,ir->opts.ngtc);
+      for(j=0;j<(ir->opts.ngtc);j++) {
+       k=ir->opts.anneal_npoints[j];
+       if(bRead) {
+         snew(ir->opts.anneal_time[j],k);
+         snew(ir->opts.anneal_temp[j],k);
+       }
+       bDum=gmx_fio_ndo_real(fio,ir->opts.anneal_time[j],k);
+       bDum=gmx_fio_ndo_real(fio,ir->opts.anneal_temp[j],k);
+      }
+    }
+    /* Walls */
+    if (file_version >= 45) {
+      gmx_fio_do_int(fio,ir->nwall);
+      gmx_fio_do_int(fio,ir->wall_type);
+      if (file_version >= 50)
+       gmx_fio_do_real(fio,ir->wall_r_linpot);
+      else
+       ir->wall_r_linpot = -1;
+      gmx_fio_do_int(fio,ir->wall_atomtype[0]);
+      gmx_fio_do_int(fio,ir->wall_atomtype[1]);
+      gmx_fio_do_real(fio,ir->wall_density[0]);
+      gmx_fio_do_real(fio,ir->wall_density[1]);
+      gmx_fio_do_real(fio,ir->wall_ewald_zfac);
+    } else {
+      ir->nwall = 0;
+      ir->wall_type = 0;
+      ir->wall_atomtype[0] = -1;
+      ir->wall_atomtype[1] = -1;
+      ir->wall_density[0] = 0;
+      ir->wall_density[1] = 0;
+      ir->wall_ewald_zfac = 3;
+    }
+    /* Cosine stuff for electric fields */
+    for(j=0; (j<DIM); j++) {
+      gmx_fio_do_int(fio,ir->ex[j].n);
+      gmx_fio_do_int(fio,ir->et[j].n);
+      if (bRead) {
+       snew(ir->ex[j].a,  ir->ex[j].n);
+       snew(ir->ex[j].phi,ir->ex[j].n);
+       snew(ir->et[j].a,  ir->et[j].n);
+       snew(ir->et[j].phi,ir->et[j].n);
+      }
+      bDum=gmx_fio_ndo_real(fio,ir->ex[j].a,  ir->ex[j].n);
+      bDum=gmx_fio_ndo_real(fio,ir->ex[j].phi,ir->ex[j].n);
+      bDum=gmx_fio_ndo_real(fio,ir->et[j].a,  ir->et[j].n);
+      bDum=gmx_fio_ndo_real(fio,ir->et[j].phi,ir->et[j].n);
+    }
+    
+    /* QMMM stuff */
+    if(file_version>=39){
+      gmx_fio_do_gmx_bool(fio,ir->bQMMM);
+      gmx_fio_do_int(fio,ir->QMMMscheme);
+      gmx_fio_do_real(fio,ir->scalefactor);
+      gmx_fio_do_int(fio,ir->opts.ngQM);
+      if (bRead) {
+        snew(ir->opts.QMmethod,    ir->opts.ngQM);
+        snew(ir->opts.QMbasis,     ir->opts.ngQM);
+        snew(ir->opts.QMcharge,    ir->opts.ngQM);
+        snew(ir->opts.QMmult,      ir->opts.ngQM);
+        snew(ir->opts.bSH,         ir->opts.ngQM);
+        snew(ir->opts.CASorbitals, ir->opts.ngQM);
+        snew(ir->opts.CASelectrons,ir->opts.ngQM);
+        snew(ir->opts.SAon,        ir->opts.ngQM);
+        snew(ir->opts.SAoff,       ir->opts.ngQM);
+        snew(ir->opts.SAsteps,     ir->opts.ngQM);
+        snew(ir->opts.bOPT,        ir->opts.ngQM);
+        snew(ir->opts.bTS,         ir->opts.ngQM);
+      }
+      if (ir->opts.ngQM > 0) {
+        bDum=gmx_fio_ndo_int(fio,ir->opts.QMmethod,ir->opts.ngQM);
+        bDum=gmx_fio_ndo_int(fio,ir->opts.QMbasis,ir->opts.ngQM);
+        bDum=gmx_fio_ndo_int(fio,ir->opts.QMcharge,ir->opts.ngQM);
+        bDum=gmx_fio_ndo_int(fio,ir->opts.QMmult,ir->opts.ngQM);
+        bDum=gmx_fio_ndo_gmx_bool(fio,ir->opts.bSH,ir->opts.ngQM);
+        bDum=gmx_fio_ndo_int(fio,ir->opts.CASorbitals,ir->opts.ngQM);
+        bDum=gmx_fio_ndo_int(fio,ir->opts.CASelectrons,ir->opts.ngQM);
+        bDum=gmx_fio_ndo_real(fio,ir->opts.SAon,ir->opts.ngQM);
+        bDum=gmx_fio_ndo_real(fio,ir->opts.SAoff,ir->opts.ngQM);
+        bDum=gmx_fio_ndo_int(fio,ir->opts.SAsteps,ir->opts.ngQM);
+        bDum=gmx_fio_ndo_gmx_bool(fio,ir->opts.bOPT,ir->opts.ngQM);
+        bDum=gmx_fio_ndo_gmx_bool(fio,ir->opts.bTS,ir->opts.ngQM);
+      }
+      /* end of QMMM stuff */
+    }    
+}
+
+
+static void do_harm(t_fileio *fio, t_iparams *iparams,gmx_bool bRead)
+{
+  gmx_fio_do_real(fio,iparams->harmonic.rA);
+  gmx_fio_do_real(fio,iparams->harmonic.krA);
+  gmx_fio_do_real(fio,iparams->harmonic.rB);
+  gmx_fio_do_real(fio,iparams->harmonic.krB);
+}
+
+void do_iparams(t_fileio *fio, t_functype ftype,t_iparams *iparams,
+                gmx_bool bRead, int file_version)
+{
+  int i;
+  gmx_bool bDum;
+  real rdum;
+  
+  if (!bRead)
+    gmx_fio_set_comment(fio, interaction_function[ftype].name);
+  switch (ftype) {
+  case F_ANGLES:
+  case F_G96ANGLES:
+  case F_BONDS:
+  case F_G96BONDS:
+  case F_HARMONIC:
+  case F_IDIHS:
+    do_harm(fio, iparams,bRead);
+    if ((ftype == F_ANGRES || ftype == F_ANGRESZ) && bRead) {
+      /* Correct incorrect storage of parameters */
+      iparams->pdihs.phiB = iparams->pdihs.phiA;
+      iparams->pdihs.cpB  = iparams->pdihs.cpA;
+    }
+    break;
+  case F_FENEBONDS:
+    gmx_fio_do_real(fio,iparams->fene.bm);
+    gmx_fio_do_real(fio,iparams->fene.kb);
+    break;
+  case F_RESTRBONDS:
+    gmx_fio_do_real(fio,iparams->restraint.lowA);
+    gmx_fio_do_real(fio,iparams->restraint.up1A);
+    gmx_fio_do_real(fio,iparams->restraint.up2A);
+    gmx_fio_do_real(fio,iparams->restraint.kA);
+    gmx_fio_do_real(fio,iparams->restraint.lowB);
+    gmx_fio_do_real(fio,iparams->restraint.up1B);
+    gmx_fio_do_real(fio,iparams->restraint.up2B);
+    gmx_fio_do_real(fio,iparams->restraint.kB);
+    break;
+  case F_TABBONDS:
+  case F_TABBONDSNC:
+  case F_TABANGLES:
+  case F_TABDIHS:
+    gmx_fio_do_real(fio,iparams->tab.kA);
+    gmx_fio_do_int(fio,iparams->tab.table);
+    gmx_fio_do_real(fio,iparams->tab.kB);
+    break;
+  case F_CROSS_BOND_BONDS:
+    gmx_fio_do_real(fio,iparams->cross_bb.r1e);
+    gmx_fio_do_real(fio,iparams->cross_bb.r2e);
+    gmx_fio_do_real(fio,iparams->cross_bb.krr);
+    break;
+  case F_CROSS_BOND_ANGLES:
+    gmx_fio_do_real(fio,iparams->cross_ba.r1e);
+    gmx_fio_do_real(fio,iparams->cross_ba.r2e);
+    gmx_fio_do_real(fio,iparams->cross_ba.r3e);
+    gmx_fio_do_real(fio,iparams->cross_ba.krt);
+    break;
+  case F_UREY_BRADLEY:
+    gmx_fio_do_real(fio,iparams->u_b.theta);
+    gmx_fio_do_real(fio,iparams->u_b.ktheta);
+    gmx_fio_do_real(fio,iparams->u_b.r13);
+    gmx_fio_do_real(fio,iparams->u_b.kUB);
+    break;
+  case F_QUARTIC_ANGLES:
+    gmx_fio_do_real(fio,iparams->qangle.theta);
+    bDum=gmx_fio_ndo_real(fio,iparams->qangle.c,5);
+    break;
+  case F_BHAM:
+    gmx_fio_do_real(fio,iparams->bham.a);
+    gmx_fio_do_real(fio,iparams->bham.b);
+    gmx_fio_do_real(fio,iparams->bham.c);
+    break;
+  case F_MORSE:
+    gmx_fio_do_real(fio,iparams->morse.b0);
+    gmx_fio_do_real(fio,iparams->morse.cb);
+    gmx_fio_do_real(fio,iparams->morse.beta);
+    break;
+  case F_CUBICBONDS:
+    gmx_fio_do_real(fio,iparams->cubic.b0);
+    gmx_fio_do_real(fio,iparams->cubic.kb);
+    gmx_fio_do_real(fio,iparams->cubic.kcub);
+    break;
+  case F_CONNBONDS:
+    break;
+  case F_POLARIZATION:
+    gmx_fio_do_real(fio,iparams->polarize.alpha);
+    break;
+  case F_WATER_POL:
+    if (file_version < 31) 
+      gmx_fatal(FARGS,"Old tpr files with water_polarization not supported. Make a new.");
+    gmx_fio_do_real(fio,iparams->wpol.al_x);
+    gmx_fio_do_real(fio,iparams->wpol.al_y);
+    gmx_fio_do_real(fio,iparams->wpol.al_z);
+    gmx_fio_do_real(fio,iparams->wpol.rOH);
+    gmx_fio_do_real(fio,iparams->wpol.rHH);
+    gmx_fio_do_real(fio,iparams->wpol.rOD);
+    break;
+  case F_THOLE_POL:
+    gmx_fio_do_real(fio,iparams->thole.a);
+    gmx_fio_do_real(fio,iparams->thole.alpha1);
+    gmx_fio_do_real(fio,iparams->thole.alpha2);
+    gmx_fio_do_real(fio,iparams->thole.rfac);
+    break;
+  case F_LJ:
+    gmx_fio_do_real(fio,iparams->lj.c6);
+    gmx_fio_do_real(fio,iparams->lj.c12);
+    break;
+  case F_LJ14:
+    gmx_fio_do_real(fio,iparams->lj14.c6A);
+    gmx_fio_do_real(fio,iparams->lj14.c12A);
+    gmx_fio_do_real(fio,iparams->lj14.c6B);
+    gmx_fio_do_real(fio,iparams->lj14.c12B);
+    break;
+  case F_LJC14_Q:
+    gmx_fio_do_real(fio,iparams->ljc14.fqq);
+    gmx_fio_do_real(fio,iparams->ljc14.qi);
+    gmx_fio_do_real(fio,iparams->ljc14.qj);
+    gmx_fio_do_real(fio,iparams->ljc14.c6);
+    gmx_fio_do_real(fio,iparams->ljc14.c12);
+    break;
+  case F_LJC_PAIRS_NB:
+    gmx_fio_do_real(fio,iparams->ljcnb.qi);
+    gmx_fio_do_real(fio,iparams->ljcnb.qj);
+    gmx_fio_do_real(fio,iparams->ljcnb.c6);
+    gmx_fio_do_real(fio,iparams->ljcnb.c12);
+    break;
+  case F_PDIHS:
+  case F_PIDIHS:
+  case F_ANGRES:
+  case F_ANGRESZ:
+    gmx_fio_do_real(fio,iparams->pdihs.phiA);
+    gmx_fio_do_real(fio,iparams->pdihs.cpA);
+    if ((ftype == F_ANGRES || ftype == F_ANGRESZ) && file_version < 42) {
+      /* Read the incorrectly stored multiplicity */
+      gmx_fio_do_real(fio,iparams->harmonic.rB);
+      gmx_fio_do_real(fio,iparams->harmonic.krB);
+      iparams->pdihs.phiB = iparams->pdihs.phiA;
+      iparams->pdihs.cpB  = iparams->pdihs.cpA;
+    } else {
+      gmx_fio_do_real(fio,iparams->pdihs.phiB);
+      gmx_fio_do_real(fio,iparams->pdihs.cpB);
+      gmx_fio_do_int(fio,iparams->pdihs.mult);
+    }
+    break;
+  case F_DISRES:
+    gmx_fio_do_int(fio,iparams->disres.label);
+    gmx_fio_do_int(fio,iparams->disres.type);
+    gmx_fio_do_real(fio,iparams->disres.low);
+    gmx_fio_do_real(fio,iparams->disres.up1);
+    gmx_fio_do_real(fio,iparams->disres.up2);
+    gmx_fio_do_real(fio,iparams->disres.kfac);
+    break;
+  case F_ORIRES:
+    gmx_fio_do_int(fio,iparams->orires.ex);
+    gmx_fio_do_int(fio,iparams->orires.label);
+    gmx_fio_do_int(fio,iparams->orires.power);
+    gmx_fio_do_real(fio,iparams->orires.c);
+    gmx_fio_do_real(fio,iparams->orires.obs);
+    gmx_fio_do_real(fio,iparams->orires.kfac);
+    break;
+  case F_DIHRES:
+    gmx_fio_do_int(fio,iparams->dihres.power);
+    gmx_fio_do_int(fio,iparams->dihres.label);
+    gmx_fio_do_real(fio,iparams->dihres.phi);
+    gmx_fio_do_real(fio,iparams->dihres.dphi);
+    gmx_fio_do_real(fio,iparams->dihres.kfac);
+    break;
+  case F_POSRES:
+    gmx_fio_do_rvec(fio,iparams->posres.pos0A);
+    gmx_fio_do_rvec(fio,iparams->posres.fcA);
+    if (bRead && file_version < 27) {
+      copy_rvec(iparams->posres.pos0A,iparams->posres.pos0B);
+      copy_rvec(iparams->posres.fcA,iparams->posres.fcB);
+    } else {
+      gmx_fio_do_rvec(fio,iparams->posres.pos0B);
+      gmx_fio_do_rvec(fio,iparams->posres.fcB);
+    }
+    break;
+  case F_RBDIHS:
+    bDum=gmx_fio_ndo_real(fio,iparams->rbdihs.rbcA,NR_RBDIHS);
+    if(file_version>=25) 
+      bDum=gmx_fio_ndo_real(fio,iparams->rbdihs.rbcB,NR_RBDIHS);
+    break;
+  case F_FOURDIHS:
+    /* Fourier dihedrals are internally represented
+     * as Ryckaert-Bellemans since those are faster to compute.
+     */
+     bDum=gmx_fio_ndo_real(fio,iparams->rbdihs.rbcA, NR_RBDIHS);
+     bDum=gmx_fio_ndo_real(fio,iparams->rbdihs.rbcB, NR_RBDIHS);
+    break;
+  case F_CONSTR:
+  case F_CONSTRNC:
+    gmx_fio_do_real(fio,iparams->constr.dA);
+    gmx_fio_do_real(fio,iparams->constr.dB);
+    break;
+  case F_SETTLE:
+    gmx_fio_do_real(fio,iparams->settle.doh);
+    gmx_fio_do_real(fio,iparams->settle.dhh);
+    break;
+  case F_VSITE2:
+    gmx_fio_do_real(fio,iparams->vsite.a);
+    break;
+  case F_VSITE3:
+  case F_VSITE3FD:
+  case F_VSITE3FAD:
+    gmx_fio_do_real(fio,iparams->vsite.a);
+    gmx_fio_do_real(fio,iparams->vsite.b);
+    break;
+  case F_VSITE3OUT:
+  case F_VSITE4FD: 
+  case F_VSITE4FDN: 
+    gmx_fio_do_real(fio,iparams->vsite.a);
+    gmx_fio_do_real(fio,iparams->vsite.b);
+    gmx_fio_do_real(fio,iparams->vsite.c);
+    break;
+  case F_VSITEN:
+    gmx_fio_do_int(fio,iparams->vsiten.n);
+    gmx_fio_do_real(fio,iparams->vsiten.a);
+    break;
+  case F_GB12:
+  case F_GB13:
+  case F_GB14:
+    /* We got rid of some parameters in version 68 */
+    if(bRead && file_version<68)
+    {
+        gmx_fio_do_real(fio,rdum);     
+        gmx_fio_do_real(fio,rdum);     
+        gmx_fio_do_real(fio,rdum);     
+        gmx_fio_do_real(fio,rdum);     
+    }
+       gmx_fio_do_real(fio,iparams->gb.sar);   
+       gmx_fio_do_real(fio,iparams->gb.st);
+       gmx_fio_do_real(fio,iparams->gb.pi);
+       gmx_fio_do_real(fio,iparams->gb.gbr);
+       gmx_fio_do_real(fio,iparams->gb.bmlt);
+       break;
+  case F_CMAP:
+       gmx_fio_do_int(fio,iparams->cmap.cmapA);
+       gmx_fio_do_int(fio,iparams->cmap.cmapB);
+    break;
+  default:
+    gmx_fatal(FARGS,"unknown function type %d (%s) in %s line %d",
+               
+               ftype,interaction_function[ftype].name,__FILE__,__LINE__);
+  }
+  if (!bRead)
+    gmx_fio_unset_comment(fio);
+}
+
+static void do_ilist(t_fileio *fio, t_ilist *ilist,gmx_bool bRead,int file_version,
+                    int ftype)
+{
+  int  i,k,idum;
+  gmx_bool bDum=TRUE;
+  
+  if (!bRead) {
+    gmx_fio_set_comment(fio, interaction_function[ftype].name);
+  }
+  if (file_version < 44) {
+    for(i=0; i<MAXNODES; i++)
+      gmx_fio_do_int(fio,idum);
+  }
+  gmx_fio_do_int(fio,ilist->nr);
+  if (bRead)
+    snew(ilist->iatoms,ilist->nr);
+  bDum=gmx_fio_ndo_int(fio,ilist->iatoms,ilist->nr);
+  if (!bRead)
+    gmx_fio_unset_comment(fio);
+}
+
+static void do_ffparams(t_fileio *fio, gmx_ffparams_t *ffparams,
+                       gmx_bool bRead, int file_version)
+{
+  int  idum,i,j;
+  gmx_bool bDum=TRUE;
+  unsigned int k;
+
+  gmx_fio_do_int(fio,ffparams->atnr);
+  if (file_version < 57) {
+    gmx_fio_do_int(fio,idum);
+  }
+  gmx_fio_do_int(fio,ffparams->ntypes);
+  if (bRead && debug)
+    fprintf(debug,"ffparams->atnr = %d, ntypes = %d\n",
+           ffparams->atnr,ffparams->ntypes);
+  if (bRead) {
+    snew(ffparams->functype,ffparams->ntypes);
+    snew(ffparams->iparams,ffparams->ntypes);
+  }
+  /* Read/write all the function types */
+  bDum=gmx_fio_ndo_int(fio,ffparams->functype,ffparams->ntypes);
+  if (bRead && debug)
+    pr_ivec(debug,0,"functype",ffparams->functype,ffparams->ntypes,TRUE);
+
+  if (file_version >= 66) {
+    gmx_fio_do_double(fio,ffparams->reppow);
+  } else {
+    ffparams->reppow = 12.0;
+  }
+
+  if (file_version >= 57) {
+    gmx_fio_do_real(fio,ffparams->fudgeQQ);
+  }
+
+  /* Check whether all these function types are supported by the code.
+   * In practice the code is backwards compatible, which means that the
+   * numbering may have to be altered from old numbering to new numbering
+   */
+  for (i=0; (i<ffparams->ntypes); i++) {
+    if (bRead)
+      /* Loop over file versions */
+      for (k=0; (k<NFTUPD); k++)
+       /* Compare the read file_version to the update table */
+       if ((file_version < ftupd[k].fvnr) && 
+           (ffparams->functype[i] >= ftupd[k].ftype)) {
+         ffparams->functype[i] += 1;
+         if (debug) {
+           fprintf(debug,"Incrementing function type %d to %d (due to %s)\n",
+                   i,ffparams->functype[i],
+                   interaction_function[ftupd[k].ftype].longname);
+           fflush(debug);
+         }
+       }
+    
+    do_iparams(fio, ffparams->functype[i],&ffparams->iparams[i],bRead,
+               file_version);
+    if (bRead && debug)
+      pr_iparams(debug,ffparams->functype[i],&ffparams->iparams[i]);
+  }
+}
+
+static void do_ilists(t_fileio *fio, t_ilist *ilist,gmx_bool bRead, 
+                      int file_version)
+{
+  int i,j,renum[F_NRE];
+  gmx_bool bDum=TRUE,bClear;
+  unsigned int k;
+  
+  for(j=0; (j<F_NRE); j++) {
+    bClear = FALSE;
+    if (bRead)
+      for (k=0; k<NFTUPD; k++)
+       if ((file_version < ftupd[k].fvnr) && (j == ftupd[k].ftype))
+         bClear = TRUE;
+    if (bClear) {
+      ilist[j].nr = 0;
+      ilist[j].iatoms = NULL;
+    } else {
+      do_ilist(fio, &ilist[j],bRead,file_version,j);
+    }
+    /*
+    if (bRead && gmx_debug_at)
+      pr_ilist(debug,0,interaction_function[j].longname,
+              functype,&ilist[j],TRUE);
+    */
+  }
+}
+
+static void do_idef(t_fileio *fio, gmx_ffparams_t *ffparams,gmx_moltype_t *molt,
+                   gmx_bool bRead, int file_version)
+{
+  do_ffparams(fio, ffparams,bRead,file_version);
+    
+  if (file_version >= 54) {
+    gmx_fio_do_real(fio,ffparams->fudgeQQ);
+  }
+
+  do_ilists(fio, molt->ilist,bRead,file_version);
+}
+
+static void do_block(t_fileio *fio, t_block *block,gmx_bool bRead,int file_version)
+{
+  int  i,idum,dum_nra,*dum_a;
+  gmx_bool bDum=TRUE;
+
+  if (file_version < 44)
+    for(i=0; i<MAXNODES; i++)
+      gmx_fio_do_int(fio,idum);
+  gmx_fio_do_int(fio,block->nr);
+  if (file_version < 51)
+    gmx_fio_do_int(fio,dum_nra);
+  if (bRead) {
+    block->nalloc_index = block->nr+1;
+    snew(block->index,block->nalloc_index);
+  }
+  bDum=gmx_fio_ndo_int(fio,block->index,block->nr+1);
+
+  if (file_version < 51 && dum_nra > 0) {
+    snew(dum_a,dum_nra);
+    bDum=gmx_fio_ndo_int(fio,dum_a,dum_nra);
+    sfree(dum_a);
+  }
+}
+
+static void do_blocka(t_fileio *fio, t_blocka *block,gmx_bool bRead,
+                      int file_version)
+{
+  int  i,idum;
+  gmx_bool bDum=TRUE;
+
+  if (file_version < 44)
+    for(i=0; i<MAXNODES; i++)
+      gmx_fio_do_int(fio,idum);
+  gmx_fio_do_int(fio,block->nr);
+  gmx_fio_do_int(fio,block->nra);
+  if (bRead) {
+    block->nalloc_index = block->nr+1;
+    snew(block->index,block->nalloc_index);
+    block->nalloc_a = block->nra;
+    snew(block->a,block->nalloc_a);
+  }
+  bDum=gmx_fio_ndo_int(fio,block->index,block->nr+1);
+  bDum=gmx_fio_ndo_int(fio,block->a,block->nra);
+}
+
+static void do_atom(t_fileio *fio, t_atom *atom,int ngrp,gmx_bool bRead, 
+                    int file_version, gmx_groups_t *groups,int atnr)
+{ 
+  int i,myngrp;
+  
+  gmx_fio_do_real(fio,atom->m);
+  gmx_fio_do_real(fio,atom->q);
+  gmx_fio_do_real(fio,atom->mB);
+  gmx_fio_do_real(fio,atom->qB);
+  gmx_fio_do_ushort(fio, atom->type);
+  gmx_fio_do_ushort(fio, atom->typeB);
+  gmx_fio_do_int(fio,atom->ptype);
+  gmx_fio_do_int(fio,atom->resind);
+  if (file_version >= 52)
+    gmx_fio_do_int(fio,atom->atomnumber);
+  else if (bRead)
+    atom->atomnumber = NOTSET;
+  if (file_version < 23) 
+    myngrp = 8;
+  else if (file_version < 39) 
+    myngrp = 9;
+  else
+    myngrp = ngrp;
+
+  if (file_version < 57) {
+    unsigned char uchar[egcNR];
+    gmx_fio_ndo_uchar(fio,uchar,myngrp);
+    for(i=myngrp; (i<ngrp); i++) {
+      uchar[i] = 0;
+    }
+    /* Copy the old data format to the groups struct */
+    for(i=0; i<ngrp; i++) {
+      groups->grpnr[i][atnr] = uchar[i];
+    }
+  }
+}
+
+static void do_grps(t_fileio *fio, int ngrp,t_grps grps[],gmx_bool bRead, 
+                    int file_version)
+{
+  int i,j,myngrp;
+  gmx_bool bDum=TRUE;
+  
+  if (file_version < 23) 
+    myngrp = 8;
+  else if (file_version < 39) 
+    myngrp = 9;
+  else
+    myngrp = ngrp;
+
+  for(j=0; (j<ngrp); j++) {
+    if (j<myngrp) {
+      gmx_fio_do_int(fio,grps[j].nr);
+      if (bRead)
+       snew(grps[j].nm_ind,grps[j].nr);
+      bDum=gmx_fio_ndo_int(fio,grps[j].nm_ind,grps[j].nr);
+    }
+    else {
+      grps[j].nr = 1;
+      snew(grps[j].nm_ind,grps[j].nr);
+    }
+  }
+}
+
+static void do_symstr(t_fileio *fio, char ***nm,gmx_bool bRead,t_symtab *symtab)
+{
+  int ls;
+  
+  if (bRead) {
+    gmx_fio_do_int(fio,ls);
+    *nm = get_symtab_handle(symtab,ls);
+  }
+  else {
+    ls = lookup_symtab(symtab,*nm);
+    gmx_fio_do_int(fio,ls);
+  }
+}
+
+static void do_strstr(t_fileio *fio, int nstr,char ***nm,gmx_bool bRead,
+                      t_symtab *symtab)
+{
+  int  j;
+  
+  for (j=0; (j<nstr); j++) 
+    do_symstr(fio, &(nm[j]),bRead,symtab);
+}
+
+static void do_resinfo(t_fileio *fio, int n,t_resinfo *ri,gmx_bool bRead,
+                       t_symtab *symtab, int file_version)
+{
+  int  j;
+  
+  for (j=0; (j<n); j++) {
+    do_symstr(fio, &(ri[j].name),bRead,symtab);
+    if (file_version >= 63) {
+      gmx_fio_do_int(fio,ri[j].nr);
+      gmx_fio_do_uchar(fio, ri[j].ic);
+    } else {
+      ri[j].nr = j + 1;
+      ri[j].ic = ' ';
+    }
+  }
+}
+
+static void do_atoms(t_fileio *fio, t_atoms *atoms,gmx_bool bRead,t_symtab *symtab,
+                    int file_version,
+                    gmx_groups_t *groups)
+{
+  int i;
+  
+  gmx_fio_do_int(fio,atoms->nr);
+  gmx_fio_do_int(fio,atoms->nres);
+  if (file_version < 57) {
+    gmx_fio_do_int(fio,groups->ngrpname);
+    for(i=0; i<egcNR; i++) {
+      groups->ngrpnr[i] = atoms->nr;
+      snew(groups->grpnr[i],groups->ngrpnr[i]);
+    }
+  }
+  if (bRead) {
+    snew(atoms->atom,atoms->nr);
+    snew(atoms->atomname,atoms->nr);
+    snew(atoms->atomtype,atoms->nr);
+    snew(atoms->atomtypeB,atoms->nr);
+    snew(atoms->resinfo,atoms->nres);
+    if (file_version < 57) {
+      snew(groups->grpname,groups->ngrpname);
+    }
+    atoms->pdbinfo = NULL;
+  }
+  for(i=0; (i<atoms->nr); i++) {
+    do_atom(fio, &atoms->atom[i],egcNR,bRead, file_version,groups,i);
+  }
+  do_strstr(fio, atoms->nr,atoms->atomname,bRead,symtab);
+  if (bRead && (file_version <= 20)) {
+    for(i=0; i<atoms->nr; i++) {
+      atoms->atomtype[i]  = put_symtab(symtab,"?");
+      atoms->atomtypeB[i] = put_symtab(symtab,"?");
+    }
+  } else {
+    do_strstr(fio, atoms->nr,atoms->atomtype,bRead,symtab);
+    do_strstr(fio, atoms->nr,atoms->atomtypeB,bRead,symtab);
+  }
+  do_resinfo(fio, atoms->nres,atoms->resinfo,bRead,symtab,file_version);
+
+  if (file_version < 57) {
+    do_strstr(fio, groups->ngrpname,groups->grpname,bRead,symtab);
+  
+    do_grps(fio, egcNR,groups->grps,bRead,file_version);
+  }
+}
+
+static void do_groups(t_fileio *fio, gmx_groups_t *groups,
+                     gmx_bool bRead,t_symtab *symtab,
+                     int file_version)
+{
+  int  g,n,i;
+  gmx_bool bDum=TRUE;
+
+  do_grps(fio, egcNR,groups->grps,bRead,file_version);
+  gmx_fio_do_int(fio,groups->ngrpname);
+  if (bRead) {
+    snew(groups->grpname,groups->ngrpname);
+  }
+  do_strstr(fio, groups->ngrpname,groups->grpname,bRead,symtab);
+  for(g=0; g<egcNR; g++) {
+    gmx_fio_do_int(fio,groups->ngrpnr[g]);
+    if (groups->ngrpnr[g] == 0) {
+      if (bRead) {
+       groups->grpnr[g] = NULL;
+      }
+    } else {
+      if (bRead) {
+       snew(groups->grpnr[g],groups->ngrpnr[g]);
+      }
+      bDum=gmx_fio_ndo_uchar(fio, groups->grpnr[g],groups->ngrpnr[g]);
+    }
+  }
+}
+
+static void do_atomtypes(t_fileio *fio, t_atomtypes *atomtypes,gmx_bool bRead,
+                        t_symtab *symtab,int file_version)
+{
+  int i,j;
+  gmx_bool bDum = TRUE;
+  
+  if (file_version > 25) {
+    gmx_fio_do_int(fio,atomtypes->nr);
+    j=atomtypes->nr;
+    if (bRead) {
+      snew(atomtypes->radius,j);
+      snew(atomtypes->vol,j);
+      snew(atomtypes->surftens,j);
+      snew(atomtypes->atomnumber,j);
+      snew(atomtypes->gb_radius,j);
+      snew(atomtypes->S_hct,j);
+    }
+    bDum=gmx_fio_ndo_real(fio,atomtypes->radius,j);
+    bDum=gmx_fio_ndo_real(fio,atomtypes->vol,j);
+    bDum=gmx_fio_ndo_real(fio,atomtypes->surftens,j);
+    if(file_version >= 40)
+    {
+        bDum=gmx_fio_ndo_int(fio,atomtypes->atomnumber,j);
+    }
+       if(file_version >= 60)
+       {
+               bDum=gmx_fio_ndo_real(fio,atomtypes->gb_radius,j);
+               bDum=gmx_fio_ndo_real(fio,atomtypes->S_hct,j);
+       }
+  } else {
+    /* File versions prior to 26 cannot do GBSA, 
+     * so they dont use this structure 
+     */
+    atomtypes->nr = 0;
+    atomtypes->radius = NULL;
+    atomtypes->vol = NULL;
+    atomtypes->surftens = NULL;
+    atomtypes->atomnumber = NULL;
+    atomtypes->gb_radius = NULL;
+    atomtypes->S_hct = NULL;
+  }  
+}
+
+static void do_symtab(t_fileio *fio, t_symtab *symtab,gmx_bool bRead)
+{
+  int i,nr;
+  t_symbuf *symbuf;
+  char buf[STRLEN];
+  
+  gmx_fio_do_int(fio,symtab->nr);
+  nr     = symtab->nr;
+  if (bRead) {
+    snew(symtab->symbuf,1);
+    symbuf = symtab->symbuf;
+    symbuf->bufsize = nr;
+    snew(symbuf->buf,nr);
+    for (i=0; (i<nr); i++) {
+      gmx_fio_do_string(fio,buf);
+      symbuf->buf[i]=strdup(buf);
+    }
+  }
+  else {
+    symbuf = symtab->symbuf;
+    while (symbuf!=NULL) {
+      for (i=0; (i<symbuf->bufsize) && (i<nr); i++) 
+       gmx_fio_do_string(fio,symbuf->buf[i]);
+      nr-=i;
+      symbuf=symbuf->next;
+    }
+    if (nr != 0)
+      gmx_fatal(FARGS,"nr of symtab strings left: %d",nr);
+  }
+}
+
+static void do_cmap(t_fileio *fio, gmx_cmap_t *cmap_grid, gmx_bool bRead)
+{
+       int i,j,ngrid,gs,nelem;
+       
+       gmx_fio_do_int(fio,cmap_grid->ngrid);
+       gmx_fio_do_int(fio,cmap_grid->grid_spacing);
+       
+       ngrid = cmap_grid->ngrid;
+       gs    = cmap_grid->grid_spacing;
+       nelem = gs * gs;
+       
+       if(bRead)
+       {
+               snew(cmap_grid->cmapdata,ngrid);
+               
+               for(i=0;i<cmap_grid->ngrid;i++)
+               {
+                       snew(cmap_grid->cmapdata[i].cmap,4*nelem);
+               }
+       }
+       
+       for(i=0;i<cmap_grid->ngrid;i++)
+       {
+               for(j=0;j<nelem;j++)
+               {
+                       gmx_fio_do_real(fio,cmap_grid->cmapdata[i].cmap[j*4]);
+                       gmx_fio_do_real(fio,cmap_grid->cmapdata[i].cmap[j*4+1]);
+                       gmx_fio_do_real(fio,cmap_grid->cmapdata[i].cmap[j*4+2]);
+                       gmx_fio_do_real(fio,cmap_grid->cmapdata[i].cmap[j*4+3]);
+               }
+       }       
+}
+
+
+void tpx_make_chain_identifiers(t_atoms *atoms,t_block *mols)
+{
+    int m,a,a0,a1,r;
+    char c,chainid;
+    int  chainnum;
+    
+    /* We always assign a new chain number, but save the chain id characters 
+     * for larger molecules.
+     */
+#define CHAIN_MIN_ATOMS 15
+    
+    chainnum=0;
+    chainid='A';
+    for(m=0; m<mols->nr; m++) 
+    {
+        a0=mols->index[m];
+        a1=mols->index[m+1];
+        if ((a1-a0 >= CHAIN_MIN_ATOMS) && (chainid <= 'Z')) 
+        {
+            c=chainid;
+            chainid++;
+        } 
+        else
+        {
+            c=' ';
+        }
+        for(a=a0; a<a1; a++) 
+        {
+            atoms->resinfo[atoms->atom[a].resind].chainnum = chainnum;
+            atoms->resinfo[atoms->atom[a].resind].chainid  = c;
+        }
+        chainnum++;
+    }
+    
+    /* Blank out the chain id if there was only one chain */
+    if (chainid == 'B') 
+    {
+        for(r=0; r<atoms->nres; r++) 
+        {
+            atoms->resinfo[r].chainid = ' ';
+        }
+    }
+}
+  
+static void do_moltype(t_fileio *fio, gmx_moltype_t *molt,gmx_bool bRead,
+                       t_symtab *symtab, int file_version,
+                      gmx_groups_t *groups)
+{
+  int i;
+
+  if (file_version >= 57) {
+    do_symstr(fio, &(molt->name),bRead,symtab);
+  }
+
+  do_atoms(fio, &molt->atoms, bRead, symtab, file_version, groups);
+
+  if (bRead && gmx_debug_at) {
+    pr_atoms(debug,0,"atoms",&molt->atoms,TRUE);
+  }
+  
+  if (file_version >= 57) {
+    do_ilists(fio, molt->ilist,bRead,file_version);
+
+    do_block(fio, &molt->cgs,bRead,file_version);
+    if (bRead && gmx_debug_at) {
+      pr_block(debug,0,"cgs",&molt->cgs,TRUE);
+    }
+  }
+
+  /* This used to be in the atoms struct */
+  do_blocka(fio, &molt->excls, bRead, file_version);
+}
+
+static void do_molblock(t_fileio *fio, gmx_molblock_t *molb,gmx_bool bRead,
+                        int file_version)
+{
+  int i;
+
+  gmx_fio_do_int(fio,molb->type);
+  gmx_fio_do_int(fio,molb->nmol);
+  gmx_fio_do_int(fio,molb->natoms_mol);
+  /* Position restraint coordinates */
+  gmx_fio_do_int(fio,molb->nposres_xA);
+  if (molb->nposres_xA > 0) {
+    if (bRead) {
+      snew(molb->posres_xA,molb->nposres_xA);
+    }
+    gmx_fio_ndo_rvec(fio,molb->posres_xA,molb->nposres_xA);
+  }
+  gmx_fio_do_int(fio,molb->nposres_xB);
+  if (molb->nposres_xB > 0) {
+    if (bRead) {
+      snew(molb->posres_xB,molb->nposres_xB);
+    }
+    gmx_fio_ndo_rvec(fio,molb->posres_xB,molb->nposres_xB);
+  }
+
+}
+
+static t_block mtop_mols(gmx_mtop_t *mtop)
+{
+  int mb,m,a,mol;
+  t_block mols;
+
+  mols.nr = 0;
+  for(mb=0; mb<mtop->nmolblock; mb++) {
+    mols.nr += mtop->molblock[mb].nmol;
+  }
+  mols.nalloc_index = mols.nr + 1;
+  snew(mols.index,mols.nalloc_index);
+
+  a = 0;
+  m = 0;
+  mols.index[m] = a;
+  for(mb=0; mb<mtop->nmolblock; mb++) {
+    for(mol=0; mol<mtop->molblock[mb].nmol; mol++) {
+      a += mtop->molblock[mb].natoms_mol;
+      m++;
+      mols.index[m] = a;
+    }
+  }
+  
+  return mols;
+}
+
+static void add_posres_molblock(gmx_mtop_t *mtop)
+{
+  t_ilist *il;
+  int am,i,mol,a;
+  gmx_bool bFE;
+  gmx_molblock_t *molb;
+  t_iparams *ip;
+
+  il = &mtop->moltype[0].ilist[F_POSRES];
+  if (il->nr == 0) {
+    return;
+  }
+  am = 0;
+  bFE = FALSE;
+  for(i=0; i<il->nr; i+=2) {
+    ip = &mtop->ffparams.iparams[il->iatoms[i]];
+    am = max(am,il->iatoms[i+1]);
+    if (ip->posres.pos0B[XX] != ip->posres.pos0A[XX] ||
+       ip->posres.pos0B[YY] != ip->posres.pos0A[YY] ||
+       ip->posres.pos0B[ZZ] != ip->posres.pos0A[ZZ]) {
+      bFE = TRUE;
+    }
+  }
+  /* Make the posres coordinate block end at a molecule end */
+  mol = 0;
+  while(am >= mtop->mols.index[mol+1]) {
+    mol++;
+  }
+  molb = &mtop->molblock[0];
+  molb->nposres_xA = mtop->mols.index[mol+1];
+  snew(molb->posres_xA,molb->nposres_xA);
+  if (bFE) {
+    molb->nposres_xB = molb->nposres_xA;
+    snew(molb->posres_xB,molb->nposres_xB);
+  } else {
+    molb->nposres_xB = 0;
+  }
+  for(i=0; i<il->nr; i+=2) {
+    ip = &mtop->ffparams.iparams[il->iatoms[i]];
+    a  = il->iatoms[i+1];
+    molb->posres_xA[a][XX] = ip->posres.pos0A[XX];
+    molb->posres_xA[a][YY] = ip->posres.pos0A[YY];
+    molb->posres_xA[a][ZZ] = ip->posres.pos0A[ZZ];
+    if (bFE) {
+      molb->posres_xB[a][XX] = ip->posres.pos0B[XX];
+      molb->posres_xB[a][YY] = ip->posres.pos0B[YY];
+      molb->posres_xB[a][ZZ] = ip->posres.pos0B[ZZ];
+    }
+  }
+}
+
+static void set_disres_npair(gmx_mtop_t *mtop)
+{
+  int mt,i,npair;
+  t_iparams *ip;
+  t_ilist *il;
+  t_iatom *a;
+
+  ip = mtop->ffparams.iparams;
+
+  for(mt=0; mt<mtop->nmoltype; mt++) {
+    il = &mtop->moltype[mt].ilist[F_DISRES];
+    if (il->nr > 0) {
+      a = il->iatoms;
+      npair = 0;
+      for(i=0; i<il->nr; i+=3) {
+       npair++;
+       if (i+3 == il->nr || ip[a[i]].disres.label != ip[a[i+3]].disres.label) {
+         ip[a[i]].disres.npair = npair;
+         npair = 0;
+       }
+      }
+    }
+  }
+}
+
+static void do_mtop(t_fileio *fio, gmx_mtop_t *mtop,gmx_bool bRead, 
+                    int file_version)
+{
+  int  mt,mb,i;
+  t_blocka dumb;
+
+  if (bRead)
+    init_mtop(mtop);
+  do_symtab(fio, &(mtop->symtab),bRead);
+  if (bRead && debug) 
+    pr_symtab(debug,0,"symtab",&mtop->symtab);
+  
+  do_symstr(fio, &(mtop->name),bRead,&(mtop->symtab));
+  
+  if (file_version >= 57) {
+    do_ffparams(fio, &mtop->ffparams,bRead,file_version);
+
+    gmx_fio_do_int(fio,mtop->nmoltype);
+  } else {
+    mtop->nmoltype = 1;
+  }
+  if (bRead) {
+    snew(mtop->moltype,mtop->nmoltype);
+    if (file_version < 57) {
+      mtop->moltype[0].name = mtop->name;
+    }
+  }
+  for(mt=0; mt<mtop->nmoltype; mt++) {
+    do_moltype(fio, &mtop->moltype[mt],bRead,&mtop->symtab,file_version,
+              &mtop->groups);
+  }
+
+  if (file_version >= 57) {
+    gmx_fio_do_int(fio,mtop->nmolblock);
+  } else {
+    mtop->nmolblock = 1;
+  }
+  if (bRead) {
+    snew(mtop->molblock,mtop->nmolblock);
+  }
+  if (file_version >= 57) {
+    for(mb=0; mb<mtop->nmolblock; mb++) {
+      do_molblock(fio, &mtop->molblock[mb],bRead,file_version);
+    }
+    gmx_fio_do_int(fio,mtop->natoms);
+  } else {
+    mtop->molblock[0].type = 0;
+    mtop->molblock[0].nmol = 1;
+    mtop->molblock[0].natoms_mol = mtop->moltype[0].atoms.nr;
+    mtop->molblock[0].nposres_xA = 0;
+    mtop->molblock[0].nposres_xB = 0;
+  }
+
+  do_atomtypes (fio, &(mtop->atomtypes),bRead,&(mtop->symtab), file_version);
+  if (bRead && debug) 
+    pr_atomtypes(debug,0,"atomtypes",&mtop->atomtypes,TRUE);
+
+  if (file_version < 57) {
+    /* Debug statements are inside do_idef */    
+    do_idef (fio, &mtop->ffparams,&mtop->moltype[0],bRead,file_version);
+    mtop->natoms = mtop->moltype[0].atoms.nr;
+  }
+       
+  if(file_version >= 65)
+  {
+      do_cmap(fio, &mtop->ffparams.cmap_grid,bRead);
+  }
+  else
+  {
+      mtop->ffparams.cmap_grid.ngrid        = 0;
+      mtop->ffparams.cmap_grid.grid_spacing = 0.1;
+      mtop->ffparams.cmap_grid.cmapdata     = NULL;
+  }
+         
+  if (file_version >= 57) {
+    do_groups(fio, &mtop->groups,bRead,&(mtop->symtab),file_version);
+  }
+
+  if (file_version < 57) {
+    do_block(fio, &mtop->moltype[0].cgs,bRead,file_version);
+    if (bRead && gmx_debug_at) {
+      pr_block(debug,0,"cgs",&mtop->moltype[0].cgs,TRUE);
+    }
+    do_block(fio, &mtop->mols,bRead,file_version);
+    /* Add the posres coordinates to the molblock */
+    add_posres_molblock(mtop);
+  }
+  if (bRead) {
+    if (file_version >= 57) {
+      mtop->mols = mtop_mols(mtop);
+    }
+    if (gmx_debug_at) { 
+      pr_block(debug,0,"mols",&mtop->mols,TRUE);
+    }
+  }
+
+  if (file_version < 51) {
+    /* Here used to be the shake blocks */
+    do_blocka(fio, &dumb,bRead,file_version);
+    if (dumb.nr > 0)
+      sfree(dumb.index);
+    if (dumb.nra > 0)
+      sfree(dumb.a);
+  }
+
+  if (bRead) {
+    close_symtab(&(mtop->symtab));
+  }
+}
+
+/* If TopOnlyOK is TRUE then we can read even future versions
+ * of tpx files, provided the file_generation hasn't changed.
+ * If it is FALSE, we need the inputrecord too, and bail out
+ * if the file is newer than the program.
+ * 
+ * The version and generation if the topology (see top of this file)
+ * are returned in the two last arguments.
+ * 
+ * If possible, we will read the inputrec even when TopOnlyOK is TRUE.
+ */
+static void do_tpxheader(t_fileio *fio,gmx_bool bRead,t_tpxheader *tpx, 
+                         gmx_bool TopOnlyOK, int *file_version, 
+                         int *file_generation)
+{
+  char  buf[STRLEN];
+  gmx_bool  bDouble;
+  int   precision;
+  int   fver,fgen;
+  int   idum=0;
+  real  rdum=0;
+
+  gmx_fio_checktype(fio);
+  gmx_fio_setdebug(fio,bDebugMode());
+  
+  /* NEW! XDR tpb file */
+  precision = sizeof(real);
+  if (bRead) {
+    gmx_fio_do_string(fio,buf);
+    if (strncmp(buf,"VERSION",7))
+      gmx_fatal(FARGS,"Can not read file %s,\n"
+                 "             this file is from a Gromacs version which is older than 2.0\n"
+                 "             Make a new one with grompp or use a gro or pdb file, if possible",
+                 gmx_fio_getname(fio));
+    gmx_fio_do_int(fio,precision);
+    bDouble = (precision == sizeof(double));
+    if ((precision != sizeof(float)) && !bDouble)
+      gmx_fatal(FARGS,"Unknown precision in file %s: real is %d bytes "
+                 "instead of %d or %d",
+                 gmx_fio_getname(fio),precision,sizeof(float),sizeof(double));
+    gmx_fio_setprecision(fio,bDouble);
+    fprintf(stderr,"Reading file %s, %s (%s precision)\n",
+           gmx_fio_getname(fio),buf,bDouble ? "double" : "single");
+  }
+  else {
+    gmx_fio_write_string(fio,GromacsVersion());
+    bDouble = (precision == sizeof(double));
+    gmx_fio_setprecision(fio,bDouble);
+    gmx_fio_do_int(fio,precision);
+    fver = tpx_version;
+    fgen = tpx_generation;
+  }
+  
+  /* Check versions! */
+  gmx_fio_do_int(fio,fver);
+  
+  if(fver>=26)
+    gmx_fio_do_int(fio,fgen);
+  else
+    fgen=0;
+  if(file_version!=NULL)
+    *file_version = fver;
+  if(file_generation!=NULL)
+    *file_generation = fgen;
+   
+  
+  if ((fver <= tpx_incompatible_version) ||
+      ((fver > tpx_version) && !TopOnlyOK) ||
+      (fgen > tpx_generation))
+    gmx_fatal(FARGS,"reading tpx file (%s) version %d with version %d program",
+               gmx_fio_getname(fio),fver,tpx_version);
+  
+  do_section(fio,eitemHEADER,bRead);
+  gmx_fio_do_int(fio,tpx->natoms);
+  if (fver >= 28)
+    gmx_fio_do_int(fio,tpx->ngtc);
+  else
+    tpx->ngtc = 0;
+  if (fver < 62) {
+    gmx_fio_do_int(fio,idum);
+    gmx_fio_do_real(fio,rdum);
+  }
+  gmx_fio_do_real(fio,tpx->lambda);
+  gmx_fio_do_int(fio,tpx->bIr);
+  gmx_fio_do_int(fio,tpx->bTop);
+  gmx_fio_do_int(fio,tpx->bX);
+  gmx_fio_do_int(fio,tpx->bV);
+  gmx_fio_do_int(fio,tpx->bF);
+  gmx_fio_do_int(fio,tpx->bBox);
+
+  if((fgen > tpx_generation)) {
+    /* This can only happen if TopOnlyOK=TRUE */
+    tpx->bIr=FALSE;
+  }
+}
+
+static int do_tpx(t_fileio *fio, gmx_bool bRead,
+                 t_inputrec *ir,t_state *state,rvec *f,gmx_mtop_t *mtop,
+                 gmx_bool bXVallocated)
+{
+  t_tpxheader tpx;
+  t_inputrec  dum_ir;
+  gmx_mtop_t  dum_top;
+  gmx_bool        TopOnlyOK,bDum=TRUE;
+  int         file_version,file_generation;
+  int         i;
+  rvec        *xptr,*vptr;
+  int         ePBC;
+  gmx_bool        bPeriodicMols;
+
+  if (!bRead) {
+    tpx.natoms = state->natoms;
+    tpx.ngtc   = state->ngtc;
+    tpx.lambda = state->lambda;
+    tpx.bIr  = (ir       != NULL);
+    tpx.bTop = (mtop     != NULL);
+    tpx.bX   = (state->x != NULL);
+    tpx.bV   = (state->v != NULL);
+    tpx.bF   = (f        != NULL);
+    tpx.bBox = TRUE;
+  }
+  
+  TopOnlyOK = (ir==NULL);
+  
+  do_tpxheader(fio,bRead,&tpx,TopOnlyOK,&file_version,&file_generation);
+
+  if (bRead) {
+    state->flags  = 0;
+    state->lambda = tpx.lambda;
+    /* The init_state calls initialize the Nose-Hoover xi integrals to zero */
+    if (bXVallocated) {
+      xptr = state->x;
+      vptr = state->v;
+      init_state(state,0,tpx.ngtc,0,0);  /* nose-hoover chains */ /* eventually, need to add nnhpres here? */
+      state->natoms = tpx.natoms; 
+      state->nalloc = tpx.natoms; 
+      state->x = xptr;
+      state->v = vptr;
+    } else {
+      init_state(state,tpx.natoms,tpx.ngtc,0,0);  /* nose-hoover chains */
+    }
+  }
+
+#define do_test(fio,b,p) if (bRead && (p!=NULL) && !b) gmx_fatal(FARGS,"No %s in %s",#p,gmx_fio_getname(fio)) 
+
+  do_test(fio,tpx.bBox,state->box);
+  do_section(fio,eitemBOX,bRead);
+  if (tpx.bBox) {
+    gmx_fio_ndo_rvec(fio,state->box,DIM);
+    if (file_version >= 51) {
+      gmx_fio_ndo_rvec(fio,state->box_rel,DIM);
+    } else {
+      /* We initialize box_rel after reading the inputrec */
+      clear_mat(state->box_rel);
+    }
+    if (file_version >= 28) {
+      gmx_fio_ndo_rvec(fio,state->boxv,DIM);
+      if (file_version < 56) {
+       matrix mdum;
+       gmx_fio_ndo_rvec(fio,mdum,DIM);
+      }
+    }
+  }
+  
+  if (state->ngtc > 0 && file_version >= 28) {
+    real *dumv;
+    /*ndo_double(state->nosehoover_xi,state->ngtc,bDum);*/
+    /*ndo_double(state->nosehoover_vxi,state->ngtc,bDum);*/
+    /*ndo_double(state->therm_integral,state->ngtc,bDum);*/
+    snew(dumv,state->ngtc);
+    if (file_version < 69) {
+      bDum=gmx_fio_ndo_real(fio,dumv,state->ngtc);
+    }
+    /* These used to be the Berendsen tcoupl_lambda's */
+    bDum=gmx_fio_ndo_real(fio,dumv,state->ngtc);
+    sfree(dumv);
+  }
+
+  /* Prior to tpx version 26, the inputrec was here.
+   * I moved it to enable partial forward-compatibility
+   * for analysis/viewer programs.
+   */
+  if(file_version<26) {
+    do_test(fio,tpx.bIr,ir);
+    do_section(fio,eitemIR,bRead);
+    if (tpx.bIr) {
+      if (ir) {
+       do_inputrec(fio, ir,bRead,file_version,
+                    mtop ? &mtop->ffparams.fudgeQQ : NULL);
+       if (bRead && debug) 
+         pr_inputrec(debug,0,"inputrec",ir,FALSE);
+      }
+      else {
+       do_inputrec(fio, &dum_ir,bRead,file_version,
+                    mtop ? &mtop->ffparams.fudgeQQ :NULL);
+       if (bRead && debug) 
+         pr_inputrec(debug,0,"inputrec",&dum_ir,FALSE);
+       done_inputrec(&dum_ir);
+      }
+      
+    }
+  }
+  
+  do_test(fio,tpx.bTop,mtop);
+  do_section(fio,eitemTOP,bRead);
+  if (tpx.bTop) {
+    if (mtop) {
+      do_mtop(fio,mtop,bRead, file_version);
+    } else {
+      do_mtop(fio,&dum_top,bRead,file_version);
+      done_mtop(&dum_top,TRUE);
+    }
+  }
+  do_test(fio,tpx.bX,state->x);  
+  do_section(fio,eitemX,bRead);
+  if (tpx.bX) {
+    if (bRead) {
+      state->flags |= (1<<estX);
+    }
+    gmx_fio_ndo_rvec(fio,state->x,state->natoms);
+  }
+  
+  do_test(fio,tpx.bV,state->v);
+  do_section(fio,eitemV,bRead);
+  if (tpx.bV) {
+    if (bRead) {
+      state->flags |= (1<<estV);
+    }
+    gmx_fio_ndo_rvec(fio,state->v,state->natoms);
+  }
+
+  do_test(fio,tpx.bF,f);
+  do_section(fio,eitemF,bRead);
+  if (tpx.bF) gmx_fio_ndo_rvec(fio,f,state->natoms);
+
+  /* Starting with tpx version 26, we have the inputrec
+   * at the end of the file, so we can ignore it 
+   * if the file is never than the software (but still the
+   * same generation - see comments at the top of this file.
+   *
+   * 
+   */
+  ePBC = -1;
+  bPeriodicMols = FALSE;
+  if (file_version >= 26) {
+    do_test(fio,tpx.bIr,ir);
+    do_section(fio,eitemIR,bRead);
+    if (tpx.bIr) {
+      if (file_version >= 53) {
+       /* Removed the pbc info from do_inputrec, since we always want it */
+       if (!bRead) {
+         ePBC          = ir->ePBC;
+         bPeriodicMols = ir->bPeriodicMols;
+       }
+       gmx_fio_do_int(fio,ePBC);
+       gmx_fio_do_gmx_bool(fio,bPeriodicMols);
+      }
+      if (file_generation <= tpx_generation && ir) {
+       do_inputrec(fio, ir,bRead,file_version,mtop ? &mtop->ffparams.fudgeQQ : NULL);
+       if (bRead && debug) 
+         pr_inputrec(debug,0,"inputrec",ir,FALSE);
+       if (file_version < 51)
+         set_box_rel(ir,state);
+       if (file_version < 53) {
+         ePBC          = ir->ePBC;
+         bPeriodicMols = ir->bPeriodicMols;
+       }
+      }
+      if (bRead && ir && file_version >= 53) {
+       /* We need to do this after do_inputrec, since that initializes ir */
+       ir->ePBC          = ePBC;
+       ir->bPeriodicMols = bPeriodicMols;
+      }
+    }
+  }
+
+    if (bRead)
+    {
+        if (tpx.bIr && ir)
+        {
+            if (state->ngtc == 0)
+            {
+                /* Reading old version without tcoupl state data: set it */
+                init_gtc_state(state,ir->opts.ngtc,0,ir->opts.nhchainlength);
+            }
+            if (tpx.bTop && mtop)
+            {
+                if (file_version < 57)
+                {
+                    if (mtop->moltype[0].ilist[F_DISRES].nr > 0)
+                    {
+                        ir->eDisre = edrSimple;
+                    }
+                    else
+                    {
+                        ir->eDisre = edrNone;
+                    }
+                }
+                set_disres_npair(mtop);
+            }
+        }
+
+        if (tpx.bTop && mtop)
+        {
+            gmx_mtop_finalize(mtop);
+        }
+
+        if (file_version >= 57)
+        {
+            char *env;
+            int  ienv;
+            env = getenv("GMX_NOCHARGEGROUPS");
+            if (env != NULL)
+            {
+                sscanf(env,"%d",&ienv);
+                fprintf(stderr,"\nFound env.var. GMX_NOCHARGEGROUPS = %d\n",
+                        ienv);
+                if (ienv > 0)
+                {
+                    fprintf(stderr,
+                            "Will make single atomic charge groups in non-solvent%s\n",
+                            ienv > 1 ? " and solvent" : "");
+                    gmx_mtop_make_atomic_charge_groups(mtop,ienv==1);
+                }
+                fprintf(stderr,"\n");
+            }
+        }
+    }
+
+    return ePBC;
+}
+
+/************************************************************
+ *
+ *  The following routines are the exported ones
+ *
+ ************************************************************/
+
+t_fileio *open_tpx(const char *fn,const char *mode)
+{
+  return gmx_fio_open(fn,mode);
+}    
+void close_tpx(t_fileio *fio)
+{
+  gmx_fio_close(fio);
+}
+
+void read_tpxheader(const char *fn, t_tpxheader *tpx, gmx_bool TopOnlyOK,
+                    int *file_version, int *file_generation)
+{
+  t_fileio *fio;
+
+  fio = open_tpx(fn,"r");
+  do_tpxheader(fio,TRUE,tpx,TopOnlyOK,file_version,file_generation);
+  close_tpx(fio);
+}
+
+void write_tpx_state(const char *fn,
+                    t_inputrec *ir,t_state *state,gmx_mtop_t *mtop)
+{
+  t_fileio *fio;
+
+  fio = open_tpx(fn,"w");
+  do_tpx(fio,FALSE,ir,state,NULL,mtop,FALSE);
+  close_tpx(fio);
+}
+
+void read_tpx_state(const char *fn,
+                   t_inputrec *ir,t_state *state,rvec *f,gmx_mtop_t *mtop)
+{
+  t_fileio *fio;
+       
+  fio = open_tpx(fn,"r");
+  do_tpx(fio,TRUE,ir,state,f,mtop,FALSE);
+  close_tpx(fio);
+}
+
+int read_tpx(const char *fn,
+            t_inputrec *ir, matrix box,int *natoms,
+            rvec *x,rvec *v,rvec *f,gmx_mtop_t *mtop)
+{
+  t_fileio *fio;
+  t_state state;
+  int ePBC;
+
+  state.x = x;
+  state.v = v;
+  fio = open_tpx(fn,"r");
+  ePBC = do_tpx(fio,TRUE,ir,&state,f,mtop,TRUE);
+  close_tpx(fio);
+  *natoms = state.natoms;
+  if (box) 
+    copy_mat(state.box,box);
+  state.x = NULL;
+  state.v = NULL;
+  done_state(&state);
+
+  return ePBC;
+}
+
+int read_tpx_top(const char *fn,
+                t_inputrec *ir, matrix box,int *natoms,
+                rvec *x,rvec *v,rvec *f,t_topology *top)
+{
+  gmx_mtop_t mtop;
+  t_topology *ltop;
+  int ePBC;
+
+  ePBC = read_tpx(fn,ir,box,natoms,x,v,f,&mtop);
+  
+  *top = gmx_mtop_t_to_t_topology(&mtop);
+
+  return ePBC;
+}
+
+gmx_bool fn2bTPX(const char *file)
+{
+  switch (fn2ftp(file)) {
+  case efTPR:
+  case efTPB:
+  case efTPA:
+    return TRUE;
+  default:
+    return FALSE;
+  }
+}
+
+gmx_bool read_tps_conf(const char *infile,char *title,t_topology *top,int *ePBC,
+                  rvec **x,rvec **v,matrix box,gmx_bool bMass)
+{
+  t_tpxheader  header;
+  int          natoms,i,version,generation;
+  gmx_bool         bTop,bXNULL;
+  gmx_mtop_t   *mtop;
+  t_topology   *topconv;
+  gmx_atomprop_t aps;
+  
+  bTop = fn2bTPX(infile);
+  *ePBC = -1;
+  if (bTop) {
+    read_tpxheader(infile,&header,TRUE,&version,&generation);
+    if (x)
+      snew(*x,header.natoms);
+    if (v)
+      snew(*v,header.natoms);
+    snew(mtop,1);
+    *ePBC = read_tpx(infile,NULL,box,&natoms,
+                    (x==NULL) ? NULL : *x,(v==NULL) ? NULL : *v,NULL,mtop);
+    *top = gmx_mtop_t_to_t_topology(mtop);
+    sfree(mtop);
+    strcpy(title,*top->name);
+    tpx_make_chain_identifiers(&top->atoms,&top->mols);
+  }
+  else {
+    get_stx_coordnum(infile,&natoms);
+    init_t_atoms(&top->atoms,natoms,FALSE);
+    bXNULL = (x == NULL);
+    snew(*x,natoms);
+    if (v)
+      snew(*v,natoms);
+    read_stx_conf(infile,title,&top->atoms,*x,(v==NULL) ? NULL : *v,ePBC,box);
+    if (bXNULL) {
+      sfree(*x);
+      x = NULL;
+    }
+    if (bMass) {
+      aps = gmx_atomprop_init();
+      for(i=0; (i<natoms); i++)
+       if (!gmx_atomprop_query(aps,epropMass,
+                               *top->atoms.resinfo[top->atoms.atom[i].resind].name,
+                               *top->atoms.atomname[i],
+                               &(top->atoms.atom[i].m))) {
+         if (debug) 
+           fprintf(debug,"Can not find mass for atom %s %d %s, setting to 1\n",
+                   *top->atoms.resinfo[top->atoms.atom[i].resind].name,
+                   top->atoms.resinfo[top->atoms.atom[i].resind].nr,
+                   *top->atoms.atomname[i]);
+       }
+      gmx_atomprop_destroy(aps);
+    }
+    top->idef.ntypes=-1;
+  }
+
+  return bTop;
+}
diff --git a/src/gromacs/gmxlib/txtdump.c b/src/gromacs/gmxlib/txtdump.c
new file mode 100644 (file)
index 0000000..8cc5c80
--- /dev/null
@@ -0,0 +1,1499 @@
+/* -*- 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
+ * 
+ *                        VERSION 3.2.0
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * 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.
+
+ * 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:
+ * GROningen Mixture of Alchemy and Childrens' Stories
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/* This file is completely threadsafe - please keep it that way! */
+#ifdef GMX_THREADS
+#include <thread_mpi.h>
+#endif
+
+
+#include <stdio.h>
+#include "smalloc.h"
+#include "typedefs.h"
+#include "names.h"
+#include "txtdump.h"
+#include "string2.h"
+#include "vec.h"
+
+
+int pr_indent(FILE *fp,int n)
+{
+  int i;
+
+  for (i=0; i<n; i++) (void) fprintf(fp," ");
+  return n;
+}
+
+int available(FILE *fp,void *p,int indent,const char *title)
+{
+  if (!p) {
+    if (indent > 0)
+      pr_indent(fp,indent);
+    (void) fprintf(fp,"%s: not available\n",title);
+  }
+  return (p!=NULL);
+}
+
+int pr_title(FILE *fp,int indent,const char *title)
+{
+  (void) pr_indent(fp,indent);
+  (void) fprintf(fp,"%s:\n",title);
+  return (indent+INDENT);
+}
+
+int pr_title_n(FILE *fp,int indent,const char *title,int n)
+{
+  (void) pr_indent(fp,indent);
+  (void) fprintf(fp,"%s (%d):\n",title,n);
+  return (indent+INDENT);
+}
+
+int pr_title_nxn(FILE *fp,int indent,const char *title,int n1,int n2)
+{
+  (void) pr_indent(fp,indent);
+  (void) fprintf(fp,"%s (%dx%d):\n",title,n1,n2);
+  return (indent+INDENT);
+}
+
+void pr_ivec(FILE *fp,int indent,const char *title,int vec[],int n, gmx_bool bShowNumbers)
+{
+  int i;
+
+  if (available(fp,vec,indent,title))
+    {
+      indent=pr_title_n(fp,indent,title,n);
+      for (i=0; i<n; i++)
+        {
+          (void) pr_indent(fp,indent);
+          (void) fprintf(fp,"%s[%d]=%d\n",title,bShowNumbers?i:-1,vec[i]);
+        }
+    }
+}
+
+void pr_ivec_block(FILE *fp,int indent,const char *title,int vec[],int n, gmx_bool bShowNumbers)
+{
+    int i,j;
+    
+    if (available(fp,vec,indent,title))
+    {
+        indent=pr_title_n(fp,indent,title,n);
+        i = 0;
+        while (i < n)
+        {
+            j = i+1;
+            while (j < n && vec[j] == vec[j-1]+1)
+            {
+                j++;
+            }
+            /* Print consecutive groups of 3 or more as blocks */
+            if (j - i < 3)
+            {
+                while(i < j)
+                {
+                    (void) pr_indent(fp,indent);
+                    (void) fprintf(fp,"%s[%d]=%d\n",
+                                   title,bShowNumbers?i:-1,vec[i]);
+                    i++;
+                }
+            }
+            else
+            {
+                (void) pr_indent(fp,indent);
+                (void) fprintf(fp,"%s[%d,...,%d] = {%d,...,%d}\n",
+                               title,
+                               bShowNumbers?i:-1,
+                               bShowNumbers?j-1:-1,
+                               vec[i],vec[j-1]); 
+                i = j;
+            }
+        }
+    }
+}
+
+void pr_bvec(FILE *fp,int indent,const char *title,gmx_bool vec[],int n, gmx_bool bShowNumbers)
+{
+  int i;
+
+  if (available(fp,vec,indent,title))
+    {
+      indent=pr_title_n(fp,indent,title,n);
+      for (i=0; i<n; i++)
+        {
+          (void) pr_indent(fp,indent);
+          (void) fprintf(fp,"%s[%d]=%s\n",title,bShowNumbers?i:-1,
+                        BOOL(vec[i]));
+        }
+    }
+}
+
+void pr_ivecs(FILE *fp,int indent,const char *title,ivec vec[],int n, gmx_bool bShowNumbers)
+{
+  int i,j;
+
+  if (available(fp,vec,indent,title))
+    {  
+      indent=pr_title_nxn(fp,indent,title,n,DIM);
+      for (i=0; i<n; i++)
+        {
+          (void) pr_indent(fp,indent);
+          (void) fprintf(fp,"%s[%d]={",title,bShowNumbers?i:-1);
+          for (j=0; j<DIM; j++)
+            {
+              if (j!=0) (void) fprintf(fp,", ");
+              fprintf(fp,"%d",vec[i][j]);
+            }
+          (void) fprintf(fp,"}\n");
+        }
+    }
+}
+
+void pr_rvec(FILE *fp,int indent,const char *title,real vec[],int n, gmx_bool bShowNumbers)
+{
+  int i;
+
+  if (available(fp,vec,indent,title))
+    {  
+      indent=pr_title_n(fp,indent,title,n);
+      for (i=0; i<n; i++)
+        {
+          pr_indent(fp,indent);
+          fprintf(fp,"%s[%d]=%12.5e\n",title,bShowNumbers?i:-1,vec[i]);
+        }
+    }
+}
+
+void pr_dvec(FILE *fp,int indent,const char *title,double vec[],int n, gmx_bool bShowNumbers)
+{
+       int i;
+       
+       if (available(fp,vec,indent,title))
+    {  
+               indent=pr_title_n(fp,indent,title,n);
+               for (i=0; i<n; i++)
+        {
+                       pr_indent(fp,indent);
+                       fprintf(fp,"%s[%d]=%12.5e\n",title,bShowNumbers?i:-1,vec[i]);
+        }
+    }
+}
+
+
+/*
+void pr_mat(FILE *fp,int indent,char *title,matrix m)
+{
+  int i,j;
+  
+  if (available(fp,m,indent,title)) {  
+    indent=pr_title_n(fp,indent,title,n);
+    for(i=0; i<n; i++) {
+      pr_indent(fp,indent);
+      fprintf(fp,"%s[%d]=%12.5e %12.5e %12.5e\n",
+             title,bShowNumbers?i:-1,m[i][XX],m[i][YY],m[i][ZZ]);
+    }
+  }
+}
+*/
+
+void pr_rvecs_len(FILE *fp,int indent,const char *title,rvec vec[],int n)
+{
+  int i,j;
+
+  if (available(fp,vec,indent,title)) {  
+    indent=pr_title_nxn(fp,indent,title,n,DIM);
+    for (i=0; i<n; i++) {
+      (void) pr_indent(fp,indent);
+      (void) fprintf(fp,"%s[%5d]={",title,i);
+      for (j=0; j<DIM; j++) {
+       if (j != 0) 
+         (void) fprintf(fp,", ");
+       (void) fprintf(fp,"%12.5e",vec[i][j]);
+      }
+      (void) fprintf(fp,"} len=%12.5e\n",norm(vec[i]));
+    }
+  }
+}
+
+void pr_rvecs(FILE *fp,int indent,const char *title,rvec vec[],int n)
+{
+  const char *fshort = "%12.5e";
+  const char *flong  = "%15.8e";
+  const char *format;
+  int i,j;
+
+  if (getenv("LONGFORMAT") != NULL)
+    format = flong;
+  else
+    format = fshort;
+    
+  if (available(fp,vec,indent,title)) {  
+    indent=pr_title_nxn(fp,indent,title,n,DIM);
+    for (i=0; i<n; i++) {
+      (void) pr_indent(fp,indent);
+      (void) fprintf(fp,"%s[%5d]={",title,i);
+      for (j=0; j<DIM; j++) {
+       if (j != 0) 
+         (void) fprintf(fp,", ");
+       (void) fprintf(fp,format,vec[i][j]);
+      }
+      (void) fprintf(fp,"}\n");
+    }
+  }
+}
+
+
+void pr_reals(FILE *fp,int indent,const char *title,real *vec,int n)
+{
+  int i;
+    
+  if (available(fp,vec,indent,title)) {  
+    (void) pr_indent(fp,indent);
+    (void) fprintf(fp,"%s:\t",title);
+    for(i=0; i<n; i++)
+      fprintf(fp,"  %10g",vec[i]);
+    (void) fprintf(fp,"\n");
+  }
+}
+
+void pr_doubles(FILE *fp,int indent,const char *title,double *vec,int n)
+{
+  int i;
+    
+  if (available(fp,vec,indent,title)) {  
+    (void) pr_indent(fp,indent);
+    (void) fprintf(fp,"%s:\t",title);
+    for(i=0; i<n; i++)
+      fprintf(fp,"  %10g",vec[i]);
+    (void) fprintf(fp,"\n");
+  }
+}
+
+static void pr_int(FILE *fp,int indent,const char *title,int i)
+{
+  pr_indent(fp,indent);
+  fprintf(fp,"%-20s = %d\n",title,i);
+}
+
+static void pr_gmx_large_int(FILE *fp,int indent,const char *title,gmx_large_int_t i)
+{
+  char buf[STEPSTRSIZE];
+
+  pr_indent(fp,indent);
+  fprintf(fp,"%-20s = %s\n",title,gmx_step_str(i,buf));
+}
+
+static void pr_real(FILE *fp,int indent,const char *title,real r)
+{
+  pr_indent(fp,indent);
+  fprintf(fp,"%-20s = %g\n",title,r);
+}
+
+static void pr_double(FILE *fp,int indent,const char *title,double d)
+{
+  pr_indent(fp,indent);
+  fprintf(fp,"%-20s = %g\n",title,d);
+}
+
+static void pr_str(FILE *fp,int indent,const char *title,const char *s)
+{
+  pr_indent(fp,indent);
+  fprintf(fp,"%-20s = %s\n",title,s);
+}
+
+void pr_qm_opts(FILE *fp,int indent,const char *title,t_grpopts *opts)
+{
+  int i,m,j;
+
+  fprintf(fp,"%s:\n",title);
+  
+  pr_int(fp,indent,"ngQM",opts->ngQM);
+  if (opts->ngQM > 0) {
+    pr_ivec(fp,indent,"QMmethod",opts->QMmethod,opts->ngQM,FALSE);
+    pr_ivec(fp,indent,"QMbasis",opts->QMbasis,opts->ngQM,FALSE);
+    pr_ivec(fp,indent,"QMcharge",opts->QMcharge,opts->ngQM,FALSE);
+    pr_ivec(fp,indent,"QMmult",opts->QMmult,opts->ngQM,FALSE);
+    pr_bvec(fp,indent,"bSH",opts->bSH,opts->ngQM,FALSE);
+    pr_ivec(fp,indent,"CASorbitals",opts->CASorbitals,opts->ngQM,FALSE);
+    pr_ivec(fp,indent,"CASelectrons",opts->CASelectrons,opts->ngQM,FALSE);
+    pr_rvec(fp,indent,"SAon",opts->SAon,opts->ngQM,FALSE);
+    pr_rvec(fp,indent,"SAon",opts->SAon,opts->ngQM,FALSE);
+    pr_ivec(fp,indent,"SAsteps",opts->SAsteps,opts->ngQM,FALSE);
+    pr_bvec(fp,indent,"bOPT",opts->bOPT,opts->ngQM,FALSE);
+    pr_bvec(fp,indent,"bTS",opts->bTS,opts->ngQM,FALSE);
+  }
+}
+
+static void pr_grp_opts(FILE *out,int indent,const char *title,t_grpopts *opts,
+                       gmx_bool bMDPformat)
+{
+  int i,m,j;
+
+  if (!bMDPformat)
+    fprintf(out,"%s:\n",title);
+  
+  pr_indent(out,indent);
+  fprintf(out,"nrdf%s",bMDPformat ? " = " : ":");
+  for(i=0; (i<opts->ngtc); i++)
+    fprintf(out,"  %10g",opts->nrdf[i]);
+  fprintf(out,"\n");
+  
+  pr_indent(out,indent);
+  fprintf(out,"ref_t%s",bMDPformat ? " = " : ":");
+  for(i=0; (i<opts->ngtc); i++)
+    fprintf(out,"  %10g",opts->ref_t[i]);
+  fprintf(out,"\n");
+
+  pr_indent(out,indent);
+  fprintf(out,"tau_t%s",bMDPformat ? " = " : ":");
+  for(i=0; (i<opts->ngtc); i++)
+    fprintf(out,"  %10g",opts->tau_t[i]);
+  fprintf(out,"\n");  
+  
+  /* Pretty-print the simulated annealing info */
+  fprintf(out,"anneal%s",bMDPformat ? " = " : ":");
+  for(i=0; (i<opts->ngtc); i++)
+    fprintf(out,"  %10s",EANNEAL(opts->annealing[i]));
+  fprintf(out,"\n");  
+  fprintf(out,"ann_npoints%s",bMDPformat ? " = " : ":");
+  for(i=0; (i<opts->ngtc); i++)
+    fprintf(out,"  %10d",opts->anneal_npoints[i]);
+  fprintf(out,"\n");  
+  for(i=0; (i<opts->ngtc); i++) {
+    if(opts->anneal_npoints[i]>0) {
+      fprintf(out,"ann. times [%d]:\t",i);
+      for(j=0; (j<opts->anneal_npoints[i]); j++)
+       fprintf(out,"  %10.1f",opts->anneal_time[i][j]);
+      fprintf(out,"\n");  
+      fprintf(out,"ann. temps [%d]:\t",i);
+      for(j=0; (j<opts->anneal_npoints[i]); j++)
+       fprintf(out,"  %10.1f",opts->anneal_temp[i][j]);
+      fprintf(out,"\n");  
+    }
+  }
+  
+  pr_indent(out,indent);
+  fprintf(out,"acc:\t");
+  for(i=0; (i<opts->ngacc); i++)
+    for(m=0; (m<DIM); m++)
+      fprintf(out,"  %10g",opts->acc[i][m]);
+  fprintf(out,"\n");
+
+  pr_indent(out,indent);
+  fprintf(out,"nfreeze:");
+  for(i=0; (i<opts->ngfrz); i++)
+    for(m=0; (m<DIM); m++)
+      fprintf(out,"  %10s",opts->nFreeze[i][m] ? "Y" : "N");
+  fprintf(out,"\n");
+
+
+  for(i=0; (i<opts->ngener); i++) {
+    pr_indent(out,indent);
+    fprintf(out,"energygrp_flags[%3d]:",i);
+    for(m=0; (m<opts->ngener); m++)
+      fprintf(out," %d",opts->egp_flags[opts->ngener*i+m]);
+    fprintf(out,"\n");
+  }
+
+  fflush(out);
+}
+
+static void pr_matrix(FILE *fp,int indent,const char *title,rvec *m,
+                     gmx_bool bMDPformat)
+{
+  if (bMDPformat)
+    fprintf(fp,"%-10s    = %g %g %g %g %g %g\n",title,
+           m[XX][XX],m[YY][YY],m[ZZ][ZZ],m[XX][YY],m[XX][ZZ],m[YY][ZZ]);
+  else
+    pr_rvecs(fp,indent,title,m,DIM);
+}
+
+static void pr_cosine(FILE *fp,int indent,const char *title,t_cosines *cos,
+                     gmx_bool bMDPformat)
+{
+  int j;
+  
+  if (bMDPformat) {
+    fprintf(fp,"%s = %d\n",title,cos->n);
+  }
+  else {
+    indent=pr_title(fp,indent,title);
+    (void) pr_indent(fp,indent);
+    fprintf(fp,"n = %d\n",cos->n);
+    if (cos->n > 0) {
+      (void) pr_indent(fp,indent+2);
+      fprintf(fp,"a =");
+      for(j=0; (j<cos->n); j++)
+       fprintf(fp," %e",cos->a[j]);
+      fprintf(fp,"\n");
+      (void) pr_indent(fp,indent+2);
+      fprintf(fp,"phi =");
+      for(j=0; (j<cos->n); j++)
+       fprintf(fp," %e",cos->phi[j]);
+      fprintf(fp,"\n");
+    }
+  }
+}
+
+#define PS(t,s) pr_str(fp,indent,t,s)
+#define PI(t,s) pr_int(fp,indent,t,s)
+#define PSTEP(t,s) pr_gmx_large_int(fp,indent,t,s)
+#define PR(t,s) pr_real(fp,indent,t,s)
+#define PD(t,s) pr_double(fp,indent,t,s)
+
+static void pr_pullgrp(FILE *fp,int indent,int g,t_pullgrp *pg)
+{
+  pr_indent(fp,indent);
+  fprintf(fp,"pull_group %d:\n",g);
+  indent += 2;
+  pr_ivec_block(fp,indent,"atom",pg->ind,pg->nat,TRUE);
+  pr_rvec(fp,indent,"weight",pg->weight,pg->nweight,TRUE);
+  PI("pbcatom",pg->pbcatom);
+  pr_rvec(fp,indent,"vec",pg->vec,DIM,TRUE);
+  pr_rvec(fp,indent,"init",pg->init,DIM,TRUE);
+  PR("rate",pg->rate);
+  PR("k",pg->k);
+  PR("kB",pg->kB);
+}
+
+static void pr_pull(FILE *fp,int indent,t_pull *pull)
+{
+  int g;
+
+  PS("pull_geometry",EPULLGEOM(pull->eGeom));
+  pr_ivec(fp,indent,"pull_dim",pull->dim,DIM,TRUE);
+  PR("pull_r1",pull->cyl_r1);
+  PR("pull_r0",pull->cyl_r0);
+  PR("pull_constr_tol",pull->constr_tol);
+  PI("pull_nstxout",pull->nstxout);
+  PI("pull_nstfout",pull->nstfout);
+  PI("pull_ngrp",pull->ngrp);
+  for(g=0; g<pull->ngrp+1; g++)
+    pr_pullgrp(fp,indent,g,&pull->grp[g]);
+}
+
+static void pr_rotgrp(FILE *fp,int indent,int g,t_rotgrp *rotg)
+{
+  pr_indent(fp,indent);
+  fprintf(fp,"rotation_group %d:\n",g);
+  indent += 2;
+  PS("type",EROTGEOM(rotg->eType));
+  PS("massw",BOOL(rotg->bMassW));
+  pr_ivec_block(fp,indent,"atom",rotg->ind,rotg->nat,TRUE);
+  pr_rvecs(fp,indent,"x_ref",rotg->x_ref,rotg->nat);
+  pr_rvec(fp,indent,"vec",rotg->vec,DIM,TRUE);
+  pr_rvec(fp,indent,"pivot",rotg->pivot,DIM,TRUE);
+  PR("rate",rotg->rate);
+  PR("k",rotg->k);
+  PR("slab_dist",rotg->slab_dist);
+  PR("min_gaussian",rotg->min_gaussian);
+  PR("epsilon",rotg->eps);
+  PS("fit_method",EROTFIT(rotg->eFittype));
+}
+
+static void pr_rot(FILE *fp,int indent,t_rot *rot)
+{
+  int g;
+
+  PI("rot_nstrout",rot->nstrout);
+  PI("rot_nstsout",rot->nstsout);
+  PI("rot_ngrp",rot->ngrp);
+  for(g=0; g<rot->ngrp; g++)
+    pr_rotgrp(fp,indent,g,&rot->grp[g]);
+}
+
+void pr_inputrec(FILE *fp,int indent,const char *title,t_inputrec *ir,
+                 gmx_bool bMDPformat)
+{
+  const char *infbuf="inf";
+  int  i;
+  
+  if (available(fp,ir,indent,title)) {
+    if (!bMDPformat)
+      indent=pr_title(fp,indent,title);
+    PS("integrator",EI(ir->eI));
+    PSTEP("nsteps",ir->nsteps);
+    PSTEP("init_step",ir->init_step);
+    PS("ns_type",ENS(ir->ns_type));
+    PI("nstlist",ir->nstlist);
+    PI("ndelta",ir->ndelta);
+    PI("nstcomm",ir->nstcomm);
+    PS("comm_mode",ECOM(ir->comm_mode));
+    PI("nstlog",ir->nstlog);
+    PI("nstxout",ir->nstxout);
+    PI("nstvout",ir->nstvout);
+    PI("nstfout",ir->nstfout);
+    PI("nstcalcenergy",ir->nstcalcenergy);
+    PI("nstenergy",ir->nstenergy);
+    PI("nstxtcout",ir->nstxtcout);
+    PR("init_t",ir->init_t);
+    PR("delta_t",ir->delta_t);
+    
+    PR("xtcprec",ir->xtcprec);
+    PI("nkx",ir->nkx);
+    PI("nky",ir->nky);
+    PI("nkz",ir->nkz);
+    PI("pme_order",ir->pme_order);
+    PR("ewald_rtol",ir->ewald_rtol);
+    PR("ewald_geometry",ir->ewald_geometry);
+    PR("epsilon_surface",ir->epsilon_surface);
+    PS("optimize_fft",BOOL(ir->bOptFFT));
+    PS("ePBC",EPBC(ir->ePBC));
+    PS("bPeriodicMols",BOOL(ir->bPeriodicMols));
+    PS("bContinuation",BOOL(ir->bContinuation));
+    PS("bShakeSOR",BOOL(ir->bShakeSOR));
+    PS("etc",ETCOUPLTYPE(ir->etc));
+    PI("nsttcouple",ir->nsttcouple);
+    PS("epc",EPCOUPLTYPE(ir->epc));
+    PS("epctype",EPCOUPLTYPETYPE(ir->epct));
+    PI("nstpcouple",ir->nstpcouple);
+    PR("tau_p",ir->tau_p);
+    pr_matrix(fp,indent,"ref_p",ir->ref_p,bMDPformat);
+    pr_matrix(fp,indent,"compress",ir->compress,bMDPformat);
+    PS("refcoord_scaling",EREFSCALINGTYPE(ir->refcoord_scaling));
+    if (bMDPformat)
+      fprintf(fp,"posres_com  = %g %g %g\n",ir->posres_com[XX],
+             ir->posres_com[YY],ir->posres_com[ZZ]);
+    else
+      pr_rvec(fp,indent,"posres_com",ir->posres_com,DIM,TRUE);
+    if (bMDPformat)
+      fprintf(fp,"posres_comB = %g %g %g\n",ir->posres_comB[XX],
+             ir->posres_comB[YY],ir->posres_comB[ZZ]);
+    else
+      pr_rvec(fp,indent,"posres_comB",ir->posres_comB,DIM,TRUE);
+    PI("andersen_seed",ir->andersen_seed);
+    PR("rlist",ir->rlist);
+    PR("rlistlong",ir->rlistlong);
+    PR("rtpi",ir->rtpi);
+    PS("coulombtype",EELTYPE(ir->coulombtype));
+    PR("rcoulomb_switch",ir->rcoulomb_switch);
+    PR("rcoulomb",ir->rcoulomb);
+    PS("vdwtype",EVDWTYPE(ir->vdwtype));
+    PR("rvdw_switch",ir->rvdw_switch);
+    PR("rvdw",ir->rvdw);
+    if (ir->epsilon_r != 0)
+      PR("epsilon_r",ir->epsilon_r);
+    else
+      PS("epsilon_r",infbuf);
+    if (ir->epsilon_rf != 0)
+      PR("epsilon_rf",ir->epsilon_rf);
+    else
+      PS("epsilon_rf",infbuf);
+    PR("tabext",ir->tabext);
+    PS("implicit_solvent",EIMPLICITSOL(ir->implicit_solvent));
+    PS("gb_algorithm",EGBALGORITHM(ir->gb_algorithm));
+    PR("gb_epsilon_solvent",ir->gb_epsilon_solvent);
+    PI("nstgbradii",ir->nstgbradii);
+    PR("rgbradii",ir->rgbradii);
+    PR("gb_saltconc",ir->gb_saltconc);
+    PR("gb_obc_alpha",ir->gb_obc_alpha);
+    PR("gb_obc_beta",ir->gb_obc_beta);
+    PR("gb_obc_gamma",ir->gb_obc_gamma);
+    PR("gb_dielectric_offset",ir->gb_dielectric_offset);
+    PS("sa_algorithm",ESAALGORITHM(ir->gb_algorithm));
+    PR("sa_surface_tension",ir->sa_surface_tension);
+         
+    PS("DispCorr",EDISPCORR(ir->eDispCorr));
+    PS("free_energy",EFEPTYPE(ir->efep));
+    PR("init_lambda",ir->init_lambda);
+    PR("delta_lambda",ir->delta_lambda);
+    if (!bMDPformat)
+    {
+        PI("n_foreign_lambda",ir->n_flambda);
+    }
+    if (ir->n_flambda > 0)
+    {
+        pr_indent(fp,indent);
+        fprintf(fp,"foreign_lambda%s",bMDPformat ? " = " : ":");
+        for(i=0; i<ir->n_flambda; i++)
+        {
+            fprintf(fp,"  %10g",ir->flambda[i]);
+        }
+        fprintf(fp,"\n");
+    }
+    PR("sc_alpha",ir->sc_alpha);
+    PI("sc_power",ir->sc_power);
+    PR("sc_sigma",ir->sc_sigma);
+    PR("sc_sigma_min",ir->sc_sigma_min);
+    PI("nstdhdl", ir->nstdhdl);
+    PS("separate_dhdl_file", SEPDHDLFILETYPE(ir->separate_dhdl_file));
+    PS("dhdl_derivatives", DHDLDERIVATIVESTYPE(ir->dhdl_derivatives));
+    PI("dh_hist_size", ir->dh_hist_size);
+    PD("dh_hist_spacing", ir->dh_hist_spacing);
+
+    PI("nwall",ir->nwall);
+    PS("wall_type",EWALLTYPE(ir->wall_type));
+    PI("wall_atomtype[0]",ir->wall_atomtype[0]);
+    PI("wall_atomtype[1]",ir->wall_atomtype[1]);
+    PR("wall_density[0]",ir->wall_density[0]);
+    PR("wall_density[1]",ir->wall_density[1]);
+    PR("wall_ewald_zfac",ir->wall_ewald_zfac);
+
+    PS("pull",EPULLTYPE(ir->ePull));
+    if (ir->ePull != epullNO)
+      pr_pull(fp,indent,ir->pull);
+    
+    PS("rotation",BOOL(ir->bRot));
+    if (ir->bRot)
+      pr_rot(fp,indent,ir->rot);
+
+    PS("disre",EDISRETYPE(ir->eDisre));
+    PS("disre_weighting",EDISREWEIGHTING(ir->eDisreWeighting));
+    PS("disre_mixed",BOOL(ir->bDisreMixed));
+    PR("dr_fc",ir->dr_fc);
+    PR("dr_tau",ir->dr_tau);
+    PR("nstdisreout",ir->nstdisreout);
+    PR("orires_fc",ir->orires_fc);
+    PR("orires_tau",ir->orires_tau);
+    PR("nstorireout",ir->nstorireout);
+
+    PR("dihre-fc",ir->dihre_fc);
+    
+    PR("em_stepsize",ir->em_stepsize);
+    PR("em_tol",ir->em_tol);
+    PI("niter",ir->niter);
+    PR("fc_stepsize",ir->fc_stepsize);
+    PI("nstcgsteep",ir->nstcgsteep);
+    PI("nbfgscorr",ir->nbfgscorr);
+
+    PS("ConstAlg",ECONSTRTYPE(ir->eConstrAlg));
+    PR("shake_tol",ir->shake_tol);
+    PI("lincs_order",ir->nProjOrder);
+    PR("lincs_warnangle",ir->LincsWarnAngle);
+    PI("lincs_iter",ir->nLincsIter);
+    PR("bd_fric",ir->bd_fric);
+    PI("ld_seed",ir->ld_seed);
+    PR("cos_accel",ir->cos_accel);
+    pr_matrix(fp,indent,"deform",ir->deform,bMDPformat);
+    PI("userint1",ir->userint1);
+    PI("userint2",ir->userint2);
+    PI("userint3",ir->userint3);
+    PI("userint4",ir->userint4);
+    PR("userreal1",ir->userreal1);
+    PR("userreal2",ir->userreal2);
+    PR("userreal3",ir->userreal3);
+    PR("userreal4",ir->userreal4);
+    pr_grp_opts(fp,indent,"grpopts",&(ir->opts),bMDPformat);
+    pr_cosine(fp,indent,"efield-x",&(ir->ex[XX]),bMDPformat);
+    pr_cosine(fp,indent,"efield-xt",&(ir->et[XX]),bMDPformat);
+    pr_cosine(fp,indent,"efield-y",&(ir->ex[YY]),bMDPformat);
+    pr_cosine(fp,indent,"efield-yt",&(ir->et[YY]),bMDPformat);
+    pr_cosine(fp,indent,"efield-z",&(ir->ex[ZZ]),bMDPformat);
+    pr_cosine(fp,indent,"efield-zt",&(ir->et[ZZ]),bMDPformat);
+    PS("bQMMM",BOOL(ir->bQMMM));
+    PI("QMconstraints",ir->QMconstraints);
+    PI("QMMMscheme",ir->QMMMscheme);
+    PR("scalefactor",ir->scalefactor);
+    pr_qm_opts(fp,indent,"qm_opts",&(ir->opts));
+  }
+}
+#undef PS
+#undef PR
+#undef PI
+
+static void pr_harm(FILE *fp,t_iparams *iparams,const char *r,const char *kr)
+{
+  fprintf(fp,"%sA=%12.5e, %sA=%12.5e, %sB=%12.5e, %sB=%12.5e\n",
+         r,iparams->harmonic.rA,kr,iparams->harmonic.krA,
+         r,iparams->harmonic.rB,kr,iparams->harmonic.krB);
+}
+
+void pr_iparams(FILE *fp,t_functype ftype,t_iparams *iparams)
+{
+  int i;
+  real VA[4],VB[4],*rbcA,*rbcB;
+
+  switch (ftype) {
+  case F_ANGLES:
+  case F_G96ANGLES:
+    pr_harm(fp,iparams,"th","ct");
+    break;
+  case F_CROSS_BOND_BONDS:
+    fprintf(fp,"r1e=%15.8e, r2e=%15.8e, krr=%15.8e\n",
+           iparams->cross_bb.r1e,iparams->cross_bb.r2e,
+           iparams->cross_bb.krr);
+    break;
+  case F_CROSS_BOND_ANGLES:
+    fprintf(fp,"r1e=%15.8e, r1e=%15.8e, r3e=%15.8e, krt=%15.8e\n",
+           iparams->cross_ba.r1e,iparams->cross_ba.r2e,
+           iparams->cross_ba.r3e,iparams->cross_ba.krt);
+    break;
+  case F_UREY_BRADLEY:
+    fprintf(fp,"theta=%15.8e, ktheta=%15.8e, r13=%15.8e, kUB=%15.8e\n",
+           iparams->u_b.theta,iparams->u_b.ktheta,iparams->u_b.r13,iparams->u_b.kUB);
+    break;
+  case F_QUARTIC_ANGLES:
+    fprintf(fp,"theta=%15.8e",iparams->qangle.theta);
+    for(i=0; i<5; i++)
+      fprintf(fp,", c%c=%15.8e",'0'+i,iparams->qangle.c[i]);
+    fprintf(fp,"\n");
+    break;
+  case F_BHAM:
+    fprintf(fp,"a=%15.8e, b=%15.8e, c=%15.8e\n",
+           iparams->bham.a,iparams->bham.b,iparams->bham.c);
+    break;
+  case F_BONDS:
+  case F_G96BONDS:
+  case F_HARMONIC:
+    pr_harm(fp,iparams,"b0","cb");
+    break;
+  case F_IDIHS:
+    pr_harm(fp,iparams,"xi","cx");
+    break;
+  case F_MORSE:
+    fprintf(fp,"b0=%15.8e, cb=%15.8e, beta=%15.8e\n",
+           iparams->morse.b0,iparams->morse.cb,iparams->morse.beta);
+    break;
+  case F_CUBICBONDS:
+    fprintf(fp,"b0=%15.8e, kb=%15.8e, kcub=%15.8e\n",
+           iparams->cubic.b0,iparams->cubic.kb,iparams->cubic.kcub);
+    break;
+  case F_CONNBONDS:
+    fprintf(fp,"\n");
+    break;
+  case F_FENEBONDS:
+    fprintf(fp,"bm=%15.8e, kb=%15.8e\n",iparams->fene.bm,iparams->fene.kb);
+    break;
+  case F_RESTRBONDS:
+      fprintf(fp,"lowA=%15.8e, up1A=%15.8e, up2A=%15.8e, kA=%15.8e, lowB=%15.8e, up1B=%15.8e, up2B=%15.8e, kB=%15.8e,\n",
+              iparams->restraint.lowA,iparams->restraint.up1A,
+              iparams->restraint.up2A,iparams->restraint.kA,
+              iparams->restraint.lowB,iparams->restraint.up1B,
+              iparams->restraint.up2B,iparams->restraint.kB);
+      break;
+  case F_TABBONDS:
+  case F_TABBONDSNC:
+  case F_TABANGLES:
+  case F_TABDIHS:
+    fprintf(fp,"tab=%d, kA=%15.8e, kB=%15.8e\n",
+           iparams->tab.table,iparams->tab.kA,iparams->tab.kB);
+    break;
+  case F_POLARIZATION:
+    fprintf(fp,"alpha=%15.8e\n",iparams->polarize.alpha);
+    break;
+  case F_THOLE_POL:
+    fprintf(fp,"a=%15.8e, alpha1=%15.8e, alpha2=%15.8e, rfac=%15.8e\n",
+           iparams->thole.a,iparams->thole.alpha1,iparams->thole.alpha2,
+           iparams->thole.rfac);
+    break;
+  case F_WATER_POL:
+    fprintf(fp,"al_x=%15.8e, al_y=%15.8e, al_z=%15.8e, rOH=%9.6f, rHH=%9.6f, rOD=%9.6f\n",
+           iparams->wpol.al_x,iparams->wpol.al_y,iparams->wpol.al_z,
+           iparams->wpol.rOH,iparams->wpol.rHH,iparams->wpol.rOD);
+    break;
+  case F_LJ:
+    fprintf(fp,"c6=%15.8e, c12=%15.8e\n",iparams->lj.c6,iparams->lj.c12);
+    break;
+  case F_LJ14:
+    fprintf(fp,"c6A=%15.8e, c12A=%15.8e, c6B=%15.8e, c12B=%15.8e\n",
+           iparams->lj14.c6A,iparams->lj14.c12A,
+           iparams->lj14.c6B,iparams->lj14.c12B);
+    break;
+  case F_LJC14_Q:
+    fprintf(fp,"fqq=%15.8e, qi=%15.8e, qj=%15.8e, c6=%15.8e, c12=%15.8e\n",
+           iparams->ljc14.fqq,
+           iparams->ljc14.qi,iparams->ljc14.qj,
+           iparams->ljc14.c6,iparams->ljc14.c12);
+    break;
+  case F_LJC_PAIRS_NB:
+    fprintf(fp,"qi=%15.8e, qj=%15.8e, c6=%15.8e, c12=%15.8e\n",
+           iparams->ljcnb.qi,iparams->ljcnb.qj,
+           iparams->ljcnb.c6,iparams->ljcnb.c12);
+    break;
+  case F_PDIHS:
+  case F_PIDIHS:
+  case F_ANGRES:
+  case F_ANGRESZ:
+    fprintf(fp,"phiA=%15.8e, cpA=%15.8e, phiB=%15.8e, cpB=%15.8e, mult=%d\n",
+           iparams->pdihs.phiA,iparams->pdihs.cpA,
+           iparams->pdihs.phiB,iparams->pdihs.cpB,
+           iparams->pdihs.mult);
+    break;
+  case F_DISRES:
+    fprintf(fp,"label=%4d, type=%1d, low=%15.8e, up1=%15.8e, up2=%15.8e, fac=%15.8e)\n",
+           iparams->disres.label,iparams->disres.type,
+           iparams->disres.low,iparams->disres.up1,
+           iparams->disres.up2,iparams->disres.kfac);
+    break;
+  case F_ORIRES:
+    fprintf(fp,"ex=%4d, label=%d, power=%4d, c=%15.8e, obs=%15.8e, kfac=%15.8e)\n",
+           iparams->orires.ex,iparams->orires.label,iparams->orires.power,
+           iparams->orires.c,iparams->orires.obs,iparams->orires.kfac);
+    break;
+  case F_DIHRES:
+    fprintf(fp,"label=%d, power=%4d phi=%15.8e, dphi=%15.8e, kfac=%15.8e)\n",
+           iparams->dihres.label,iparams->dihres.power,
+           iparams->dihres.phi,iparams->dihres.dphi,iparams->dihres.kfac);
+    break;
+  case F_POSRES:
+    fprintf(fp,"pos0A=(%15.8e,%15.8e,%15.8e), fcA=(%15.8e,%15.8e,%15.8e), pos0B=(%15.8e,%15.8e,%15.8e), fcB=(%15.8e,%15.8e,%15.8e)\n",
+           iparams->posres.pos0A[XX],iparams->posres.pos0A[YY],
+           iparams->posres.pos0A[ZZ],iparams->posres.fcA[XX],
+           iparams->posres.fcA[YY],iparams->posres.fcA[ZZ],
+           iparams->posres.pos0B[XX],iparams->posres.pos0B[YY],
+           iparams->posres.pos0B[ZZ],iparams->posres.fcB[XX],
+           iparams->posres.fcB[YY],iparams->posres.fcB[ZZ]);
+    break;
+  case F_RBDIHS:
+    for (i=0; i<NR_RBDIHS; i++) 
+      fprintf(fp,"%srbcA[%d]=%15.8e",i==0?"":", ",i,iparams->rbdihs.rbcA[i]);
+    fprintf(fp,"\n");
+    for (i=0; i<NR_RBDIHS; i++) 
+      fprintf(fp,"%srbcB[%d]=%15.8e",i==0?"":", ",i,iparams->rbdihs.rbcB[i]);
+    fprintf(fp,"\n");
+    break;
+  case F_FOURDIHS:
+    /* Use the OPLS -> Ryckaert-Bellemans formula backwards to get the
+     * OPLS potential constants back.
+     */
+    rbcA = iparams->rbdihs.rbcA;
+    rbcB = iparams->rbdihs.rbcB;
+
+    VA[3] = -0.25*rbcA[4];
+    VA[2] = -0.5*rbcA[3];
+    VA[1] = 4.0*VA[3]-rbcA[2];
+    VA[0] = 3.0*VA[2]-2.0*rbcA[1];
+
+    VB[3] = -0.25*rbcB[4];
+    VB[2] = -0.5*rbcB[3];
+    VB[1] = 4.0*VB[3]-rbcB[2];
+    VB[0] = 3.0*VB[2]-2.0*rbcB[1];
+
+    for (i=0; i<NR_FOURDIHS; i++) 
+      fprintf(fp,"%sFourA[%d]=%15.8e",i==0?"":", ",i,VA[i]);
+    fprintf(fp,"\n");
+    for (i=0; i<NR_FOURDIHS; i++) 
+      fprintf(fp,"%sFourB[%d]=%15.8e",i==0?"":", ",i,VB[i]);
+    fprintf(fp,"\n");
+    break;
+   
+  case F_CONSTR:
+  case F_CONSTRNC:
+    fprintf(fp,"dA=%15.8e, dB=%15.8e\n",iparams->constr.dA,iparams->constr.dB);
+    break;
+  case F_SETTLE:
+    fprintf(fp,"doh=%15.8e, dhh=%15.8e\n",iparams->settle.doh,
+           iparams->settle.dhh);
+    break;
+  case F_VSITE2:
+    fprintf(fp,"a=%15.8e\n",iparams->vsite.a);
+    break;
+  case F_VSITE3:
+  case F_VSITE3FD:
+  case F_VSITE3FAD:
+    fprintf(fp,"a=%15.8e, b=%15.8e\n",iparams->vsite.a,iparams->vsite.b);
+    break;
+  case F_VSITE3OUT:
+  case F_VSITE4FD:
+  case F_VSITE4FDN:
+    fprintf(fp,"a=%15.8e, b=%15.8e, c=%15.8e\n",
+           iparams->vsite.a,iparams->vsite.b,iparams->vsite.c);
+    break;
+  case F_VSITEN:
+    fprintf(fp,"n=%2d, a=%15.8e\n",iparams->vsiten.n,iparams->vsiten.a);
+    break;
+  case F_GB12:
+  case F_GB13:
+  case F_GB14:
+    fprintf(fp, "sar=%15.8e, st=%15.8e, pi=%15.8e, gbr=%15.8e, bmlt=%15.8e\n",iparams->gb.sar,iparams->gb.st,iparams->gb.pi,iparams->gb.gbr,iparams->gb.bmlt);
+    break;               
+  case F_CMAP:
+    fprintf(fp, "cmapA=%1d, cmapB=%1d\n",iparams->cmap.cmapA, iparams->cmap.cmapB);
+    break;               
+  default:
+    gmx_fatal(FARGS,"unknown function type %d (%s) in %s line %d",
+             ftype,interaction_function[ftype].name,__FILE__,__LINE__);
+  }
+}
+
+void pr_ilist(FILE *fp,int indent,const char *title,
+              t_functype *functype,t_ilist *ilist, gmx_bool bShowNumbers)
+{
+    int i,j,k,type,ftype;
+    t_iatom *iatoms;
+    
+    if (available(fp,ilist,indent,title) && ilist->nr > 0)
+    {  
+        indent=pr_title(fp,indent,title);
+        (void) pr_indent(fp,indent);
+        fprintf(fp,"nr: %d\n",ilist->nr);
+        if (ilist->nr > 0) {
+            (void) pr_indent(fp,indent);
+            fprintf(fp,"iatoms:\n");
+            iatoms=ilist->iatoms;
+            for (i=j=0; i<ilist->nr;) {
+#ifndef DEBUG
+                (void) pr_indent(fp,indent+INDENT);
+                type=*(iatoms++);
+                ftype=functype[type];
+                (void) fprintf(fp,"%d type=%d (%s)",
+                               bShowNumbers?j:-1,bShowNumbers?type:-1,
+                               interaction_function[ftype].name);
+                j++;
+                for (k=0; k<interaction_function[ftype].nratoms; k++)
+                    (void) fprintf(fp," %u",*(iatoms++));
+                (void) fprintf(fp,"\n");
+                i+=1+interaction_function[ftype].nratoms;
+#else
+                fprintf(fp,"%5d%5d\n",i,iatoms[i]);
+                i++;
+#endif
+            }
+        }
+    }
+}
+
+static void pr_cmap(FILE *fp, int indent, const char *title,
+                    gmx_cmap_t *cmap_grid, gmx_bool bShowNumbers)
+{
+    int i,j,nelem;
+    real dx,idx;
+       
+    dx    = 360.0 / cmap_grid->grid_spacing;
+    nelem = cmap_grid->grid_spacing*cmap_grid->grid_spacing;
+       
+    if(available(fp,cmap_grid,indent,title))
+    {
+        fprintf(fp,"%s\n",title);
+               
+        for(i=0;i<cmap_grid->ngrid;i++)
+        {
+            idx = -180.0;
+            fprintf(fp,"%8s %8s %8s %8s\n","V","dVdx","dVdy","d2dV");
+                       
+            fprintf(fp,"grid[%3d]={\n",bShowNumbers?i:-1);
+                       
+            for(j=0;j<nelem;j++)
+            {
+                if( (j%cmap_grid->grid_spacing)==0)
+                {
+                    fprintf(fp,"%8.1f\n",idx);
+                    idx+=dx;
+                }
+                               
+                fprintf(fp,"%8.3f ",cmap_grid->cmapdata[i].cmap[j*4]);
+                fprintf(fp,"%8.3f ",cmap_grid->cmapdata[i].cmap[j*4+1]);
+                fprintf(fp,"%8.3f ",cmap_grid->cmapdata[i].cmap[j*4+2]);
+                fprintf(fp,"%8.3f\n",cmap_grid->cmapdata[i].cmap[j*4+3]);
+            }
+            fprintf(fp,"\n");
+        }
+    }
+       
+}
+
+void pr_ffparams(FILE *fp,int indent,const char *title,
+                 gmx_ffparams_t *ffparams,
+                 gmx_bool bShowNumbers)
+{
+  int i,j;
+  
+  indent=pr_title(fp,indent,title);
+  (void) pr_indent(fp,indent);
+  (void) fprintf(fp,"atnr=%d\n",ffparams->atnr);
+  (void) pr_indent(fp,indent);
+  (void) fprintf(fp,"ntypes=%d\n",ffparams->ntypes);
+  for (i=0; i<ffparams->ntypes; i++) {
+      (void) pr_indent(fp,indent+INDENT);
+      (void) fprintf(fp,"functype[%d]=%s, ",
+                     bShowNumbers?i:-1,
+                     interaction_function[ffparams->functype[i]].name);
+      pr_iparams(fp,ffparams->functype[i],&ffparams->iparams[i]);
+  }
+  (void) pr_double(fp,indent,"reppow",ffparams->reppow);
+  (void) pr_real(fp,indent,"fudgeQQ",ffparams->fudgeQQ);
+  pr_cmap(fp,indent,"cmap",&ffparams->cmap_grid,bShowNumbers);
+}
+
+void pr_idef(FILE *fp,int indent,const char *title,t_idef *idef, gmx_bool bShowNumbers)
+{
+  int i,j;
+  
+  if (available(fp,idef,indent,title)) {  
+    indent=pr_title(fp,indent,title);
+    (void) pr_indent(fp,indent);
+    (void) fprintf(fp,"atnr=%d\n",idef->atnr);
+    (void) pr_indent(fp,indent);
+    (void) fprintf(fp,"ntypes=%d\n",idef->ntypes);
+    for (i=0; i<idef->ntypes; i++) {
+      (void) pr_indent(fp,indent+INDENT);
+      (void) fprintf(fp,"functype[%d]=%s, ",
+                    bShowNumbers?i:-1,
+                    interaction_function[idef->functype[i]].name);
+      pr_iparams(fp,idef->functype[i],&idef->iparams[i]);
+    }
+    (void) pr_real(fp,indent,"fudgeQQ",idef->fudgeQQ);
+
+    for(j=0; (j<F_NRE); j++)
+      pr_ilist(fp,indent,interaction_function[j].longname,
+               idef->functype,&idef->il[j],bShowNumbers);
+  }
+}
+
+static int pr_block_title(FILE *fp,int indent,const char *title,t_block *block)
+{
+  int i;
+
+  if (available(fp,block,indent,title))
+    {
+      indent=pr_title(fp,indent,title);
+      (void) pr_indent(fp,indent);
+      (void) fprintf(fp,"nr=%d\n",block->nr);
+    }
+  return indent;
+}
+
+static int pr_blocka_title(FILE *fp,int indent,const char *title,t_blocka *block)
+{
+  int i;
+
+  if (available(fp,block,indent,title))
+    {
+      indent=pr_title(fp,indent,title);
+      (void) pr_indent(fp,indent);
+      (void) fprintf(fp,"nr=%d\n",block->nr);
+      (void) pr_indent(fp,indent);
+      (void) fprintf(fp,"nra=%d\n",block->nra);
+    }
+  return indent;
+}
+
+static void low_pr_block(FILE *fp,int indent,const char *title,t_block *block, gmx_bool bShowNumbers)
+{
+  int i;
+  
+  if (available(fp,block,indent,title))
+    {
+      indent=pr_block_title(fp,indent,title,block);
+      for (i=0; i<=block->nr; i++)
+        {
+          (void) pr_indent(fp,indent+INDENT);
+          (void) fprintf(fp,"%s->index[%d]=%u\n",
+                        title,bShowNumbers?i:-1,block->index[i]);
+        }
+    }
+}
+
+static void low_pr_blocka(FILE *fp,int indent,const char *title,t_blocka *block, gmx_bool bShowNumbers)
+{
+  int i;
+  
+  if (available(fp,block,indent,title))
+    {
+      indent=pr_blocka_title(fp,indent,title,block);
+      for (i=0; i<=block->nr; i++)
+        {
+          (void) pr_indent(fp,indent+INDENT);
+          (void) fprintf(fp,"%s->index[%d]=%u\n",
+                        title,bShowNumbers?i:-1,block->index[i]);
+        }
+      for (i=0; i<block->nra; i++)
+        {
+          (void) pr_indent(fp,indent+INDENT);
+          (void) fprintf(fp,"%s->a[%d]=%u\n",
+                        title,bShowNumbers?i:-1,block->a[i]);
+        }
+    }
+}
+
+void pr_block(FILE *fp,int indent,const char *title,t_block *block,gmx_bool bShowNumbers)
+{
+  int i,j,ok,size,start,end;
+  
+  if (available(fp,block,indent,title))
+    {
+      indent=pr_block_title(fp,indent,title,block);
+      start=0;
+      end=start;
+      if ((ok=(block->index[start]==0))==0)
+        (void) fprintf(fp,"block->index[%d] should be 0\n",start);
+      else
+        for (i=0; i<block->nr; i++)
+          {
+            end=block->index[i+1];
+            size=pr_indent(fp,indent);
+            if (end<=start)
+              size+=fprintf(fp,"%s[%d]={}\n",title,i);
+            else
+              size+=fprintf(fp,"%s[%d]={%d..%d}\n",
+                           title,bShowNumbers?i:-1,
+                           bShowNumbers?start:-1,bShowNumbers?end-1:-1);
+            start=end;
+          }
+    }
+}
+
+void pr_blocka(FILE *fp,int indent,const char *title,t_blocka *block,gmx_bool bShowNumbers)
+{
+  int i,j,ok,size,start,end;
+  
+  if (available(fp,block,indent,title))
+    {
+      indent=pr_blocka_title(fp,indent,title,block);
+      start=0;
+      end=start;
+      if ((ok=(block->index[start]==0))==0)
+        (void) fprintf(fp,"block->index[%d] should be 0\n",start);
+      else
+        for (i=0; i<block->nr; i++)
+          {
+            end=block->index[i+1];
+            size=pr_indent(fp,indent);
+            if (end<=start)
+              size+=fprintf(fp,"%s[%d]={",title,i);
+            else
+              size+=fprintf(fp,"%s[%d][%d..%d]={",
+                           title,bShowNumbers?i:-1,
+                           bShowNumbers?start:-1,bShowNumbers?end-1:-1);
+            for (j=start; j<end; j++)
+              {
+                if (j>start) size+=fprintf(fp,", ");
+                if ((size)>(USE_WIDTH))
+                  {
+                    (void) fprintf(fp,"\n");
+                    size=pr_indent(fp,indent+INDENT);
+                  }
+                size+=fprintf(fp,"%u",block->a[j]);
+              }
+            (void) fprintf(fp,"}\n");
+            start=end;
+          }
+      if ((end!=block->nra)||(!ok)) 
+        {
+          (void) pr_indent(fp,indent);
+          (void) fprintf(fp,"tables inconsistent, dumping complete tables:\n");
+          low_pr_blocka(fp,indent,title,block,bShowNumbers);
+        }
+    }
+}
+
+static void pr_strings(FILE *fp,int indent,const char *title,char ***nm,int n, gmx_bool bShowNumbers)
+{
+  int i;
+
+  if (available(fp,nm,indent,title))
+    {  
+      indent=pr_title_n(fp,indent,title,n);
+      for (i=0; i<n; i++)
+        {
+          (void) pr_indent(fp,indent);
+          (void) fprintf(fp,"%s[%d]={name=\"%s\"}\n",
+                        title,bShowNumbers?i:-1,*(nm[i]));
+        }
+    }
+}
+
+static void pr_strings2(FILE *fp,int indent,const char *title,
+                       char ***nm,char ***nmB,int n, gmx_bool bShowNumbers)
+{
+  int i;
+
+  if (available(fp,nm,indent,title))
+    {  
+      indent=pr_title_n(fp,indent,title,n);
+      for (i=0; i<n; i++)
+        {
+          (void) pr_indent(fp,indent);
+          (void) fprintf(fp,"%s[%d]={name=\"%s\",nameB=\"%s\"}\n",
+                        title,bShowNumbers?i:-1,*(nm[i]),*(nmB[i]));
+        }
+    }
+}
+
+static void pr_resinfo(FILE *fp,int indent,const char *title,t_resinfo *resinfo,int n, gmx_bool bShowNumbers)
+{
+    int i;
+    
+    if (available(fp,resinfo,indent,title))
+    {  
+        indent=pr_title_n(fp,indent,title,n);
+        for (i=0; i<n; i++)
+        {
+            (void) pr_indent(fp,indent);
+            (void) fprintf(fp,"%s[%d]={name=\"%s\", nr=%d, ic='%c'}\n",
+                           title,bShowNumbers?i:-1,
+                           *(resinfo[i].name),resinfo[i].nr,
+                           (resinfo[i].ic == '\0') ? ' ' : resinfo[i].ic);
+        }
+    }
+}
+
+static void pr_atom(FILE *fp,int indent,const char *title,t_atom *atom,int n)
+{
+  int i,j;
+  
+  if (available(fp,atom,indent,title)) {  
+    indent=pr_title_n(fp,indent,title,n);
+    for (i=0; i<n; i++) {
+      (void) pr_indent(fp,indent);
+      fprintf(fp,"%s[%6d]={type=%3d, typeB=%3d, ptype=%8s, m=%12.5e, "
+              "q=%12.5e, mB=%12.5e, qB=%12.5e, resind=%5d, atomnumber=%3d}\n",
+              title,i,atom[i].type,atom[i].typeB,ptype_str[atom[i].ptype],
+              atom[i].m,atom[i].q,atom[i].mB,atom[i].qB,
+              atom[i].resind,atom[i].atomnumber);
+    }
+  }
+}
+
+static void pr_grps(FILE *fp,int indent,const char *title,t_grps grps[],
+                   char **grpname[], gmx_bool bShowNumbers)
+{
+    int i,j;
+
+    for(i=0; (i<egcNR); i++)
+    {
+        fprintf(fp,"%s[%-12s] nr=%d, name=[",title,gtypes[i],grps[i].nr);
+        for(j=0; (j<grps[i].nr); j++)
+        {
+            fprintf(fp," %s",*(grpname[grps[i].nm_ind[j]]));
+        }
+        fprintf(fp,"]\n");
+    }
+}
+
+static void pr_groups(FILE *fp,int indent,const char *title,
+                      gmx_groups_t *groups,
+                      gmx_bool bShowNumbers)
+{
+    int grpnr[egcNR];
+    int nat_max,i,g;
+
+    pr_grps(fp,indent,"grp",groups->grps,groups->grpname,bShowNumbers);
+    pr_strings(fp,indent,"grpname",groups->grpname,groups->ngrpname,bShowNumbers);
+
+    (void) pr_indent(fp,indent);
+    fprintf(fp,"groups          ");
+    for(g=0; g<egcNR; g++)
+    {
+       printf(" %5.5s",gtypes[g]);
+    }
+    printf("\n");
+
+    (void) pr_indent(fp,indent);
+    fprintf(fp,"allocated       ");
+    nat_max = 0;
+    for(g=0; g<egcNR; g++)
+    {
+        printf(" %5d",groups->ngrpnr[g]);
+        nat_max = max(nat_max,groups->ngrpnr[g]);
+    }
+    printf("\n");
+
+    if (nat_max == 0)
+    {
+        (void) pr_indent(fp,indent);
+        fprintf(fp,"groupnr[%5s] =","*");
+        for(g=0; g<egcNR; g++)
+        {
+            fprintf(fp,"  %3d ",0);
+        }
+        fprintf(fp,"\n");
+    }
+    else
+    {
+        for(i=0; i<nat_max; i++)
+        {
+            (void) pr_indent(fp,indent);
+            fprintf(fp,"groupnr[%5d] =",i);
+            for(g=0; g<egcNR; g++)
+            {
+                fprintf(fp,"  %3d ",
+                        groups->grpnr[g] ? groups->grpnr[g][i] : 0);
+            }
+            fprintf(fp,"\n");
+        }
+    }
+}
+
+void pr_atoms(FILE *fp,int indent,const char *title,t_atoms *atoms, 
+             gmx_bool bShownumbers)
+{
+  if (available(fp,atoms,indent,title))
+    {
+      indent=pr_title(fp,indent,title);
+      pr_atom(fp,indent,"atom",atoms->atom,atoms->nr);
+      pr_strings(fp,indent,"atom",atoms->atomname,atoms->nr,bShownumbers);
+      pr_strings2(fp,indent,"type",atoms->atomtype,atoms->atomtypeB,atoms->nr,bShownumbers);
+      pr_resinfo(fp,indent,"residue",atoms->resinfo,atoms->nres,bShownumbers);
+    }
+}
+
+
+void pr_atomtypes(FILE *fp,int indent,const char *title,t_atomtypes *atomtypes, 
+                 gmx_bool bShowNumbers)
+{
+  int i;
+  if (available(fp,atomtypes,indent,title)) 
+  {
+    indent=pr_title(fp,indent,title);
+    for(i=0;i<atomtypes->nr;i++) {
+      pr_indent(fp,indent);
+               fprintf(fp,
+                               "atomtype[%3d]={radius=%12.5e, volume=%12.5e, gb_radius=%12.5e, surftens=%12.5e, atomnumber=%4d, S_hct=%12.5e)}\n",
+                               bShowNumbers?i:-1,atomtypes->radius[i],atomtypes->vol[i],
+                               atomtypes->gb_radius[i],
+                               atomtypes->surftens[i],atomtypes->atomnumber[i],atomtypes->S_hct[i]);
+    }
+  }
+}
+
+static void pr_moltype(FILE *fp,int indent,const char *title,
+                       gmx_moltype_t *molt,int n,
+                       gmx_ffparams_t *ffparams,
+                       gmx_bool bShowNumbers)
+{
+    int j;
+
+    indent = pr_title_n(fp,indent,title,n);
+    (void) pr_indent(fp,indent);
+    (void) fprintf(fp,"name=\"%s\"\n",*(molt->name));
+    pr_atoms(fp,indent,"atoms",&(molt->atoms),bShowNumbers);
+    pr_block(fp,indent,"cgs",&molt->cgs, bShowNumbers);
+    pr_blocka(fp,indent,"excls",&molt->excls, bShowNumbers);
+    for(j=0; (j<F_NRE); j++) {
+        pr_ilist(fp,indent,interaction_function[j].longname,
+                 ffparams->functype,&molt->ilist[j],bShowNumbers);
+    }
+}
+
+static void pr_molblock(FILE *fp,int indent,const char *title,
+                        gmx_molblock_t *molb,int n,
+                        gmx_moltype_t *molt,
+                        gmx_bool bShowNumbers)
+{
+    indent = pr_title_n(fp,indent,title,n);
+    (void) pr_indent(fp,indent);
+    (void) fprintf(fp,"%-20s = %d \"%s\"\n",
+                   "moltype",molb->type,*(molt[molb->type].name));
+    pr_int(fp,indent,"#molecules",molb->nmol);
+    pr_int(fp,indent,"#atoms_mol",molb->natoms_mol);
+    pr_int(fp,indent,"#posres_xA",molb->nposres_xA);
+    if (molb->nposres_xA > 0) {
+        pr_rvecs(fp,indent,"posres_xA",molb->posres_xA,molb->nposres_xA);
+    }
+    pr_int(fp,indent,"#posres_xB",molb->nposres_xB);
+    if (molb->nposres_xB > 0) {
+        pr_rvecs(fp,indent,"posres_xB",molb->posres_xB,molb->nposres_xB);
+    }
+}
+
+void pr_mtop(FILE *fp,int indent,const char *title,gmx_mtop_t *mtop,
+             gmx_bool bShowNumbers)
+{
+    int mt,mb;
+
+    if (available(fp,mtop,indent,title)) {
+        indent=pr_title(fp,indent,title);
+        (void) pr_indent(fp,indent);
+        (void) fprintf(fp,"name=\"%s\"\n",*(mtop->name));
+        pr_int(fp,indent,"#atoms",mtop->natoms);
+        for(mb=0; mb<mtop->nmolblock; mb++) {
+            pr_molblock(fp,indent,"molblock",&mtop->molblock[mb],mb,
+                        mtop->moltype,bShowNumbers);
+        }
+        pr_ffparams(fp,indent,"ffparams",&(mtop->ffparams),bShowNumbers);
+        pr_atomtypes(fp,indent,"atomtypes",&(mtop->atomtypes),bShowNumbers);
+        for(mt=0; mt<mtop->nmoltype; mt++) {
+            pr_moltype(fp,indent,"moltype",&mtop->moltype[mt],mt,
+                       &mtop->ffparams,bShowNumbers);
+        }
+        pr_groups(fp,indent,"groups",&mtop->groups,bShowNumbers);
+    }
+}
+
+void pr_top(FILE *fp,int indent,const char *title,t_topology *top, gmx_bool bShowNumbers)
+{
+  if (available(fp,top,indent,title)) {
+    indent=pr_title(fp,indent,title);
+    (void) pr_indent(fp,indent);
+    (void) fprintf(fp,"name=\"%s\"\n",*(top->name));
+    pr_atoms(fp,indent,"atoms",&(top->atoms),bShowNumbers);
+    pr_atomtypes(fp,indent,"atomtypes",&(top->atomtypes),bShowNumbers);
+    pr_block(fp,indent,"cgs",&top->cgs, bShowNumbers);
+    pr_block(fp,indent,"mols",&top->mols, bShowNumbers);
+    pr_blocka(fp,indent,"excls",&top->excls, bShowNumbers);
+    pr_idef(fp,indent,"idef",&top->idef,bShowNumbers);
+  }
+}
+
+void pr_header(FILE *fp,int indent,const char *title,t_tpxheader *sh)
+{
+  char buf[22];
+    
+  if (available(fp,sh,indent,title))
+    {
+      indent=pr_title(fp,indent,title);
+      pr_indent(fp,indent);
+      fprintf(fp,"bIr    = %spresent\n",sh->bIr?"":"not ");
+      pr_indent(fp,indent);
+      fprintf(fp,"bBox   = %spresent\n",sh->bBox?"":"not ");
+      pr_indent(fp,indent);
+      fprintf(fp,"bTop   = %spresent\n",sh->bTop?"":"not ");
+      pr_indent(fp,indent);
+      fprintf(fp,"bX     = %spresent\n",sh->bX?"":"not ");
+      pr_indent(fp,indent);
+      fprintf(fp,"bV     = %spresent\n",sh->bV?"":"not ");
+      pr_indent(fp,indent);
+      fprintf(fp,"bF     = %spresent\n",sh->bF?"":"not ");
+      
+      pr_indent(fp,indent);
+      fprintf(fp,"natoms = %d\n",sh->natoms);
+      pr_indent(fp,indent);
+      fprintf(fp,"lambda = %e\n",sh->lambda);
+    }
+}
+
+void pr_commrec(FILE *fp,int indent,t_commrec *cr)
+{
+  pr_indent(fp,indent);
+  fprintf(fp,"commrec:\n");
+  indent+=2;
+  pr_indent(fp,indent);
+  fprintf(fp,"nodeid    = %d\n",cr->nodeid);
+  pr_indent(fp,indent);
+  fprintf(fp,"nnodes    = %d\n",cr->nnodes);
+  pr_indent(fp,indent);
+  fprintf(fp,"npmenodes = %d\n",cr->npmenodes);
+  /*
+  pr_indent(fp,indent);
+  fprintf(fp,"threadid  = %d\n",cr->threadid);
+  pr_indent(fp,indent);
+  fprintf(fp,"nthreads  = %d\n",cr->nthreads);
+  */
+}
similarity index 100%
rename from src/gmxlib/wgms.c
rename to src/gromacs/gmxlib/wgms.c
similarity index 100%
rename from src/gmxlib/wman.c
rename to src/gromacs/gmxlib/wman.c
similarity index 100%
rename from src/gmxlib/xdrd.c
rename to src/gromacs/gmxlib/xdrd.c
similarity index 100%
rename from src/gmxlib/xvgr.c
rename to src/gromacs/gmxlib/xvgr.c
diff --git a/src/gromacs/gromacs.h b/src/gromacs/gromacs.h
new file mode 100644 (file)
index 0000000..29b90ea
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * Dummy header for Doxygen documentation.
+ *
+ * This file just holds the main page for doxygen.  When, at some point in the
+ * future, there is an obvious location for this documentation, we should
+ * move it there.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ */
+/*! \mainpage Gromacs
+ * GROMACS is a versatile package to perform molecular dynamics, i.e. simulate
+ * the Newtonian equations of motion for systems with hundreds, to millions
+ * of particles.
+ */
+/*! \defgroup group_publicapi Public API
+ * \brief
+ * Classes and other symbols that are publicly accessible from user code.
+ */
+/*! \defgroup group_libraryapi Library API
+ * \brief
+ * Classes and other symbols that are publicly accessible within the Gromacs
+ * library.
+ *
+ * \see group_publicapi
+ */
+/*! \defgroup group_utilitymodules Utility Modules
+ * \brief
+ * Modules with generic utility functions.
+ */
+/*! \defgroup group_analysismodules Analysis Modules
+ * \brief
+ * Modules used in analysis tools.
+ */
+/*! \namespace gmx
+ * \brief
+ * Generic Gromacs namespace.
+ *
+ * \inpublicapi
+ */
diff --git a/src/gromacs/legacyheaders/CMakeLists.txt b/src/gromacs/legacyheaders/CMakeLists.txt
new file mode 100644 (file)
index 0000000..593fc53
--- /dev/null
@@ -0,0 +1,7 @@
+# includes: Nothing to build, just installation
+install(DIRECTORY . DESTINATION ${INCL_INSTALL_DIR}/gromacs/legacyheaders
+  COMPONENT development
+  PATTERN "Makefile*" EXCLUDE
+  PATTERN "CMake*" EXCLUDE
+  PATTERN "cmake*" EXCLUDE
+)
diff --git a/src/gromacs/legacyheaders/gmx_statistics.h b/src/gromacs/legacyheaders/gmx_statistics.h
new file mode 100644 (file)
index 0000000..afc1248
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+ * 
+ *                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
+ */
+
+#ifndef _GMX_STATS_H
+#define _GMX_STATS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "typedefs.h"
+
+typedef struct gmx_stats *gmx_stats_t;
+       
+/* Error codes returned by the routines */
+enum { estatsOK, estatsNO_POINTS, estatsNO_MEMORY, estatsERROR, 
+       estatsINVALID_INPUT, estatsNOT_IMPLEMENTED, estatsNR };
+       
+enum { elsqWEIGHT_NONE, elsqWEIGHT_X, elsqWEIGHT_Y, 
+       elsqWEIGHT_XY, elsqWEIGHT_NR  };
+
+enum { ehistoX, ehistoY, ehistoNR };
+  
+gmx_stats_t gmx_stats_init();
+
+int gmx_stats_done(gmx_stats_t stats);
+
+/* Remove outliers from a straight line, where level in units of
+   sigma. Level needs to be larger than one obviously. */
+int gmx_stats_remove_outliers(gmx_stats_t stats,double level);
+
+
+
+int gmx_stats_add_point(gmx_stats_t stats,double x,double y,
+                              double dx,double dy);
+
+/* The arrays dx and dy may be NULL if no uncertainties are available,
+   in that case zero uncertainties will be assumed. */
+int gmx_stats_add_points(gmx_stats_t stats,int n,real *x,real *y,
+                               real *dx,real *dy);
+
+/* Return the data points one by one. Return estatsOK while there are
+   more points, and returns estatsNOPOINTS when the last point has
+   been returned. Should be used in a while loop. Variables for either
+   pointer may be NULL, in which case the routine can be used as an
+   expensive point counter. 
+   If level > 0 then the outliers outside level*sigma are reported
+   only. */
+int gmx_stats_get_point(gmx_stats_t stats,real *x,real *y,
+                       real *dx,real *dy,real level);
+
+/* Fit the data to y = ax + b, possibly weighted, if uncertainties
+   have been input. Returns slope in *a and intercept in b, *return
+   sigmas in *da and *db respectively. Returns normalized *quality of
+   fit in *chi2 and correlation of fit with data in Rfit. chi2, Rfit,
+   da and db may be NULL. */
+int gmx_stats_get_ab(gmx_stats_t stats,int weight,
+                           real *a,real *b,
+                           real *da,real *db,real *chi2,real *Rfit);
+
+/* Fit the data to y = ax, possibly weighted, if uncertainties have
+   been input. Returns slope in *a, sigma in a in *da, and normalized
+   quality of fit in *chi2 and correlation of fit with data in
+   Rfit. chi2, Rfit and da may be NULL. */
+int gmx_stats_get_a(gmx_stats_t stats,int weight,
+                          real *a,real *da,real *chi2,real *Rfit);
+
+/* Return the correlation coefficient between the data (x and y) as
+   input to the structure. */
+int gmx_stats_get_corr_coeff(gmx_stats_t stats,real *R);
+
+/* Returns the root mean square deviation between x and y values. */
+int gmx_stats_get_rmsd(gmx_stats_t gstats,real *rmsd);
+
+int gmx_stats_get_npoints(gmx_stats_t stats,int *N);
+
+int gmx_stats_get_average(gmx_stats_t stats,real *aver);
+
+int gmx_stats_get_sigma(gmx_stats_t stats,real *sigma);
+
+int gmx_stats_get_error(gmx_stats_t stats,real *error);
+
+/* Get all three of the above. Pointers may be null, in which case no
+   assignment will be done. */
+int gmx_stats_get_ase(gmx_stats_t gstats,real *aver,real *sigma,real *error);
+
+/* Dump the x, y, dx, dy data to a text file */
+int gmx_stats_dump_xy(gmx_stats_t gstats,FILE *fp);
+
+/* Make a histogram of the data present. Uses either bindwith to
+   determine the number of bins, or nbins to determine the binwidth,
+   therefore one of these should be zero, but not the other. If *nbins = 0
+   the number of bins will be returned in this variable. ehisto should be one of 
+   ehistoX or ehistoY. If
+   normalized not equal to zero, the integral of the histogram will be
+   normalized to one. The output is in two arrays, *x and *y, to which
+   you should pass a pointer. Memory for the arrays will be allocated
+   as needed. Function returns one of the estats codes. */
+int gmx_stats_make_histogram(gmx_stats_t gstats,real binwidth,int *nbins,
+                                   int ehisto,
+                                   int normalized,real **x,real **y);
+
+/* Return message belonging to error code */
+const char *gmx_stats_message(int estats);
+
+/****************************************************
+ * Some statistics utilities for convenience: useful when a complete data
+ * set is available already from another source, e.g. an xvg file.
+ ****************************************************/
+int lsq_y_ax(int n, real x[], real y[], real *a);
+/* Fit a straight line y=ax thru the n data points x, y, return the
+   slope in *a. Return value can be estatsOK, or something else. */
+
+int lsq_y_ax_b(int n, real x[], real y[], real *a, real *b,real *r,
+                     real *chi2);
+/* Fit a straight line y=ax+b thru the n data points x,y.
+ * Returns the "fit quality" sigma = sqrt(chi^2/(n-2)).
+ * The correlation coefficient is returned in r.
+ */
+
+int lsq_y_ax_b_xdouble(int n, double x[], real y[],
+                              real *a, real *b,real *r,real *chi2);
+/* As lsq_y_ax_b, but with x in double precision.
+ */
+
+int lsq_y_ax_b_error(int n, real x[], real y[], real dy[],
+                            real *a, real *b, real *da, real *db,
+                            real *r,real *chi2);
+/* Fit a straight line y=ax+b thru the n data points x,y, with sigma dy
+ * Returns the "fit quality" sigma = sqrt(chi^2/(n-2)).
+ * The correlation coefficient is returned in r.
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/gromacs/legacyheaders/gmx_wallcycle.h b/src/gromacs/legacyheaders/gmx_wallcycle.h
new file mode 100644 (file)
index 0000000..b00cd65
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * 
+ *                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
+ */
+
+
+#ifndef _gmx_wallcycle_h
+#define _gmx_wallcycle_h
+
+#include <stdio.h>
+#include "typedefs.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+  enum { ewcRUN, ewcSTEP, ewcPPDURINGPME, ewcDOMDEC, ewcDDCOMMLOAD, ewcDDCOMMBOUND, ewcVSITECONSTR, ewcPP_PMESENDX, ewcMOVEX, ewcNS, ewcGB, ewcFORCE, ewcMOVEF, ewcPMEMESH, ewcPME_REDISTXF, ewcPME_SPREADGATHER, ewcPME_FFT, ewcPME_SOLVE, ewcPMEWAITCOMM, ewcPP_PMEWAITRECVF, ewcVSITESPREAD, ewcTRAJ, ewcUPDATE, ewcCONSTR, ewcMoveE, ewcROT, ewcTEST, ewcNR };
+
+gmx_bool wallcycle_have_counter(void);
+/* Returns if cycle counting is supported */
+
+gmx_wallcycle_t wallcycle_init(FILE *fplog,int resetstep,t_commrec *cr);
+/* Returns the wall cycle structure.
+ * Returns NULL when cycle counting is not supported.
+ */
+
+void wallcycle_start(gmx_wallcycle_t wc, int ewc);
+/* Set the start cycle count for ewc */
+
+double wallcycle_stop(gmx_wallcycle_t wc, int ewc);
+/* Stop the cycle count for ewc, returns the last cycle count */
+
+void wallcycle_reset_all(gmx_wallcycle_t wc);
+/* Resets all cycle counters to zero */
+
+void wallcycle_sum(t_commrec *cr, gmx_wallcycle_t wc,double cycles[]);
+/* Sum the cycles over the nodes in cr->mpi_comm_mysim */
+
+void wallcycle_print(FILE *fplog, int nnodes, int npme, double realtime,
+                           gmx_wallcycle_t wc, double cycles[]);
+/* Print the cycle and time accounting */
+
+gmx_large_int_t wcycle_get_reset_counters(gmx_wallcycle_t wc);
+/* Return reset_counters from wc struct */
+
+void wcycle_set_reset_counters(gmx_wallcycle_t wc, gmx_large_int_t reset_counters);
+/* Set reset_counters */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _gmx_wallcycle_h */
diff --git a/src/gromacs/legacyheaders/gmxfio.h b/src/gromacs/legacyheaders/gmxfio.h
new file mode 100644 (file)
index 0000000..e0db1ad
--- /dev/null
@@ -0,0 +1,459 @@
+/*
+ * 
+ *                This source code is part of
+ * 
+ *                 G   R   O   M   A   C   S
+ * 
+ *          GROningen MAchine for Chemical Simulations
+ * 
+ *                        VERSION 3.2.0
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * 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.
+
+ * 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:
+ * Gromacs Runs On Most of All Computer Systems
+ */
+
+#ifndef _gmxfio_h
+#define _gmxfio_h
+
+#include <stdio.h>
+#include "sysstuff.h"
+#include "typedefs.h"
+#include "xdrf.h"
+#include "futil.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+/* types */
+
+
+/* Enumerated for different items in files */
+enum { eitemHEADER, eitemIR, eitemBOX, 
+       eitemTOP, eitemX, eitemV, eitemF, eitemNR };
+       
+/* Enumerated for data types in files */
+enum { eioREAL, eioFLOAT, eioDOUBLE, eioINT, eioGMX_LARGE_INT,
+       eioUCHAR, eioNUCHAR, eioUSHORT,
+       eioRVEC, eioNRVEC, eioIVEC, eioSTRING, eioNR };
+
+typedef struct t_fileio t_fileio;
+
+extern const char *itemstr[eitemNR];
+extern const char *comment_str[eitemNR];
+
+/* NOTE ABOUT THREAD SAFETY:
+
+   The functions are all thread-safe, provided that two threads don't 
+   do something silly like closing the same file, or one thread 
+   accesses a file that has been closed by another.
+   */
+
+/********************************************************
+ * Open and Close 
+ ********************************************************/
+
+t_fileio *gmx_fio_open(const char *fn,const char *mode);
+/* Open a new file for reading or writing.
+ * The file type will be deduced from the file name.
+ * If fn is NULL, stdin / stdout will be used for Ascii I/O (TPA type)
+ * mode may be "r", "w", or "a". You should append a "b" to the mode
+ * if you are writing a binary file, but the routine will also 
+ * doublecheck it and try to do it if you forgot. This has no effect on
+ * unix, but is important on windows.
+ */
+int gmx_fio_close(t_fileio *fp);
+/* Close the file corresponding to fp (if not stdio)
+ * The routine will exit when an invalid fio is handled.
+ * Returns 0 on success.
+ */
+
+int gmx_fio_fp_close(t_fileio *fp);
+/* Close the file corresponding to fp without closing the FIO entry
+ * Needed e.g. for trxio because the FIO entries are used to store 
+ * additional data.
+ * NOTE that the fp still needs to be properly closed with gmx_fio_close().
+ * The routine will exit when an invalid fio is handled.
+ * Returns 0 on success.
+ */
+
+
+/* Open a file, return a stream, record the entry in internal FIO object */
+FILE* gmx_fio_fopen(const char *fn,const char *mode);
+
+/* Close a file previously opened with gmx_fio_fopen. 
+ * Do not mix these calls with standard fopen/fclose ones!
+ * Returns 0 on success.  */
+int gmx_fio_fclose(FILE *fp);
+
+
+
+/********************************************************
+ * Change properties of the open file
+ ********************************************************/
+
+void gmx_fio_setprecision(t_fileio *fio,gmx_bool bDouble);
+/* Select the floating point precision for reading and writing files */
+
+char *gmx_fio_getname(t_fileio *fio);
+/* Return the filename corresponding to the fio index */
+
+int gmx_fio_getftp(t_fileio *fio);
+/* Return the filetype corresponding to the fio index. 
+    There is as of now no corresponding setftp function because the file
+    was opened as a specific file type and changing that midway is most 
+    likely an evil hack. */
+
+void gmx_fio_setdebug(t_fileio *fio,gmx_bool bDebug);
+/* Set the debug mode */
+
+gmx_bool gmx_fio_getdebug(t_fileio *fio);
+/* Return  whether debug mode is on in fio  */
+
+gmx_bool gmx_fio_getread(t_fileio *fio);
+/* Return  whether read mode is on in fio  */
+
+
+void gmx_fio_checktype(t_fileio *fio);
+/* Check whether the fio is of a sane type */
+
+/***************************************************
+ * FILE Operations
+ ***************************************************/
+
+void gmx_fio_rewind(t_fileio *fio);
+/* Rewind the tpa file in fio */
+
+int gmx_fio_flush(t_fileio *fio);
+/* Flush the fio, returns 0 on success */
+
+int gmx_fio_fsync(t_fileio *fio);
+/* fsync the fio, returns 0 on success. 
+   NOTE: don't use fsync function unless you're absolutely sure you need it
+   because it deliberately interferes with the OS's caching mechanisms and
+   can cause dramatically slowed down IO performance. Some OSes (Linux, 
+   for example), may implement fsync as a full sync() point. */
+
+gmx_off_t gmx_fio_ftell(t_fileio *fio);
+/* Return file position if possible */
+
+int gmx_fio_seek(t_fileio *fio,gmx_off_t fpos);
+/* Set file position if possible, quit otherwise */
+
+FILE *gmx_fio_getfp(t_fileio *fio);
+/* Return the file pointer itself */
+
+XDR *gmx_fio_getxdr(t_fileio *fio);
+/* Return the file pointer itself */
+
+
+
+
+
+/* Element with information about position in a currently open file.
+ * gmx_off_t should be defined by autoconf if your system does not have it.
+ * If you do not have it on some other platform you do not have largefile 
+ * support at all, and you can define it to int (or better, find out how to 
+ * enable large files).  */
+typedef struct
+{
+       char      filename[STRLEN];
+       gmx_off_t offset; 
+       unsigned char chksum[16];
+       int       chksum_size;
+} 
+gmx_file_position_t;
+
+
+int gmx_fio_check_file_position(t_fileio *fio);
+/* Check if the file position is out of the range of off_t.
+ * The result is stored along with the other file data of fio.
+ */
+
+int gmx_fio_get_output_file_positions(gmx_file_position_t ** outputfiles,
+                                      int *nfiles );
+/* Return the name and file pointer positions for all currently open
+ * output files. This is used for saving in the checkpoint files, so we
+ * can truncate output files upon restart-with-appending.
+ *
+ * For the first argument you should use a pointer, which will be set to
+ * point to a list of open files.
+ */
+
+t_fileio *gmx_fio_all_output_fsync(void);
+/* fsync all open output files. This is used for checkpointing, where
+   we need to ensure that all output is actually written out to 
+   disk. 
+   This is most important in the case of some networked file systems, 
+   where data is not synced with the file server until close() or 
+   fsync(), so data could remain in cache for days.
+   Note the caveats reported with gmx_fio_fsync(). 
+   
+    returns: NULL if no error occurred, or a pointer to the first file that
+             failed if an error occurred 
+*/
+
+
+int gmx_fio_get_file_md5(t_fileio *fio, gmx_off_t offset,  
+                         unsigned char digest[]);
+
+
+int xtc_seek_frame(t_fileio *fio, int frame, int natoms);
+
+int xtc_seek_time(t_fileio *fio, real time, int natoms);
+
+       
+/* Add this to the comment string for debugging */
+void gmx_fio_set_comment(t_fileio *fio, const char *comment);
+
+/* Remove previously set comment */
+void gmx_fio_unset_comment(t_fileio *fio);
+
+
+
+
+/********************************************************
+ * Read and write
+ ********************************************************/
+
+
+/* basic reading & writing */
+gmx_bool gmx_fio_reade_real(t_fileio *fio, real *item, 
+                        const char *desc, const char *srcfile, int line);
+gmx_bool gmx_fio_reade_float(t_fileio *fio, float *item, 
+                          const char *desc, const char *srcfile, int line);
+gmx_bool gmx_fio_reade_double(t_fileio *fio, double *item, 
+                          const char *desc, const char *srcfile, int line);
+gmx_bool gmx_fio_reade_int(t_fileio *fio, int *item, 
+                       const char *desc, const char *srcfile, int line);
+gmx_bool gmx_fio_reade_gmx_large_int(t_fileio *fio, gmx_large_int_t *item, 
+                                 const char *desc, const char *srcfile, int line);
+gmx_bool gmx_fio_reade_uchar(t_fileio *fio, unsigned char *item, 
+                         const char *desc, const char *srcfile, int line);
+gmx_bool gmx_fio_reade_ushort(t_fileio *fio, unsigned short *item, 
+                         const char *desc, const char *srcfile, int line);
+gmx_bool gmx_fio_reade_rvec(t_fileio *fio, rvec *item, 
+                        const char *desc, const char *srcfile, int line);
+gmx_bool gmx_fio_reade_ivec(t_fileio *fio, ivec *item, 
+                        const char *desc, const char *srcfile, int line);
+gmx_bool gmx_fio_reade_string(t_fileio *fio, char *item, 
+                          const char *desc, const char *srcfile, int line);
+
+gmx_bool gmx_fio_writee_real(t_fileio *fio, real item, 
+                         const char *desc, const char *srcfile, int line);
+gmx_bool gmx_fio_writee_float(t_fileio *fio, float item, 
+                           const char *desc, const char *srcfile, int line);
+gmx_bool gmx_fio_writee_double(t_fileio *fio, double item, 
+                           const char *desc, const char *srcfile, int line);
+gmx_bool gmx_fio_writee_int(t_fileio *fio, int item, 
+                        const char *desc, const char *srcfile, int line);
+gmx_bool gmx_fio_writee_gmx_large_int(t_fileio *fio, gmx_large_int_t item, 
+                                  const char *desc, const char *srcfile, int line);
+gmx_bool gmx_fio_writee_uchar(t_fileio *fio, unsigned char item, 
+                          const char *desc, const char *srcfile, int line);
+gmx_bool gmx_fio_writee_ushort(t_fileio *fio, unsigned short item, 
+                          const char *desc, const char *srcfile, int line);
+gmx_bool gmx_fio_writee_rvec(t_fileio *fio, rvec *item, 
+                         const char *desc, const char *srcfile, int line);
+gmx_bool gmx_fio_writee_ivec(t_fileio *fio, ivec *item, 
+                         const char *desc, const char *srcfile, int line);
+gmx_bool gmx_fio_writee_string(t_fileio *fio, const char *item, 
+                           const char *desc, const char *srcfile, int line);
+
+/* reading or writing, depending on the file's opening mode string */
+gmx_bool gmx_fio_doe_real(t_fileio *fio, real *item, 
+                      const char *desc, const char *srcfile, int line);
+gmx_bool gmx_fio_doe_float(t_fileio *fio, float *item, 
+                       const char *desc, const char *srcfile, int line);
+gmx_bool gmx_fio_doe_double(t_fileio *fio, double *item, 
+                        const char *desc, const char *srcfile, int line);
+gmx_bool gmx_fio_doe_gmx_bool(t_fileio *fio, gmx_bool *item, 
+                     const char *desc, const char *srcfile, int line);
+gmx_bool gmx_fio_doe_int(t_fileio *fio, int *item, 
+                     const char *desc, const char *srcfile, int line);
+gmx_bool gmx_fio_doe_gmx_large_int(t_fileio *fio, gmx_large_int_t *item, 
+                               const char *desc, const char *srcfile, int line);
+gmx_bool gmx_fio_doe_uchar(t_fileio *fio, unsigned char *item, 
+                       const char *desc, const char *srcfile, int line);
+gmx_bool gmx_fio_doe_ushort(t_fileio *fio, unsigned short *item, 
+                       const char *desc, const char *srcfile, int line);
+gmx_bool gmx_fio_doe_rvec(t_fileio *fio, rvec *item, 
+                      const char *desc, const char *srcfile, int line);
+gmx_bool gmx_fio_doe_ivec(t_fileio *fio, ivec *item, 
+                      const char *desc, const char *srcfile, int line);
+gmx_bool gmx_fio_doe_string(t_fileio *fio, char *item, 
+                        const char *desc, const char *srcfile, int line);
+
+
+
+
+/* array reading & writing */
+gmx_bool gmx_fio_nreade_real(t_fileio *fio, real *item, int n, 
+                         const char *desc, const char *srcfile, int line);
+gmx_bool gmx_fio_nreade_float(t_fileio *fio, float *item, int n, 
+                          const char *desc, const char *srcfile, int line);
+gmx_bool gmx_fio_nreade_double(t_fileio *fio, double *item, int n, 
+                           const char *desc, const char *srcfile, int line);
+gmx_bool gmx_fio_nreade_int(t_fileio *fio, int *item, int n, 
+                        const char *desc, const char *srcfile, int line);
+gmx_bool gmx_fio_nreade_gmx_large_int(t_fileio *fio, gmx_large_int_t *item, int n, 
+                                  const char *desc, const char *srcfile, 
+                                  int line);
+gmx_bool gmx_fio_nreade_uchar(t_fileio *fio, unsigned char *item, int n, 
+                          const char *desc, const char *srcfile, int line);
+gmx_bool gmx_fio_nreade_ushort(t_fileio *fio, unsigned short *item, int n, 
+                          const char *desc, const char *srcfile, int line);
+gmx_bool gmx_fio_nreade_rvec(t_fileio *fio, rvec *item, int n, 
+                         const char *desc, const char *srcfile, int line);
+gmx_bool gmx_fio_nreade_ivec(t_fileio *fio, ivec *item, int n, 
+                         const char *desc, const char *srcfile, int line);
+gmx_bool gmx_fio_nreade_string(t_fileio *fio, char *item[], int n, 
+                           const char *desc, const char *srcfile, int line);
+
+gmx_bool gmx_fio_nwritee_real(t_fileio *fio, const real *item, int n, 
+                          const char *desc, const char *srcfile, int line);
+gmx_bool gmx_fio_nwritee_float(t_fileio *fio, const float *item, int n, 
+                           const char *desc, const char *srcfile, int line);
+gmx_bool gmx_fio_nwritee_double(t_fileio *fio, const double *item, int n, 
+                            const char *desc, const char *srcfile, int line);
+gmx_bool gmx_fio_nwritee_int(t_fileio *fio, const int *item, int n, 
+                         const char *desc, const char *srcfile, int line);
+gmx_bool gmx_fio_nwritee_gmx_large_int(t_fileio *fio, 
+                                   const gmx_large_int_t *item, int n,
+                                   const char *desc, const char *srcfile, 
+                                   int line);
+gmx_bool gmx_fio_nwritee_uchar(t_fileio *fio, const unsigned char *item, int n, 
+                           const char *desc, const char *srcfile, int line);
+gmx_bool gmx_fio_nwritee_ushort(t_fileio *fio, const unsigned short *item, int n, 
+                           const char *desc, const char *srcfile, int line);
+gmx_bool gmx_fio_nwritee_rvec(t_fileio *fio, const rvec *item, int n, 
+                          const char *desc, const char *srcfile, int line);
+gmx_bool gmx_fio_nwritee_ivec(t_fileio *fio, const ivec *item, int n, 
+                          const char *desc, const char *srcfile, int line);
+gmx_bool gmx_fio_nwritee_string(t_fileio *fio, const char *item[], int n, 
+                            const char *desc, const char *srcfile, int line);
+
+gmx_bool gmx_fio_ndoe_real(t_fileio *fio, real *item, int n, 
+                       const char *desc, const char *srcfile, int line);
+gmx_bool gmx_fio_ndoe_float(t_fileio *fio, float *item, int n, 
+                         const char *desc, const char *srcfile, int line);
+gmx_bool gmx_fio_ndoe_double(t_fileio *fio, double *item, int n, 
+                         const char *desc, const char *srcfile, int line);
+gmx_bool gmx_fio_ndoe_gmx_bool(t_fileio *fio, gmx_bool *item, int n, 
+                      const char *desc, const char *srcfile, int line);
+gmx_bool gmx_fio_ndoe_int(t_fileio *fio, int *item, int n, 
+                      const char *desc, const char *srcfile, int line);
+gmx_bool gmx_fio_ndoe_gmx_large_int(t_fileio *fio, gmx_large_int_t *item, int n, 
+                                const char *desc, const char *srcfile, 
+                                int line);
+gmx_bool gmx_fio_ndoe_uchar(t_fileio *fio, unsigned char *item, int n, 
+                        const char *desc, const char *srcfile, int line);
+gmx_bool gmx_fio_ndoe_ushort(t_fileio *fio, unsigned short *item, int n, 
+                        const char *desc, const char *srcfile, int line);
+gmx_bool gmx_fio_ndoe_rvec(t_fileio *fio, rvec *item, int n, 
+                       const char *desc, const char *srcfile, int line);
+gmx_bool gmx_fio_ndoe_ivec(t_fileio *fio, ivec *item, int n, 
+                       const char *desc, const char *srcfile, int line);
+gmx_bool gmx_fio_ndoe_string(t_fileio *fio, char *item[], int n, 
+                         const char *desc, const char *srcfile, int line);
+
+
+
+/* convenience macros */
+#define gmx_fio_read_real(fio, item)           gmx_fio_reade_real(fio, &item, (#item), __FILE__, __LINE__)
+#define gmx_fio_read_float(fio, item)          gmx_fio_reade_float(fio, &item, (#item), __FILE__, __LINE__)
+#define gmx_fio_read_double(fio, item)         gmx_fio_reade_double(fio, &item, (#item), __FILE__, __LINE__)
+#define gmx_fio_read_int(fio, item)            gmx_fio_reade_int(fio, &item, (#item), __FILE__, __LINE__)
+#define gmx_fio_read_gmx_large_int(fio, item)  gmx_fio_reade_gmx_large_int(fio, &item, (#item), __FILE__, __LINE__)
+#define gmx_fio_read_uchar(fio, item)          gmx_fio_reade_uchar(fio, &item, (#item), __FILE__, __LINE__)
+#define gmx_fio_read_ushort(fio, item)         gmx_fio_reade_ushort(fio, &item, (#item), __FILE__, __LINE__)
+#define gmx_fio_read_rvec(fio, item)           gmx_fio_reade_rvec(fio, item, (#item), __FILE__, __LINE__)
+#define gmx_fio_read_ivec(fio, item)           gmx_fio_reade_ivec(fio, item, (#item), __FILE__, __LINE__)
+#define gmx_fio_read_string(fio, item)         gmx_fio_reade_string(fio, item, (#item), __FILE__, __LINE__)
+
+#define gmx_fio_write_real(fio, item)           gmx_fio_writee_real(fio, item, (#item), __FILE__, __LINE__)
+#define gmx_fio_write_float(fio, item)          gmx_fio_writee_float(fio, item, (#item), __FILE__, __LINE__)
+#define gmx_fio_write_double(fio, item)         gmx_fio_writee_double(fio, item, (#item), __FILE__, __LINE__)
+#define gmx_fio_write_int(fio, item)            gmx_fio_writee_int(fio, item, (#item), __FILE__, __LINE__)
+#define gmx_fio_write_gmx_large_int(fio, item)  gmx_fio_writee_gmx_large_int(fio, item, (#item), __FILE__, __LINE__)
+#define gmx_fio_write_uchar(fio, item)          gmx_fio_writee_uchar(fio, item, (#item), __FILE__, __LINE__)
+#define gmx_fio_write_ushort(fio, item)         gmx_fio_writee_ushort(fio, item, (#item), __FILE__, __LINE__)
+#define gmx_fio_write_rvec(fio, item)           gmx_fio_writee_rvec(fio, item, (#item), __FILE__, __LINE__)
+#define gmx_fio_write_ivec(fio, item)           gmx_fio_writee_ivec(fio, item, (#item), __FILE__, __LINE__)
+#define gmx_fio_write_string(fio, item)         gmx_fio_writee_string(fio, item, (#item), __FILE__, __LINE__)
+
+#define gmx_fio_do_real(fio, item)              gmx_fio_doe_real(fio, &item, (#item), __FILE__, __LINE__)
+#define gmx_fio_do_float(fio, item)             gmx_fio_doe_float(fio, &item, (#item), __FILE__, __LINE__)
+#define gmx_fio_do_double(fio, item)            gmx_fio_doe_double(fio, &item, (#item), __FILE__, __LINE__)
+#define gmx_fio_do_gmx_bool(fio, item)              gmx_fio_doe_gmx_bool(fio, &item, (#item), __FILE__, __LINE__)
+#define gmx_fio_do_int(fio, item)               gmx_fio_doe_int(fio, &item, (#item), __FILE__, __LINE__)
+#define gmx_fio_do_gmx_large_int(fio, item)     gmx_fio_doe_gmx_large_int(fio, &item, (#item), __FILE__, __LINE__)
+#define gmx_fio_do_uchar(fio, item)             gmx_fio_doe_uchar(fio, &item, (#item), __FILE__, __LINE__)
+#define gmx_fio_do_ushort(fio, item)            gmx_fio_doe_ushort(fio, &item, (#item), __FILE__, __LINE__)
+#define gmx_fio_do_rvec(fio, item)              gmx_fio_doe_rvec(fio, &item, (#item), __FILE__, __LINE__)
+#define gmx_fio_do_ivec(fio, item)              gmx_fio_doe_ivec(fio, &item, (#item), __FILE__, __LINE__)
+#define gmx_fio_do_string(fio, item)            gmx_fio_doe_string(fio, item, (#item), __FILE__, __LINE__)
+
+
+
+
+#define gmx_fio_nread_real(fio, item, n)            gmx_fio_nreade_real(fio, item, n, (#item), __FILE__, __LINE__)
+#define gmx_fio_nread_float(fio, item, n)           gmx_fio_nreade_float(fio, item, n, (#item), __FILE__, __LINE__)
+#define gmx_fio_nread_double(fio, item, n)          gmx_fio_nreade_double(fio, item, n, (#item), __FILE__, __LINE__)
+#define gmx_fio_nread_int(fio, item, n)             gmx_fio_nreade_int(fio, item, n, (#item), __FILE__, __LINE__)
+#define gmx_fio_nread_gmx_large_int(fio, item, n)   gmx_fio_nreade_gmx_large_int(fio, item, n, (#item), __FILE__, __LINE__)
+#define gmx_fio_nread_uchar(fio, item, n)           gmx_fio_nreade_uchar(fio, item, n, (#item), __FILE__, __LINE__)
+#define gmx_fio_nread_ushort(fio, item, n)          gmx_fio_nreade_ushort(fio, item, n, (#item), __FILE__, __LINE__)
+#define gmx_fio_nread_rvec(fio, item, n)            gmx_fio_nreade_rvec(fio, item, n, (#item), __FILE__, __LINE__)
+#define gmx_fio_nread_ivec(fio, item, n)            gmx_fio_nreade_ivec(fio, item, n, (#item), __FILE__, __LINE__)
+#define gmx_fio_nread_string(fio, item, n)          gmx_fio_nreade_string(fio, item, n, (#item), __FILE__, __LINE__)
+
+#define gmx_fio_nwrite_real(fio, item, n)           gmx_fio_nwritee_real(fio, item, n, (#item), __FILE__, __LINE__)
+#define gmx_fio_nwrite_float(fio, item, n)          gmx_fio_nwritee_float(fio, item, n, (#item), __FILE__, __LINE__)
+#define gmx_fio_nwrite_double(fio, item, n)         gmx_fio_nwritee_double(fio, item, n, (#item), __FILE__, __LINE__)
+#define gmx_fio_nwrite_int(fio, item, n)            gmx_fio_nwritee_int(fio, item, n, (#item), __FILE__, __LINE__)
+#define gmx_fio_nwrite_gmx_large_int(fio, item, n)  gmx_fio_nwritee_gmx_large_int(fio, item, n, (#item), __FILE__, __LINE__)
+#define gmx_fio_nwrite_uchar(fio, item, n)          gmx_fio_nwritee_uchar(fio, item, n, (#item), __FILE__, __LINE__)
+#define gmx_fio_nwrite_ushort(fio, item, n)         gmx_fio_nwritee_ushort(fio, item, n, (#item), __FILE__, __LINE__)
+#define gmx_fio_nwrite_rvec(fio, item, n)           gmx_fio_nwritee_rvec(fio, item, n, (#item), __FILE__, __LINE__)
+#define gmx_fio_nwrite_ivec(fio, item, n)           gmx_fio_nwritee_ivec(fio, item, n, (#item), __FILE__, __LINE__)
+#define gmx_fio_nwrite_string(fio, item, n)         gmx_fio_nwritee_string(fio, item, n, (#item), __FILE__, __LINE__)
+
+#define gmx_fio_ndo_real(fio, item, n)              gmx_fio_ndoe_real(fio, item, n, (#item), __FILE__, __LINE__)
+#define gmx_fio_ndo_float(fio, item, n)             gmx_fio_ndoe_float(fio, item, n, (#item), __FILE__, __LINE__)
+#define gmx_fio_ndo_double(fio, item, n)            gmx_fio_ndoe_double(fio, item, n, (#item), __FILE__, __LINE__)
+#define gmx_fio_ndo_gmx_bool(fio, item, n)              gmx_fio_ndoe_gmx_bool(fio, item, n, (#item), __FILE__, __LINE__)
+#define gmx_fio_ndo_int(fio, item, n)               gmx_fio_ndoe_int(fio, item, n, (#item), __FILE__, __LINE__)
+#define gmx_fio_ndo_gmx_large_int(fio, item, n)     gmx_fio_ndoe_gmx_large_int(fio, item, n, (#item), __FILE__, __LINE__)
+#define gmx_fio_ndo_uchar(fio, item, n)             gmx_fio_ndoe_uchar(fio, item, n, (#item), __FILE__, __LINE__)
+#define gmx_fio_ndo_ushort(fio, item, n)            gmx_fio_ndoe_ushort(fio, item, n, (#item), __FILE__, __LINE__)
+#define gmx_fio_ndo_rvec(fio, item, n)              gmx_fio_ndoe_rvec(fio, item, n, (#item), __FILE__, __LINE__)
+#define gmx_fio_ndo_ivec(fio, item, n)              gmx_fio_ndoe_ivec(fio, item, n, (#item), __FILE__, __LINE__)
+#define gmx_fio_ndo_string(fio, item, n)            gmx_fio_ndoe_string(fio, item, n, (#item), __FILE__, __LINE__)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/gromacs/legacyheaders/mdrun.h b/src/gromacs/legacyheaders/mdrun.h
new file mode 100644 (file)
index 0000000..db0f7d7
--- /dev/null
@@ -0,0 +1,372 @@
+/*
+ * 
+ *                This source code is part of
+ * 
+ *                 G   R   O   M   A   C   S
+ * 
+ *          GROningen MAchine for Chemical Simulations
+ * 
+ *                        VERSION 3.2.0
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * 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.
+
+ * 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:
+ * Gromacs Runs On Most of All Computer Systems
+ */
+
+#ifndef _mdrun_h
+#define _mdrun_h
+
+#include <stdio.h>
+#include <time.h>
+#include "typedefs.h"
+#include "network.h"
+#include "tgroup.h"
+#include "filenm.h"
+#include "mshift.h"
+#include "force.h"
+#include "edsam.h"
+#include "mdebin.h"
+#include "vcm.h"
+#include "vsite.h"
+#include "pull.h"
+#include "update.h"
+#include "membed.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define MD_POLARISE       (1<<2)
+#define MD_IONIZE         (1<<3)
+#define MD_RERUN          (1<<4)
+#define MD_RERUN_VSITE    (1<<5)
+#define MD_FFSCAN         (1<<6)
+#define MD_SEPPOT         (1<<7)
+#define MD_PARTDEC        (1<<9)
+#define MD_DDBONDCHECK    (1<<10)
+#define MD_DDBONDCOMM     (1<<11)
+#define MD_CONFOUT        (1<<12)
+#define MD_REPRODUCIBLE   (1<<13)
+#define MD_READ_RNG       (1<<14)
+#define MD_APPENDFILES    (1<<15)
+#define MD_KEEPANDNUMCPT  (1<<16)
+#define MD_READ_EKIN      (1<<17)
+#define MD_STARTFROMCPT   (1<<18)
+#define MD_RESETCOUNTERSHALFWAY (1<<19)
+
+/* Define a number of flags to better control the information
+ * passed to compute_globals in md.c and global_stat.
+ */
+
+/* We are rerunning the simulation */
+#define CGLO_RERUNMD        (1<<1)
+/* we are computing the kinetic energy from average velocities */
+#define CGLO_EKINAVEVEL     (1<<2)
+/* we are removing the center of mass momenta */
+#define CGLO_STOPCM         (1<<3)
+/* bGStat is defined in do_md */
+#define CGLO_GSTAT          (1<<4)
+/* Sum the energy terms in global computation */
+#define CGLO_ENERGY         (1<<6)
+/* Sum the kinetic energy terms in global computation */
+#define CGLO_TEMPERATURE    (1<<7)
+/* Sum the kinetic energy terms in global computation */
+#define CGLO_PRESSURE       (1<<8)
+/* Sum the constraint term in global computation */
+#define CGLO_CONSTRAINT     (1<<9)
+/* we are using an integrator that requires iteration over some steps - currently not used*/
+#define CGLO_ITERATE        (1<<10)
+/* it is the first time we are iterating (or, only once through is required */
+#define CGLO_FIRSTITERATE   (1<<11)
+/* Reading ekin from the trajectory */
+#define CGLO_READEKIN       (1<<12)
+/* we need to reset the ekin rescaling factor here */
+#define CGLO_SCALEEKIN      (1<<13)
+  
+enum {
+  ddnoSEL, ddnoINTERLEAVE, ddnoPP_PME, ddnoCARTESIAN, ddnoNR
+};
+
+typedef struct {
+  double real;
+#ifdef GMX_CRAY_XT3
+  double proc;
+#else
+  clock_t proc;
+#endif
+  double realtime;
+  double proctime;
+  double time_per_step;
+  double last;
+  gmx_large_int_t nsteps_done;
+} gmx_runtime_t;
+
+typedef struct {
+  t_fileio *fp_trn;
+  t_fileio *fp_xtc;
+  int  xtc_prec;
+  ener_file_t fp_ene;
+  const char *fn_cpt;
+  gmx_bool bKeepAndNumCPT;
+  int  eIntegrator;
+  int  simulation_part;
+  FILE *fp_dhdl;
+  FILE *fp_field;
+} gmx_mdoutf_t;
+
+/* Variables for temporary use with the deform option,
+ * used in runner.c and md.c.
+ * (These variables should be stored in the tpx file.)
+ */
+extern gmx_large_int_t     deform_init_init_step_tpx;
+extern matrix              deform_init_box_tpx;
+#ifdef GMX_THREADS
+extern tMPI_Thread_mutex_t deform_init_box_mutex;
+
+/* The minimum number of atoms per thread. With fewer atoms than this,
+ * the number of threads will get lowered.
+ */
+#define MIN_ATOMS_PER_THREAD    90
+#endif
+
+
+typedef double gmx_integrator_t(FILE *log,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 *inputrec,
+                               gmx_mtop_t *mtop,t_fcdata *fcd,
+                               t_state *state,
+                               t_mdatoms *mdatoms,
+                               t_nrnb *nrnb,gmx_wallcycle_t wcycle,
+                               gmx_edsam_t ed, 
+                               t_forcerec *fr,
+                               int repl_ex_nst,int repl_ex_seed,
+                                gmx_membed_t *membed,
+                               real cpt_period,real max_hours,
+                               const char *deviceOptions,
+                               unsigned long Flags,
+                               gmx_runtime_t *runtime);
+
+typedef struct gmx_global_stat *gmx_global_stat_t;
+
+/* ROUTINES from md.c */
+
+gmx_integrator_t do_md;
+
+gmx_integrator_t do_md_openmm;
+
+/* ROUTINES from minimize.c */
+
+gmx_integrator_t do_steep;
+/* Do steepest descents EM */
+
+gmx_integrator_t do_cg;
+/* Do conjugate gradient EM */
+
+gmx_integrator_t do_lbfgs;
+/* Do conjugate gradient L-BFGS */
+
+gmx_integrator_t do_nm;
+/* Do normal mode analysis */
+
+/* ROUTINES from tpi.c */
+
+gmx_integrator_t do_tpi;
+/* Do test particle insertion */
+
+
+/* ROUTINES from sim_util.c */
+void do_pbc_first(FILE *log,matrix box,t_forcerec *fr,
+                        t_graph *graph,rvec x[]);
+
+void do_pbc_first_mtop(FILE *fplog,int ePBC,matrix box,
+                             gmx_mtop_t *mtop,rvec x[]);
+
+void do_pbc_mtop(FILE *fplog,int ePBC,matrix box,
+                       gmx_mtop_t *mtop,rvec x[]);
+
+                    
+/* ROUTINES from stat.c */
+gmx_global_stat_t global_stat_init(t_inputrec *ir);
+
+void global_stat_destroy(gmx_global_stat_t gs);
+
+void global_stat(FILE *log,gmx_global_stat_t gs,
+                       t_commrec *cr,gmx_enerdata_t *enerd,
+                       tensor fvir,tensor svir,rvec mu_tot,
+                       t_inputrec *inputrec,
+                       gmx_ekindata_t *ekind,
+                       gmx_constr_t constr,t_vcm *vcm,
+                       int nsig,real *sig,
+                       gmx_mtop_t *top_global, t_state *state_local, 
+                       gmx_bool bSumEkinhOld, int flags);
+/* Communicate statistics over cr->mpi_comm_mysim */
+
+gmx_mdoutf_t *init_mdoutf(int nfile,const t_filenm fnm[],
+                                int mdrun_flags,
+                                const t_commrec *cr,const t_inputrec *ir,
+                                const output_env_t oenv);
+/* Returns a pointer to a data structure with all output file pointers
+ * and names required by mdrun.
+ */
+
+void done_mdoutf(gmx_mdoutf_t *of);
+/* Close all open output files and free the of pointer */
+
+#define MDOF_X   (1<<0)
+#define MDOF_V   (1<<1)
+#define MDOF_F   (1<<2)
+#define MDOF_XTC (1<<3)
+#define MDOF_CPT (1<<4)
+
+void write_traj(FILE *fplog,t_commrec *cr,
+                      gmx_mdoutf_t *of,
+                      int mdof_flags,
+                      gmx_mtop_t *top_global,
+                      gmx_large_int_t step,double t,
+                      t_state *state_local,t_state *state_global,
+                      rvec *f_local,rvec *f_global,
+                      int *n_xtc,rvec **x_xtc);
+/* Routine that writes frames to trn, xtc and/or checkpoint.
+ * What is written is determined by the mdof_flags defined above.
+ * Data is collected to the master node only when necessary.
+ */
+
+int do_per_step(gmx_large_int_t step,gmx_large_int_t nstep);
+/* Return TRUE if io should be done */
+
+int do_any_io(int step, t_inputrec *ir);
+
+/* ROUTINES from sim_util.c */
+
+double gmx_gettime();
+
+void print_time(FILE *out, gmx_runtime_t *runtime,
+                       gmx_large_int_t step,t_inputrec *ir, t_commrec *cr);
+
+void runtime_start(gmx_runtime_t *runtime);
+
+void runtime_end(gmx_runtime_t *runtime);
+
+void runtime_upd_proc(gmx_runtime_t *runtime);
+/* The processor time should be updated every once in a while,
+ * since on 32-bit manchines it loops after 72 minutes.
+ */
+  
+void print_date_and_time(FILE *log,int pid,const char *title,
+                               const gmx_runtime_t *runtime);
+  
+void nstop_cm(FILE *log,t_commrec *cr,
+                    int start,int nr_atoms,real mass[],rvec x[],rvec v[]);
+
+void finish_run(FILE *log,t_commrec *cr,const char *confout,
+                      t_inputrec *inputrec,
+                      t_nrnb nrnb[],gmx_wallcycle_t wcycle,
+                      gmx_runtime_t *runtime,
+                      gmx_bool bWriteStat);
+
+void calc_enervirdiff(FILE *fplog,int eDispCorr,t_forcerec *fr);
+
+void calc_dispcorr(FILE *fplog,t_inputrec *ir,t_forcerec *fr,
+                         gmx_large_int_t step, int natoms, 
+                         matrix box,real lambda,tensor pres,tensor virial,
+                         real *prescorr, real *enercorr, real *dvdlcorr);
+
+typedef enum
+{
+  LIST_SCALARS =0001,
+  LIST_INPUTREC        =0002,
+  LIST_TOP     =0004,
+  LIST_X       =0010,
+  LIST_V       =0020,
+  LIST_F       =0040,
+  LIST_LOAD    =0100
+} t_listitem;
+
+void check_nnodes_top(char *fn,t_topology *top);
+/* Reset the tpr file to work with one node if necessary */
+
+
+/* check the version */
+void check_ir_old_tpx_versions(t_commrec *cr,FILE *fplog,
+                               t_inputrec *ir,gmx_mtop_t *mtop);
+
+/* Allocate and initialize node-local state entries. */
+void set_state_entries(t_state *state,const t_inputrec *ir,int nnodes);
+
+/* Broadcast the data for a simulation, and allocate node-specific settings
+   such as rng generators. */
+void init_parallel(FILE *log, t_commrec *cr, t_inputrec *inputrec,
+                          gmx_mtop_t *mtop);
+
+
+void do_constrain_first(FILE *log,gmx_constr_t constr,
+                              t_inputrec *inputrec,t_mdatoms *md,
+                              t_state *state,rvec *f,
+                              t_graph *graph,t_commrec *cr,t_nrnb *nrnb,
+                              t_forcerec *fr, gmx_localtop_t *top, tensor shake_vir); 
+                         
+void dynamic_load_balancing(gmx_bool bVerbose,t_commrec *cr,real capacity[],
+                                  int dimension,t_mdatoms *md,t_topology *top,
+                                  rvec x[],rvec v[],matrix box);
+/* Perform load balancing, i.e. split the particles over processors
+ * based on their coordinates in the "dimension" direction.
+ */
+                                  
+int mdrunner(int nthreads_requested, 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,
+            int nstepout, int resetstep, int nmultisim, int repl_ex_nst,
+             int repl_ex_seed, real pforce,real cpt_period,real max_hours,
+            const char *deviceOptions, unsigned long Flags);
+/* Driver routine, that calls the different methods */
+
+void md_print_warning(const t_commrec *cr,FILE *fplog,const char *buf);
+/* Print a warning message to stderr on the master node
+ * and to fplog if fplog!=NULL.
+ */
+
+void init_md(FILE *fplog,
+                   t_commrec *cr,t_inputrec *ir, const output_env_t oenv, 
+                   double *t,double *t0,
+                   real *lambda,double *lam0,
+                   t_nrnb *nrnb,gmx_mtop_t *mtop,
+                   gmx_update_t *upd,
+                   int nfile,const t_filenm fnm[],
+                   gmx_mdoutf_t **outf,t_mdebin **mdebin,
+                   tensor force_vir,tensor shake_vir,
+                   rvec mu_tot,
+                   gmx_bool *bSimAnn,t_vcm **vcm, 
+                   t_state *state, unsigned long Flags);
+  /* Routine in sim_util.c */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _mdrun_h */
diff --git a/src/gromacs/legacyheaders/membed.h b/src/gromacs/legacyheaders/membed.h
new file mode 100644 (file)
index 0000000..e22362a
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * 
+ *                This source code is part of
+ * 
+ *                 G   R   O   M   A   C   S
+ * 
+ *          GROningen MAchine for Chemical Simulations
+ * 
+ *                        VERSION 3.2.0
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * 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.
+
+ * 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:
+ * Gromacs Runs On Most of All Computer Systems
+ */
+
+#ifndef _gmx_membed_h
+#define _gmx_membed_h
+
+#include "typedefs.h"
+
+/* information about scaling center */
+typedef struct {
+       rvec    xmin;
+       rvec    xmax;
+       rvec    *geom_cent;
+       int    pieces;
+       int    *nidx;
+       atom_id **subindex;
+} pos_ins_t;
+
+/* variables needed in do_md */
+typedef struct {
+  int   it_xy;
+  int   it_z;
+  real  xy_step;
+  real  z_step;
+  rvec  fac;           /* scaling factor */
+  rvec  *r_ins;                /* target coordinates */
+  pos_ins_t *pos_ins;
+} gmx_membed_t;
+
+/* initialisation of membed code */
+extern void init_membed(FILE *fplog, gmx_membed_t *membed, int nfile, const t_filenm fnm[], 
+                       gmx_mtop_t *mtop, t_inputrec *inputrec, t_state *state, t_commrec *cr,
+                       real *cpt);
+
+/* rescaling the coordinates voor de membed code */
+extern void rescale_membed(int step_rel, gmx_membed_t *membed, rvec *x);
+#endif
diff --git a/src/gromacs/legacyheaders/mpelogging.h b/src/gromacs/legacyheaders/mpelogging.h
new file mode 100644 (file)
index 0000000..24e7925
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * 
+ *                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
+ */
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* define USE_MPE if you want MPE logging 
+ *
+ * you then need to link with the appropriate libraries
+ * that come with the mpich distribution (can be found in the
+ * mpe subdirectory */
+/* #define USE_MPE */
+
+/* define BARRIERS if you want to have extra MPI_Barriers
+ * in the code which might help analyzing the MPE logfiles 
+ */
+/* #define BARRIERS */
+#ifdef BARRIERS
+#define GMX_BARRIER(communicator) MPI_Barrier(communicator)
+#else
+#define GMX_BARRIER(communicator)
+#endif
+
+#ifdef USE_MPE
+#define GMX_MPE_LOG(event) MPE_Log_event(event, 0, "")
+#else
+#define GMX_MPE_LOG(event)
+#endif
+
+#ifdef USE_MPE
+#include <mpe.h>
+     /* Define MPE logging events here */
+     /* General events */
+     int ev_timestep1,               ev_timestep2;
+     int ev_ns_start,                ev_ns_finish;
+     int ev_calc_bonds_start,        ev_calc_bonds_finish;
+     int ev_send_coordinates_start,  ev_send_coordinates_finish;
+     int ev_update_fr_start,         ev_update_fr_finish;
+     int ev_clear_rvecs_start,       ev_clear_rvecs_finish;
+     int ev_output_start,            ev_output_finish;
+     int ev_update_start,            ev_update_finish;     
+     int ev_force_start,             ev_force_finish;
+     int ev_do_fnbf_start,           ev_do_fnbf_finish;
+     int ev_test_start,              ev_test_finish;
+     
+     /* COM and enforced rotation pulling */
+     int ev_flexll_start,            ev_flexll_finish;
+     int ev_add_rot_forces_start,    ev_add_rot_forces_finish;
+     int ev_forcecycles_start,       ev_forcecycles_finish;
+     int ev_rotcycles_start,         ev_rotcycles_finish;
+     
+     /* Shift related events*/
+     int ev_shift_start,             ev_shift_finish;     
+     int ev_unshift_start,           ev_unshift_finish;     
+     int ev_mk_mshift_start,         ev_mk_mshift_finish;
+     
+     /* PME related events */
+     int ev_pme_start,               ev_pme_finish;
+     int ev_spread_on_grid_start,    ev_spread_on_grid_finish;
+     int ev_sum_qgrid_start,         ev_sum_qgrid_finish;
+     int ev_gmxfft3d_start,          ev_gmxfft3d_finish;
+     int ev_solve_pme_start,         ev_solve_pme_finish;
+     int ev_gather_f_bsplines_start, ev_gather_f_bsplines_finish;
+     int ev_reduce_start,            ev_reduce_finish;
+     int ev_rscatter_start,          ev_rscatter_finish;
+     int ev_alltoall_start,          ev_alltoall_finish;
+     int ev_pmeredist_start,         ev_pmeredist_finish;
+     int ev_init_pme_start,          ev_init_pme_finish;
+     int ev_global_stat_start,       ev_global_stat_finish;
+     int ev_sum_lrforces_start,      ev_sum_lrforces_finish;
+     int ev_virial_start,            ev_virial_finish;
+     int ev_sort_start,              ev_sort_finish;
+     int ev_sum_qgrid_start,         ev_sum_qgrid_finish;
+     
+     /* Essential dynamics related events */
+     int ev_edsam_start,             ev_edsam_finish;
+     int ev_get_group_x_start,       ev_get_group_x_finish;
+     int ev_ed_apply_cons_start,     ev_ed_apply_cons_finish;
+     int ev_fit_to_reference_start,  ev_fit_to_reference_finish;
+#endif
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/gromacs/legacyheaders/names.h b/src/gromacs/legacyheaders/names.h
new file mode 100644 (file)
index 0000000..bd00ec5
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * 
+ *                This source code is part of
+ * 
+ *                 G   R   O   M   A   C   S
+ * 
+ *          GROningen MAchine for Chemical Simulations
+ * 
+ *                        VERSION 3.2.0
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * 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.
+
+ * 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:
+ * Gromacs Runs On Most of All Computer Systems
+ */
+
+#ifndef _names_h
+#define _names_h
+
+
+#include "typedefs.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* All string arrays are NULL terminated, and therefore have an
+ * extra argument (the +1)
+ * these should correspond to names.c and include/types/enums.h
+ */
+extern const char *epbc_names[epbcNR+1];
+extern const char *etcoupl_names[etcNR+1];
+extern const char *epcoupl_names[epcNR+1];
+extern const char *epcoupltype_names[epctNR+1];
+extern const char *erefscaling_names[erscNR+1];
+extern const char *ens_names[ensNR+1];
+extern const char *ei_names[eiNR+1];
+extern const char *yesno_names[BOOL_NR+1];
+extern const char *bool_names[BOOL_NR+1];
+extern const char *eel_names[eelNR+1];
+extern const char *eewg_names[eewgNR+1];
+extern const char *evdw_names[evdwNR+1];
+extern const char *econstr_names[econtNR+1];
+extern const char *ptype_str[eptNR+1];
+extern const char *egrp_nm[egNR+1];
+extern const char *edisre_names[edrNR+1];
+extern const char *edisreweighting_names[edrwNR+1];
+extern const char *enbf_names[eNBF_NR+1];
+extern const char *ecomb_names[eCOMB_NR+1];
+extern const char *gtypes[egcNR+1];
+extern const char *efep_names[efepNR+1];
+extern const char *separate_dhdl_file_names[efepNR+1];
+extern const char *dhdl_derivatives_names[efepNR+1];
+extern const char *efep_names[efepNR+1];
+extern const char *esol_names[esolNR+1];
+extern const char *enlist_names[enlistNR+1];
+extern const char *edispc_names[edispcNR+1];
+extern const char *ecm_names[ecmNR+1];
+extern const char *eann_names[eannNR+1];
+extern const char *egb_names[egbNR+1];
+extern const char *eis_names[eisNR+1];
+extern const char *esa_names[esaNR+1];
+extern const char *ewt_names[ewtNR+1];
+extern const char *epull_names[epullNR+1];
+extern const char *epullg_names[epullgNR+1];
+extern const char *erotg_names[erotgNR+1];
+extern const char *erotg_originnames[erotgNR+1];
+extern const char *erotg_fitnames[erotgFitNR+1];
+extern const char *eQMmethod_names[eQMmethodNR+1];
+extern const char *eQMbasis_names[eQMbasisNR+1];
+extern const char *eQMMMscheme_names[eQMMMschemeNR+1];
+extern const char *eMultentOpt_names[eMultentOptNR+1];
+
+#define        UNDEFINED               "UNDEFINED"
+#define ENUM_NAME(e,max,names) ((((e)<0)||((e)>=(max)))?UNDEFINED:(names)[e])
+
+#define BOOL(e)        ENUM_NAME(e,BOOL_NR,bool_names)
+#define ENS(e)         ENUM_NAME(e,ensNR,ens_names)
+#define EI(e)          ENUM_NAME(e,eiNR,ei_names)
+#define EPBC(e)        ENUM_NAME(e,epbcNR,epbc_names)
+#define ETCOUPLTYPE(e) ENUM_NAME(e,etcNR,etcoupl_names)
+#define EPCOUPLTYPE(e) ENUM_NAME(e,epcNR,epcoupl_names)
+#define EPCOUPLTYPETYPE(e) ENUM_NAME(e,epctNR,epcoupltype_names)
+#define EREFSCALINGTYPE(e) ENUM_NAME(e,erscNR,erefscaling_names)
+#define EBLOCKS(e)     ENUM_NAME(e,ebNR,eblock_names)
+#define EPARAM(e)      ENUM_NAME(e,epNR,eparam_names)
+#define EELTYPE(e)     ENUM_NAME(e,eelNR,eel_names)
+#define EVDWTYPE(e)    ENUM_NAME(e,evdwNR,evdw_names)
+#define ECONSTRTYPE(e) ENUM_NAME(e,econtNR,econstr_names)
+#define EDISRETYPE(e)  ENUM_NAME(e,edrNR,edisre_names)
+#define EDISREWEIGHTING(e)  ENUM_NAME(e,edrwNR,edisreweighting_names)
+#define ENBFNAME(e)    ENUM_NAME(e,eNBF_NR,enbf_names)
+#define ECOMBNAME(e)   ENUM_NAME(e,eCOMB_NR,ecomb_names)
+#define EFEPTYPE(e)    ENUM_NAME(e,efepNR,efep_names)
+#define SEPDHDLFILETYPE(e) ENUM_NAME(e,sepdhdlfileNR,separate_dhdl_file_names)
+#define DHDLDERIVATIVESTYPE(e) ENUM_NAME(e,dhdlderivativesNR,dhdl_derivatives_names)
+#define ESOLTYPE(e)    ENUM_NAME(e,esolNR,esol_names)
+#define ENLISTTYPE(e)  ENUM_NAME(e,enlistNR,enlist_names)
+#define EDISPCORR(e)   ENUM_NAME(e,edispcNR,edispc_names)
+#define ECOM(e)        ENUM_NAME(e,ecmNR,ecm_names)
+#define EANNEAL(e)      ENUM_NAME(e,eannNR,eann_names)
+#define EGBALGORITHM(e) ENUM_NAME(e,egbNR,egb_names)
+#define ESAALGORITHM(e) ENUM_NAME(e,esaNR,esa_names)
+#define EIMPLICITSOL(e) ENUM_NAME(e,eisNR,eis_names)
+#define EWALLTYPE(e)   ENUM_NAME(e,ewtNR,ewt_names)
+#define EPULLTYPE(e)   ENUM_NAME(e,epullNR,epull_names)
+#define EPULLGEOM(e)   ENUM_NAME(e,epullgNR,epullg_names)
+#define EROTGEOM(e)    ENUM_NAME(e,erotgNR,erotg_names)
+#define EROTORIGIN(e)  ENUM_NAME(e,erotgOriginNR,erotg_originnames)
+#define EROTFIT(e)     ENUM_NAME(e,erotgFitNR,erotg_fitnames)
+#define EQMMETHOD(e)   ENUM_NAME(e,eQMmethodNR,eQMmethod_names)
+#define EQMBASIS(e)    ENUM_NAME(e,eQMbasisNR,eQMbasis_names)
+#define EQMMMSCHEME(e) ENUM_NAME(e,eQMMMschemeNR,eQMMMscheme_names)
+#define EMULTENTOPT(e) ENUM_NAME(e,eMultentOptNR,eMultentOpt_names)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _names_h */
similarity index 100%
rename from include/ns.h
rename to src/gromacs/legacyheaders/ns.h
diff --git a/src/gromacs/legacyheaders/physics.h b/src/gromacs/legacyheaders/physics.h
new file mode 100644 (file)
index 0000000..941fc7e
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+ * 
+ *                This source code is part of
+ * 
+ *                 G   R   O   M   A   C   S
+ * 
+ *          GROningen MAchine for Chemical Simulations
+ * 
+ *                        VERSION 3.2.0
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * 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.
+
+ * 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:
+ * Gromacs Runs On Most of All Computer Systems
+ */
+
+#ifndef _physics_h
+#define _physics_h
+
+/*
+ * Physical constants to be used in Gromacs.
+ * No constants (apart from 0, 1 or 2) should
+ * be anywhere else in the code.
+ */
+
+#include <math.h>
+
+/* we do it anyway. */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef M_PI
+#ifdef _PI
+#define M_PI _PI
+#else
+#define M_PI        3.14159265358979323846
+#endif
+#endif
+
+#define ANGSTROM        (1e-10)                /* Old...       */
+#define KILO            (1e3)                  /* Thousand     */
+#define NANO            (1e-9)                 /* A Number     */
+#define PICO            (1e-12)                /* A Number     */
+#define A2NM            (ANGSTROM/NANO)        /* NANO         */
+#define NM2A            (NANO/ANGSTROM)        /* 10.0         */
+#define RAD2DEG                 (180.0/M_PI)           /* Conversion   */
+#define DEG2RAD                 (M_PI/180.0)           /* id           */
+#define CAL2JOULE       (4.184)                /* id           */
+#define E_CHARGE         (1.60217733e-19)      /* Coulomb      */
+
+#define AMU              (1.6605402e-27)        /* kg           */
+#define BOLTZMANN       (1.380658e-23)         /* (J/K)        */
+#define AVOGADRO        (6.0221367e23)         /* ()           */
+#define RGAS             (BOLTZMANN*AVOGADRO)   /* (J/(mol K))  */
+#define BOLTZ            (RGAS/KILO)            /* (kJ/(mol K)) */
+#define FARADAY          (E_CHARGE*AVOGADRO)    /* (C/mol)      */
+#define ELECTRONVOLT     (E_CHARGE*AVOGADRO/KILO) /* (kJ/mol)   */     
+#define PLANCK1          (6.6262e-34)           /* J s */
+#define PLANCK           (6.6262e-34*AVOGADRO/(PICO*KILO)) /* (kJ/mol) ps */
+
+#define EPSILON0        (5.72765E-4)           /* (e^2 / Na (kJ nm))     
+                                                  == (e^2 mol/(kJ nm)) */
+                                                
+#define SPEED_OF_LIGHT   (2.9979245800E05)      /* nm/ps                */
+#define ATOMICMASS_keV   (940000.0)             /* Atomic mass in keV   */
+#define ELECTRONMASS_keV (512.0)                /* Electron mas in keV  */
+
+/* Improved accuracy (PL & EL, 20090421) */
+#define FACEL           (332.0636930*CAL2JOULE)/* (10 * (ONE_4PI_EPS0)) */
+#define ONE_4PI_EPS0    (FACEL*0.1)            /* 1/(4*pi*e0)*/
+#define PRESFAC           (16.6054)             /* bar / pressure unity */
+#define ENM2DEBYE         48.0321               /* Convert electron nm  *
+                                                * to debye             */
+#define DEBYE2ENM         0.02081941
+/* to convert from a acceleration in (e V)/(amu nm) */
+/* FIELDFAC is also Faraday's constant and E_CHARGE/(1e6 AMU) */
+#define FIELDFAC          (FARADAY/KILO)
+
+/* to convert AU to MD units: */
+#define HARTREE2KJ        4.3597482e-21
+#define BOHR2NM           0.0529177249
+#define HARTREE_BOHR2MD   (HARTREE2KJ*AVOGADRO/BOHR2NM)
+
+
+/* The four basic units */
+#define unit_length   "nm"
+#define unit_time     "ps"
+#define unit_mass     "u"
+#define unit_energy   "kJ/mol"
+
+/* Temperature unit, T in this unit times BOLTZ give energy in unit_energy */
+#define unit_temp_K   "K"
+
+/* Charge unit, electron charge, involves ONE_4PI_EPS0 */
+#define unit_charge_e "e"
+
+/* Pressure unit, pressure in basic units times PRESFAC gives this unit */
+#define unit_pres_bar "bar"
+
+/* Dipole unit, debye, conversion from the unit_charge_e involves ENM2DEBYE */
+#define unit_dipole_D "D"
+
+/* Derived units from basic units only */
+#define unit_vel      unit_length "/" unit_time
+#define unit_volume   unit_length "^3"
+#define unit_invtime  "1/" unit_time
+
+/* Other derived units */
+#define unit_surft_bar unit_pres_bar " " unit_length
+
+/* SI units, conversion from basic units involves NANO, PICO and AMU */
+#define unit_length_SI  "m"
+#define unit_time_SI    "s"
+#define unit_mass_SI    "kg"
+
+#define unit_density_SI unit_mass_SI "/" unit_length_SI "^3"
+#define unit_invvisc_SI unit_length_SI " " unit_time_SI "/" unit_mass_SI
+
+  /* The routines below can be used for converting units from or to GROMACS
+     internal units. */
+  enum { eg2cAngstrom, eg2cNm, eg2cBohr, eg2cKcal_Mole, 
+        eg2cHartree, eg2cHartree_e, eg2cAngstrom3, eg2cCoulomb,
+        eg2cDebye, eg2cElectron, eg2cBuckingham, eg2cNR };
+  
+  /* Convert value x to GROMACS units. Energy -> Energy, Length -> Length etc. 
+     The type of x is deduced from unit, 
+     which should be taken from the enum above. */
+  extern double convert2gmx(double x,int unit);
+  
+  /* Convert value x from GROMACS units to the desired one. 
+     The type of return value is deduced from unit, see above */
+  extern double gmx2convert(double x,int unit);
+
+  /* Convert the string to one of the units supported. Returns -1 if not found. */
+  extern int string2unit(char *string);
+  
+  /* Convert the unit to a strong. Return NULL when unit is out of range. */
+  extern const char *unit2string(int unit);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* _physics_h */
+
+
diff --git a/src/gromacs/legacyheaders/pull_rotation.h b/src/gromacs/legacyheaders/pull_rotation.h
new file mode 100644 (file)
index 0000000..8de318e
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * 
+ *                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
+ */
+
+/*! \file pull_rotation.h
+ *
+ *  @brief Enforced rotation of protein parts or other groups of particles.
+ *
+ *  This file contains routines that are used to enforce rotational motion
+ *  upon a subgroup of particles.  
+ *  
+ */
+
+#ifndef _pull_rotation_h
+#define _pull_rotation_h
+
+#ifdef HAVE_CONFIG_H
+  #include <config.h>
+#endif
+
+#include "vec.h"
+#include "typedefs.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*! \brief Initialize the enforced rotation groups.
+ * 
+ * This routine does the memory allocation for various helper arrays, opens
+ * the output files etc.  
+ *
+ * \param fplog             General output file, normally md.log.
+ * \param ir                Struct containing MD input parameters, among those
+ *                          also the enforced rotation parameters.
+ * \param nfile             Number of entries in the fnm structure.       
+ * \param fnm               The filenames struct containing also the names
+ *                          of the rotation output files.
+ * \param cr                Pointer to MPI communication data.
+ * \param x                 The positions of all MD particles.
+ * \param mtop              Molecular topology.
+ * \param oenv              Needed to open the rotation output xvgr file.
+ * \param Flags             Flags passed over from main, used to determine
+ *                          whether or not we are doing a rerun.
+ */
+extern void init_rot(FILE *fplog,t_inputrec *ir,int nfile,const t_filenm fnm[],
+        t_commrec *cr, rvec *x, matrix box, gmx_mtop_t *mtop, const output_env_t oenv,
+        gmx_bool bVerbose, unsigned long Flags);
+
+
+/*! \brief Make a selection of the home atoms for all enforced rotation groups.
+ *
+ * This routine is similar to dd_make_local_pull_groups, but works only with
+ * domain decomposition. It should be called at every domain decomposition.
+ *
+ * \param dd                Structure containing domain decomposition data.
+ * \param rot               Pointer to all the enforced rotation data.
+ */
+extern void dd_make_local_rotation_groups(gmx_domdec_t *dd,t_rot *rot);
+
+
+/*! \brief Calculation of the enforced rotation potential.
+ * 
+ * This is the main enforced rotation module which is called during every time
+ * step. Here the rotation potential as well as the resulting forces are 
+ * calculated.
+ * 
+ * \param cr                Pointer to MPI communication data.
+ * \param ir                Struct containing MD input parameters, among those
+ * \param box               Simulation box, needed to make group whole.
+ * \param x                 The positions of all the local particles.
+ * \param t                 Time.
+ * \param step              The time step.
+ * \param wcycle            During the potential calculation the wallcycles are
+ *                          counted. Later they enter the dynamic load balancing.
+ * \param bNS               After domain decomposition / neighborsearching several
+ *                          local arrays have to be updated (masses, shifts)
+ */
+extern void do_rotation(t_commrec *cr,t_inputrec *ir,matrix box,rvec x[],real t,
+        gmx_large_int_t step,gmx_wallcycle_t wcycle,gmx_bool bNS);
+
+
+/*! \brief Add the enforced rotation forces to the official force array.
+ * 
+ * Adds the forces from enforced rotation potential to the local forces and
+ * sums up the contributions to the rotation potential from all the nodes. Since
+ * this needs communication, this routine should be called after the SR forces 
+ * have been evaluated (in order not to spoil cycle counts). 
+ * This routine also outputs data to the various rotation output files (e.g.
+ * the potential, the angle of the group, torques and more).
+ * 
+ * \param rot               Pointer to all the enforced rotation data.
+ * \param f                 The local forces to which the rotational forces have
+ *                          to be added.
+ * \param cr                Pointer to MPI communication data.
+ * \param step              The time step, used for output.
+ * \param t                 Time, used for output.
+ */
+extern real add_rot_forces(t_rot *rot, rvec f[], t_commrec *cr, gmx_large_int_t step, real t);
+
+
+/*! \brief Close the enforced rotation output files.
+ *
+ * \param fplog             General output file, normally md.log.
+ * \param rot               Pointer to all the enforced rotation data.
+ */
+extern void finish_rot(FILE *fplog,t_rot *rot);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
diff --git a/src/gromacs/legacyheaders/string2.h b/src/gromacs/legacyheaders/string2.h
new file mode 100644 (file)
index 0000000..0f26e3f
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * 
+ *                This source code is part of
+ * 
+ *                 G   R   O   M   A   C   S
+ * 
+ *          GROningen MAchine for Chemical Simulations
+ * 
+ *                        VERSION 3.2.0
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * 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.
+
+ * 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:
+ * Gromacs Runs On Most of All Computer Systems
+ */
+/*! \file
+ * \brief Generic string handling functions.
+ */
+#ifndef _string2_h
+#define _string2_h
+
+/*
+ *
+ * string2.h
+ * David van der Spoel
+ *
+ */
+
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <time.h>
+#include <errno.h>
+
+/*#include "typedefs.h"*/
+#include "types/simple.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define CONTINUE    '\\'
+#define COMMENTSIGN ';'
+
+int continuing(char *s);
+
+char *fgets2(char *s, int n, FILE *stream);
+
+void strip_comment (char *line);
+
+int break_line (char *line,
+                      char *variable,
+                      char *value);
+
+void upstring (char *str);
+
+void ltrim (char *str);
+
+void rtrim (char *str);
+
+void trim (char *str);
+
+void nice_header (FILE *out,const char *fn);
+
+int gmx_strcasecmp_min(const char *str1, const char *str2);
+int gmx_strncasecmp_min(const char *str1, const char *str2, int n);
+/* This funny version of strcasecmp, is not only case-insensitive,
+ * but also ignores '-' and '_'.
+ */
+
+int gmx_strcasecmp(const char *str1, const char *str2);
+int gmx_strncasecmp(const char *str1, const char *str2, int n);
+
+char *gmx_strdup(const char *src);
+char *gmx_strndup(const char *src, int n);
+    
+/** Pattern matcing with wildcards. */
+int gmx_wcmatch(const char *pattern, const char *src);
+
+/** Return value for gmx_wcmatch() when there is no match. */
+#define GMX_NO_WCMATCH 1
+
+
+/* this is our implementation of strsep, the thread-safe replacement for
+   strtok */
+char *gmx_strsep(char **stringp, const char *delim);
+
+
+char *wrap_lines(const char *buf,int line_width, int indent,
+                       gmx_bool bIndentFirst);
+/* wraps lines at 'linewidth', indenting all following
+ * lines by 'indent' spaces. A temp buffer is allocated and returned,
+ * which can be disposed of if no longer needed.
+ * If !bIndentFirst, then the first line will not be indented, only 
+ * the lines that are created due to wapping.
+ */
+
+
+char **split(char sep,const char *str);
+/* Implementation of the well-known Perl function split */
+
+gmx_large_int_t str_to_large_int_t(const char *str, char **endptr);
+
+#if ((defined WIN32 || defined _WIN32 || defined WIN64 || defined _WIN64) && !defined __CYGWIN__ && !defined __CYGWIN32__)
+#define snprintf _snprintf
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _string2_h */
diff --git a/src/gromacs/legacyheaders/types/enums.h b/src/gromacs/legacyheaders/types/enums.h
new file mode 100644 (file)
index 0000000..556fc98
--- /dev/null
@@ -0,0 +1,267 @@
+/*
+ * 
+ *                This source code is part of
+ * 
+ *                 G   R   O   M   A   C   S
+ * 
+ *          GROningen MAchine for Chemical Simulations
+ * 
+ *                        VERSION 3.2.0
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * 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.
+
+ * 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:
+ * GRoups of Organic Molecules in ACtion for Science
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* note: these enums should correspond to the names in gmxlib/names.c */
+
+enum {
+  epbcXYZ, epbcNONE, epbcXY, epbcSCREW, epbcNR
+};
+
+enum {
+  etcNO, etcBERENDSEN, etcNOSEHOOVER, etcYES, etcANDERSEN, etcANDERSENINTERVAL, etcVRESCALE, etcNR
+}; /* yes is an alias for berendsen */
+
+enum {
+  epcNO, epcBERENDSEN, epcPARRINELLORAHMAN, epcISOTROPIC, epcMTTK, epcNR
+}; /* isotropic is an alias for berendsen */
+
+/* trotter decomposition extended variable parts */
+enum {
+  etrtNONE, etrtNHC, etrtBAROV, etrtBARONHC, etrtNHC2, etrtBAROV2, etrtBARONHC2, 
+  etrtVELOCITY1, etrtVELOCITY2, etrtPOSITION, etrtSKIPALL, etrtNR
+};
+
+/* sequenced parts of the trotter decomposition */
+enum {
+  ettTSEQ0,  ettTSEQ1,  ettTSEQ2,  ettTSEQ3,  ettTSEQ4, ettTSEQMAX
+};
+
+enum {
+  epctISOTROPIC, epctSEMIISOTROPIC, epctANISOTROPIC,
+  epctSURFACETENSION, epctNR
+};
+
+enum {
+  erscNO, erscALL, erscCOM, erscNR
+};
+
+/*
+ * eelNOTUSED1 used to be GB, but to enable generalized born with different
+ * forms of electrostatics (RF, switch, etc.) in the future it is now selected
+ * separately (through the implicit_solvent option).
+ */
+enum {
+  eelCUT,     eelRF,     eelGRF,   eelPME,  eelEWALD,  eelPPPM, 
+  eelPOISSON, eelSWITCH, eelSHIFT, eelUSER, eelGB_NOTUSED, eelRF_NEC, eelENCADSHIFT, 
+  eelPMEUSER, eelPMESWITCH, eelPMEUSERSWITCH, eelRF_ZERO, eelNR
+};
+
+/* Ewald geometry */
+enum { 
+  eewg3D, eewg3DC, eewgNR
+};
+
+#define EEL_RF(e) ((e) == eelRF || (e) == eelGRF || (e) == eelRF_NEC || (e) == eelRF_ZERO )
+
+#define EEL_PME(e)  ((e) == eelPME || (e) == eelPMESWITCH || (e) == eelPMEUSER || (e) == eelPMEUSERSWITCH)
+#define EEL_FULL(e) (EEL_PME(e) || (e) == eelPPPM || (e) == eelPOISSON || (e) == eelEWALD)
+
+#define EEL_SWITCHED(e) ((e) == eelSWITCH || (e) == eelSHIFT || (e) == eelENCADSHIFT || (e) == eelPMESWITCH || (e) == eelPMEUSERSWITCH)
+
+#define EEL_IS_ZERO_AT_CUTOFF(e) (EEL_SWITCHED(e) || (e) == eelRF_ZERO)
+
+#define EEL_MIGHT_BE_ZERO_AT_CUTOFF(e) (EEL_IS_ZERO_AT_CUTOFF(e) || (e) == eelUSER || (e) == eelPMEUSER)
+
+enum {
+  evdwCUT, evdwSWITCH, evdwSHIFT, evdwUSER, evdwENCADSHIFT, evdwNR
+};
+
+#define EVDW_SWITCHED(e) ((e) == evdwSWITCH || (e) == evdwSHIFT || (e) == evdwENCADSHIFT)
+
+#define EVDW_IS_ZERO_AT_CUTOFF(e) EVDW_SWITCHED(e)
+
+#define EVDW_MIGHT_BE_ZERO_AT_CUTOFF(e) (EVDW_IS_ZERO_AT_CUTOFF(e) || (e) == evdwUSER)
+
+enum { 
+  ensGRID, ensSIMPLE, ensNR
+};
+
+/* eiVV is normal velocity verlet -- eiVVAK uses 1/2*(KE(t-dt/2)+KE(t+dt/2)) as the kinetic energy, and the half step kinetic
+   energy for temperature control */
+
+enum {
+  eiMD, eiSteep, eiCG, eiBD, eiSD2, eiNM, eiLBFGS, eiTPI, eiTPIC, eiSD1, eiVV, eiVVAK, eiNR
+};
+#define EI_VV(e) ((e) == eiVV || (e) == eiVVAK)
+#define EI_SD(e) ((e) == eiSD1 || (e) == eiSD2)
+#define EI_RANDOM(e) (EI_SD(e) || (e) == eiBD)
+/*above integrators may not conserve momenta*/
+#define EI_DYNAMICS(e) ((e) == eiMD || EI_SD(e) || (e) == eiBD || EI_VV(e))
+#define EI_ENERGY_MINIMIZATION(e) ((e) == eiSteep || (e) == eiCG || (e) == eiLBFGS)
+#define EI_TPI(e) ((e) == eiTPI || (e) == eiTPIC)
+
+#define EI_STATE_VELOCITY(e) ((e) == eiMD || EI_VV(e) || EI_SD(e))
+
+enum {
+  econtLINCS, econtSHAKE, econtNR
+};
+
+enum {
+  edrNone, edrSimple, edrEnsemble, edrNR
+};
+
+enum {
+  edrwConservative, edrwEqual, edrwNR
+};
+
+/* Combination rule things */
+enum { 
+  eCOMB_NONE, eCOMB_GEOMETRIC, eCOMB_ARITHMETIC, eCOMB_GEOM_SIG_EPS, eCOMB_NR 
+};
+
+/* NBF selection */
+enum { 
+  eNBF_NONE, eNBF_LJ, eNBF_BHAM, eNBF_NR 
+};
+
+/* FEP selection */
+enum {
+  efepNO, efepYES, efepNR
+};
+
+/* separate_dhdl_file selection */
+enum
+{
+    /* NOTE: YES is the first one. Do NOT interpret this one as a gmx_bool */
+    sepdhdlfileYES, sepdhdlfileNO, sepdhdlfileNR
+};
+
+/* dhdl_derivatives selection */
+enum
+{
+    /* NOTE: YES is the first one. Do NOT interpret this one as a gmx_bool */
+    dhdlderivativesYES, dhdlderivativesNO, dhdlderivativesNR
+};
+
+/* Solvent model */
+enum {
+  esolNO, esolSPC, esolTIP4P, esolNR
+};
+
+/* Dispersion correction */
+enum {
+  edispcNO, edispcEnerPres, edispcEner, edispcAllEnerPres, edispcAllEner, edispcNR
+}; 
+
+/* Shell types, for completion stuff */
+enum {
+  eshellCSH, eshellBASH, eshellZSH, eshellNR
+}; 
+
+/* Center of mass motion selection */
+enum { 
+  ecmLINEAR, ecmANGULAR, ecmNO, ecmNR 
+};
+
+/* New version of simulated annealing */
+enum { 
+  eannNO, eannSINGLE, eannPERIODIC, eannNR 
+};
+
+/* Implicit solvent algorithms */
+enum { 
+       eisNO, eisGBSA, eisNR 
+};
+
+/* Algorithms for calculating GB radii */
+enum { 
+  egbSTILL, egbHCT, egbOBC, egbNR 
+};
+
+enum {
+  esaAPPROX, esaNO, esaSTILL, esaNR
+};
+
+/* Wall types */
+enum {
+  ewt93, ewt104, ewtTABLE, ewt126, ewtNR
+};
+
+/* Pull stuff */
+enum {
+  epullNO, epullUMBRELLA, epullCONSTRAINT, epullCONST_F, epullNR
+};
+
+enum {
+  epullgDIST, epullgDIR, epullgCYL, epullgPOS, epullgDIRPBC, epullgNR
+};
+
+#define PULL_CYL(pull) ((pull)->eGeom == epullgCYL)
+
+/* Enforced rotation groups */
+enum {
+  erotgISO  , erotgISOPF ,
+  erotgPM   , erotgPMPF  ,
+  erotgRM   , erotgRMPF  ,
+  erotgRM2  , erotgRM2PF ,
+  erotgFLEX , erotgFLEXT ,
+  erotgFLEX2, erotgFLEX2T,
+  erotgNR
+};
+
+enum {
+    erotgFitRMSD, erotgFitNORM, erotgFitNR
+};
+
+/* QMMM */
+enum {
+  eQMmethodAM1, eQMmethodPM3, eQMmethodRHF, 
+  eQMmethodUHF, eQMmethodDFT, eQMmethodB3LYP, eQMmethodMP2, eQMmethodCASSCF, eQMmethodB3LYPLAN,
+  eQMmethodDIRECT, eQMmethodNR
+};
+
+enum {
+  eQMbasisSTO3G, eQMbasisSTO3G2, eQMbasis321G, 
+  eQMbasis321Gp, eQMbasis321dGp, eQMbasis621G,
+  eQMbasis631G, eQMbasis631Gp, eQMbasis631dGp, 
+  eQMbasis6311G, eQMbasisNR
+};
+
+enum {
+  eQMMMschemenormal,eQMMMschemeoniom,eQMMMschemeNR
+};
+
+enum {
+  eMultentOptName, eMultentOptNo, eMultentOptLast, eMultentOptNR
+};
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/src/gromacs/legacyheaders/types/inputrec.h b/src/gromacs/legacyheaders/types/inputrec.h
new file mode 100644 (file)
index 0000000..694fad5
--- /dev/null
@@ -0,0 +1,347 @@
+/*
+ * 
+ *                This source code is part of
+ * 
+ *                 G   R   O   M   A   C   S
+ * 
+ *          GROningen MAchine for Chemical Simulations
+ * 
+ *                        VERSION 3.2.0
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * 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.
+
+ * 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:
+ * GRoups of Organic Molecules in ACtion for Science
+ */
+#ifndef _inputrec_h_
+#define _inputrec_h_
+
+
+#include "simple.h"
+#include "../sysstuff.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+typedef struct {
+  int  n;              /* Number of terms                              */
+  real *a;             /* Coeffients (V / nm )                         */
+  real *phi;           /* Phase angles                                 */
+} t_cosines;
+
+typedef struct {
+  real E0;              /* Field strength (V/nm)                        */
+  real omega;           /* Frequency (1/ps)                             */
+  real t0;              /* Centre of the Gaussian pulse (ps)            */
+  real sigma;           /* Width of the Gaussian pulse (FWHM) (ps)      */
+} t_efield;
+
+#define EGP_EXCL  (1<<0)
+#define EGP_TABLE (1<<1)
+
+typedef struct {
+  int     ngtc;                  /* # T-Coupl groups                        */
+  int     nhchainlength;         /* # of nose-hoover chains per group       */
+  int     ngacc;                 /* # Accelerate groups                     */
+  int     ngfrz;                 /* # Freeze groups                         */
+  int     ngener;               /* # Ener groups                           */
+  real    *nrdf;                /* Nr of degrees of freedom in a group     */
+  real    *ref_t;               /* Coupling temperature        per group   */
+  int     *annealing;            /* No/simple/periodic SA for each group    */
+  int     *anneal_npoints;       /* Number of annealing time points per grp */    
+  real    **anneal_time;         /* For ea. group: Time points              */
+  real    **anneal_temp;         /* For ea. grp: Temperature at these times */
+                                 /* Final temp after all intervals is ref_t */ 
+  real    *tau_t;               /* Tau coupling time                       */
+  rvec    *acc;                         /* Acceleration per group                  */
+  ivec    *nFreeze;             /* Freeze the group in each direction ?    */
+  int     *egp_flags;            /* Exclusions/tables of energy group pairs */
+
+  /* QMMM stuff */
+  int     ngQM;         /* nr of QM groups                              */
+  int     *QMmethod;    /* Level of theory in the QM calculation        */
+  int     *QMbasis;     /* Basisset in the QM calculation               */
+  int     *QMcharge;    /* Total charge in the QM region                */
+  int     *QMmult;      /* Spin multiplicicty in the QM region          */
+  gmx_bool    *bSH;         /* surface hopping (diabatic hop only)          */
+  int     *CASorbitals; /* number of orbiatls in the active space       */
+  int     *CASelectrons;/* number of electrons in the active space      */
+  real    *SAon;        /* at which gap (A.U.) the SA is switched on    */
+  real    *SAoff;
+  int     *SAsteps;     /* in how many steps SA goes from 1-1 to 0.5-0.5*/
+  gmx_bool    *bOPT;
+  gmx_bool    *bTS;
+} t_grpopts;
+
+enum { epgrppbcNONE, epgrppbcREFAT, epgrppbcCOS };
+
+typedef struct {
+  int        nat;      /* Number of atoms in the pull group */
+  atom_id    *ind;     /* The global atoms numbers */
+  int        nat_loc;  /* Number of local pull atoms */
+  int        nalloc_loc; /* Allocation size for ind_loc and weight_loc */ 
+  atom_id    *ind_loc; /* Local pull indices */
+  int        nweight;  /* The number of weights (0 or nat) */
+  real       *weight;  /* Weights (use all 1 when weight==NULL) */
+  real       *weight_loc; /* Weights for the local indices */
+  int        epgrppbc; /* The type of pbc for this pull group, see enum above */
+  atom_id    pbcatom;  /* The reference atom for pbc (global number) */
+  rvec       vec;      /* The pull vector, direction or position */
+  rvec       init;     /* Initial reference displacement */
+  real       rate;     /* Rate of motion (nm/ps) */
+  real       k;        /* force constant */
+  real       kB;       /* force constant for state B */
+  real       wscale;   /* scaling factor for the weights: sum w m/sum w w m */
+  real       invtm;    /* inverse total mass of the group: 1/wscale sum w m */
+  dvec       x;        /* center of mass before update */
+  dvec       xp;       /* center of mass after update before constraining */
+  dvec       dr;       /* The distance from the reference group */
+  double     f_scal;   /* Scalar force for directional pulling */
+  dvec       f;        /* force due to the pulling/constraining */
+} t_pullgrp; 
+
+typedef struct {
+  int        ngrp;        /* number of groups */
+  int        eGeom;       /* pull geometry */
+  ivec       dim;         /* used to select components for constraint */
+  real       cyl_r1;      /* radius of cylinder for dynamic COM */
+  real       cyl_r0;      /* radius of cylinder including switch length */
+  real       constr_tol;  /* absolute tolerance for constraints in (nm) */
+  int        nstxout;     /* Output frequency for pull x */
+  int        nstfout;     /* Output frequency for pull f */
+  int        ePBC;        /* the boundary conditions */
+  int        npbcdim;     /* do pbc in dims 0 <= dim < npbcdim */
+  gmx_bool       bRefAt;      /* do we need reference atoms for a group COM ? */
+  int        cosdim;      /* dimension for cosine weighting, -1 if none */
+  gmx_bool       bVirial;     /* do we need to add the pull virial? */
+  t_pullgrp  *grp;        /* groups to pull/restrain/etc/ */
+  t_pullgrp  *dyna;       /* dynamic groups for use with local constraints */
+  rvec       *rbuf;       /* COM calculation buffer */
+  dvec       *dbuf;       /* COM calculation buffer */
+  double     *dbuf_cyl;   /* cylinder ref. groups COM calculation buffer */
+
+  FILE       *out_x;      /* output file for pull data */
+  FILE       *out_f;      /* output file for pull data */
+} t_pull;
+
+
+/* Abstract types for enforced rotation only defined in pull_rotation.c       */
+typedef struct gmx_enfrot *gmx_enfrot_t;
+typedef struct gmx_enfrotgrp *gmx_enfrotgrp_t;
+
+typedef struct {
+  int        eType;          /* Rotation type for this group                  */
+  int        bMassW;         /* Use mass-weighed positions?                   */
+  int        nat;            /* Number of atoms in the group                  */
+  atom_id    *ind;           /* The global atoms numbers                      */
+  rvec       *x_ref;         /* The reference positions                       */
+  rvec       vec;            /* The normalized rotation vector                */
+  real       rate;           /* Rate of rotation (degree/ps)                  */
+  real       k;              /* Force constant (kJ/(mol nm^2)                 */
+  rvec       pivot;          /* Pivot point of rotation axis (nm)             */
+  int        eFittype;       /* Type of fit to determine actual group angle   */
+  real       slab_dist;      /* Slab distance (nm)                            */
+  real       min_gaussian;   /* Minimum value the gaussian must have so that 
+                                the force is actually evaluated               */
+  real       eps;            /* Additive constant for radial motion2 and
+                                flexible2 potentials (nm^2)                   */
+  gmx_enfrotgrp_t enfrotgrp; /* Stores non-inputrec rotation data per group   */
+} t_rotgrp;
+
+typedef struct {
+  int        ngrp;           /* Number of rotation groups                     */
+  int        nstrout;        /* Output frequency for main rotation outfile    */
+  int        nstsout;        /* Output frequency for per-slab data            */
+  t_rotgrp   *grp;           /* Groups to rotate                              */
+  gmx_enfrot_t enfrot;       /* Stores non-inputrec enforced rotation data    */
+} t_rot;
+
+
+typedef struct {
+  int  eI;              /* Integration method                          */
+  gmx_large_int_t nsteps;      /* number of steps to be taken                  */
+  int  simulation_part; /* Used in checkpointing to separate chunks */
+  gmx_large_int_t init_step;   /* start at a stepcount >0 (used w. tpbconv)    */
+  int  nstcalcenergy;  /* fequency of energy calc. and T/P coupl. upd. */
+  int  ns_type;                /* which ns method should we use?               */
+  int  nstlist;                /* number of steps before pairlist is generated */
+  int  ndelta;         /* number of cells per rlong                    */
+  int  nstcomm;                /* number of steps after which center of mass   */
+                        /* motion is removed                           */
+  int  comm_mode;       /* Center of mass motion removal algorithm      */
+  int nstcheckpoint;    /* checkpointing frequency                      */
+  int nstlog;          /* number of steps after which print to logfile */
+  int nstxout;         /* number of steps after which X is output      */
+  int nstvout;         /* id. for V                                    */
+  int nstfout;         /* id. for F                                    */
+  int nstenergy;       /* number of steps after which energies printed */
+  int nstxtcout;       /* id. for compressed trj (.xtc)                */
+  double init_t;       /* initial time (ps)                            */
+  double delta_t;      /* time step (ps)                               */
+  real xtcprec;         /* precision of xtc file                        */
+  int  nkx,nky,nkz;     /* number of k vectors in each spatial dimension*/
+                        /* for fourier methods for long range electrost.*/
+  int  pme_order;       /* interpolation order for PME                  */
+  real ewald_rtol;      /* Real space tolerance for Ewald, determines   */
+                        /* the real/reciprocal space relative weight    */
+  int  ewald_geometry;  /* normal/3d ewald, or pseudo-2d LR corrections */
+  real epsilon_surface; /* Epsilon for PME dipole correction            */
+  gmx_bool bOptFFT;         /* optimize the fft plan at start               */
+  int  ePBC;           /* Type of periodic boundary conditions         */
+  int  bPeriodicMols;   /* Periodic molecules                           */
+  gmx_bool bContinuation;   /* Continuation run: starting state is correct     */
+  int  etc;            /* temperature coupling                         */
+  int  nsttcouple;      /* interval in steps for temperature coupling   */
+  int  epc;            /* pressure coupling                            */
+  int  epct;           /* pressure coupling type                       */
+  int  nstpcouple;      /* interval in steps for pressure coupling      */
+  real tau_p;          /* pressure coupling time (ps)                  */
+  tensor ref_p;                /* reference pressure (kJ/(mol nm^3))           */
+  tensor compress;     /* compressability ((mol nm^3)/kJ)              */
+  int  refcoord_scaling;/* How to scale absolute reference coordinates  */
+  rvec posres_com;      /* The COM of the posres atoms                  */
+  rvec posres_comB;     /* The B-state COM of the posres atoms          */
+  int  andersen_seed;   /* Random seed for Andersen thermostat.         */
+  real rlist;          /* short range pairlist cut-off (nm)            */
+  real rlistlong;      /* long range pairlist cut-off (nm)             */
+  real rtpi;            /* Radius for test particle insertion           */
+  int  coulombtype;    /* Type of electrostatics treatment             */
+  real rcoulomb_switch; /* Coulomb switch range start (nm)             */
+  real rcoulomb;        /* Coulomb cutoff (nm)                         */
+  real epsilon_r;       /* relative dielectric constant                 */ 
+  real epsilon_rf;      /* relative dielectric constant of the RF       */ 
+  int  implicit_solvent;/* No (=explicit water), or GBSA solvent models */
+  int  gb_algorithm;    /* Algorithm to use for calculation Born radii  */
+  int  nstgbradii;      /* Frequency of updating Generalized Born radii */
+  real rgbradii;        /* Cutoff for GB radii calculation              */
+  real gb_saltconc;     /* Salt concentration (M) for GBSA models       */
+  real gb_epsilon_solvent; /* dielectric coeff. of implicit solvent     */
+  real gb_obc_alpha;    /* 1st scaling factor for Bashford-Case GB      */
+  real gb_obc_beta;     /* 2nd scaling factor for Bashford-Case GB      */
+  real gb_obc_gamma;    /* 3rd scaling factor for Bashford-Case GB      */
+  real gb_dielectric_offset; /* Dielectric offset for Still/HCT/OBC     */
+  int  sa_algorithm;    /* Algorithm for SA part of GBSA                */
+  real sa_surface_tension; /* Energy factor for SA part of GBSA */
+  int  vdwtype;         /* Type of Van der Waals treatment              */
+  real rvdw_switch;     /* Van der Waals switch range start (nm)        */
+  real rvdw;               /* Van der Waals cutoff (nm)                */
+  int  eDispCorr;       /* Perform Long range dispersion corrections    */
+  real tabext;          /* Extension of the table beyond the cut-off,   *
+                        * as well as the table length for 1-4 interac. */
+  real shake_tol;      /* tolerance for shake                          */
+  int  efep;                   /* free energy interpolation no/yes             */
+  double init_lambda;  /* initial value for perturbation variable      */
+  double delta_lambda; /* change of lambda per time step (1/dt)        */
+  int  n_flambda;       /* The number of foreign lambda points          */
+  double *flambda;      /* The foreign lambda values                    */
+  real sc_alpha;        /* free energy soft-core parameter              */
+  int  sc_power;        /* lambda power for soft-core interactions      */
+  real sc_sigma;        /* free energy soft-core sigma when c6 or c12=0 */
+  real sc_sigma_min;    /* minimum FE sc sigma (default: =sg_sigma)     */
+  int  nstdhdl;         /* The frequency for writing to dhdl.xvg        */
+  int  separate_dhdl_file; /* whether to write a separate dhdl.xvg file 
+                              note: NOT a gmx_bool, but an enum */
+  int  dhdl_derivatives;/* whether to calculate+write dhdl derivatives 
+                              note: NOT a gmx_bool, but an enum */
+  int  dh_hist_size;    /* The maximum size for the dH histogram        */
+  double dh_hist_spacing; /* The spacing for the dH histogram           */
+  int  eDisre;          /* Type of distance restraining                 */
+  real dr_fc;              /* force constant for ta_disre                      */
+  int  eDisreWeighting; /* type of weighting of pairs in one restraints        */
+  gmx_bool bDisreMixed;     /* Use comb of time averaged and instan. viol's    */
+  int  nstdisreout;     /* frequency of writing pair distances to enx   */ 
+  real dr_tau;             /* time constant for memory function in disres      */
+  real orires_fc;          /* force constant for orientational restraints  */
+  real orires_tau;         /* time constant for memory function in orires      */
+  int  nstorireout;     /* frequency of writing tr(SD) to enx           */ 
+  real dihre_fc;        /* force constant for dihedral restraints      */
+  real em_stepsize;        /* The stepsize for updating                        */
+  real em_tol;             /* The tolerance                            */
+  int  niter;           /* Number of iterations for convergence of      */
+                        /* steepest descent in relax_shells             */
+  real fc_stepsize;     /* Stepsize for directional minimization        */
+                        /* in relax_shells                              */
+  int  nstcgsteep;      /* number of steps after which a steepest       */
+                        /* descents step is done while doing cg         */
+  int  nbfgscorr;       /* Number of corrections to the hessian to keep */
+  int  eConstrAlg;      /* Type of constraint algorithm                 */
+  int  nProjOrder;      /* Order of the LINCS Projection Algorithm      */
+  real LincsWarnAngle;  /* If bond rotates more than %g degrees, warn   */
+  int  nLincsIter;      /* Number of iterations in the final Lincs step */
+  gmx_bool bShakeSOR;       /* Use successive overrelaxation for shake      */
+  real bd_fric;         /* Friction coefficient for BD (amu/ps)         */
+  int  ld_seed;         /* Random seed for SD and BD                    */
+  int  nwall;           /* The number of walls                          */
+  int  wall_type;       /* The type of walls                            */
+  real wall_r_linpot;   /* The potentail is linear for r<=wall_r_linpot */
+  int  wall_atomtype[2];/* The atom type for walls                      */
+  real wall_density[2]; /* Number density for walls                     */
+  real wall_ewald_zfac; /* Scaling factor for the box for Ewald         */
+  int  ePull;           /* Type of pulling: no, umbrella or constraint  */
+  t_pull *pull;         /* The data for center of mass pulling          */
+  gmx_bool bRot;        /* Calculate enforced rotation potential(s)?    */
+  t_rot *rot;           /* The data for enforced rotation potentials    */
+  real cos_accel;       /* Acceleration for viscosity calculation       */
+  tensor deform;        /* Triclinic deformation velocities (nm/ps)     */
+  int  userint1;        /* User determined parameters                   */
+  int  userint2;
+  int  userint3;
+  int  userint4;
+  real userreal1;
+  real userreal2;
+  real userreal3;
+  real userreal4;
+  t_grpopts opts;      /* Group options                                */
+  t_cosines ex[DIM];   /* Electric field stuff (spatial part)          */
+  t_cosines et[DIM];   /* Electric field stuff (time part)             */
+  gmx_bool bQMMM;           /* QM/MM calculation                            */ 
+  int  QMconstraints;   /* constraints on QM bonds                      */
+  int  QMMMscheme;      /* Scheme: ONIOM or normal                      */
+  real scalefactor;     /* factor for scaling the MM charges in QM calc.*/
+} t_inputrec;
+
+#define DEFORM(ir) ((ir).deform[XX][XX]!=0 || (ir).deform[YY][YY]!=0 || (ir).deform[ZZ][ZZ]!=0 || (ir).deform[YY][XX]!=0 || (ir).deform[ZZ][XX]!=0 || (ir).deform[ZZ][YY]!=0)
+
+#define DYNAMIC_BOX(ir) ((ir).epc!=epcNO || (ir).eI==eiTPI || DEFORM(ir))
+
+#define PRESERVE_SHAPE(ir) ((ir).epc != epcNO && (ir).deform[XX][XX] == 0 && ((ir).epct == epctISOTROPIC || (ir).epct == epctSEMIISOTROPIC))
+
+#define NEED_MUTOT(ir) (((ir).coulombtype==eelEWALD || EEL_PME((ir).coulombtype)) && ((ir).ewald_geometry==eewg3DC || (ir).epsilon_surface!=0))
+
+#define IR_TWINRANGE(ir) ((ir).rlist > 0 && ((ir).rlistlong == 0 || (ir).rlistlong > (ir).rlist))
+
+#define IR_ELEC_FIELD(ir) ((ir).ex[XX].n > 0 || (ir).ex[YY].n > 0 || (ir).ex[ZZ].n > 0)
+
+#define IR_EXCL_FORCES(ir) (EEL_FULL((ir).coulombtype) || (EEL_RF((ir).coulombtype) && (ir).coulombtype != eelRF_NEC) || (ir).implicit_solvent != eisNO)
+/* use pointer definitions of ir here, since that's what's usually used in the code */
+#define IR_NVT_TROTTER(ir) ((((ir)->eI == eiVV) || ((ir)->eI == eiVVAK)) && ((ir)->etc == etcNOSEHOOVER))
+
+#define IR_NPT_TROTTER(ir) ((((ir)->eI == eiVV) || ((ir)->eI == eiVVAK)) && ((ir)->epc == epcMTTK))
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
diff --git a/src/gromacs/legacyheaders/vec.h b/src/gromacs/legacyheaders/vec.h
new file mode 100644 (file)
index 0000000..10d221c
--- /dev/null
@@ -0,0 +1,877 @@
+/*
+ * 
+ *                This source code is part of
+ * 
+ *                 G   R   O   M   A   C   S
+ * 
+ *          GROningen MAchine for Chemical Simulations
+ * 
+ *                        VERSION 3.2.0
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * 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.
+
+ * 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:
+ * Gromacs Runs On Most of All Computer Systems
+ */
+#ifndef _vec_h
+#define _vec_h
+
+/*
+  collection of in-line ready operations:
+  
+  lookup-table optimized scalar operations:
+  real gmx_invsqrt(real x)
+  void vecinvsqrt(real in[],real out[],int n)
+  void vecrecip(real in[],real out[],int n)
+  real sqr(real x)
+  double dsqr(double x)
+  
+  vector operations:
+  void rvec_add(const rvec a,const rvec b,rvec c)  c = a + b
+  void dvec_add(const dvec a,const dvec b,dvec c)  c = a + b
+  void ivec_add(const ivec a,const ivec b,ivec c)  c = a + b
+  void rvec_inc(rvec a,const rvec b)               a += b
+  void dvec_inc(dvec a,const dvec b)               a += b
+  void ivec_inc(ivec a,const ivec b)               a += b
+  void rvec_sub(const rvec a,const rvec b,rvec c)  c = a - b
+  void dvec_sub(const dvec a,const dvec b,dvec c)  c = a - b
+  void rvec_dec(rvec a,rvec b)                     a -= b
+  void copy_rvec(const rvec a,rvec b)              b = a (reals)
+  void copy_dvec(const dvec a,dvec b)              b = a (reals)
+  void copy_ivec(const ivec a,ivec b)              b = a (integers)
+  void ivec_sub(const ivec a,const ivec b,ivec c)  c = a - b
+  void svmul(real a,rvec v1,rvec v2)               v2 = a * v1
+  void dsvmul(double a,dvec v1,dvec v2)            v2 = a * v1
+  void clear_rvec(rvec a)                          a = 0
+  void clear_dvec(dvec a)                          a = 0
+  void clear_ivec(rvec a)                          a = 0
+  void clear_rvecs(int n,rvec v[])
+  real iprod(rvec a,rvec b)                        = a . b (inner product)
+  double diprod(dvec a,dvec b)                     = a . b (inner product)
+  real iiprod(ivec a,ivec b)                       = a . b (integers)
+  real norm2(rvec a)                               = | a |^2 ( = x*y*z )
+  double dnorm2(dvec a)                            = | a |^2 ( = x*y*z )
+  real norm(rvec a)                                = | a |
+  double dnorm(dvec a)                             = | a |
+  void cprod(rvec a,rvec b,rvec c)                 c = a x b (cross product)
+  void dprod(rvec a,rvec b,rvec c)                 c = a x b (cross product)
+  void dprod(rvec a,rvec b,rvec c)                 c = a * b (direct product)
+  real cos_angle(rvec a,rvec b)
+  real cos_angle_no_table(rvec a,rvec b)
+  real distance2(rvec v1, rvec v2)                 = | v2 - v1 |^2
+  void unitv(rvec src,rvec dest)                   dest = src / |src|
+  void unitv_no_table(rvec src,rvec dest)          dest = src / |src|
+  
+  matrix (3x3) operations:
+    ! indicates that dest should not be the same as a, b or src
+    the _ur0 varieties work on matrices that have only zeros
+    in the upper right part, such as box matrices, these varieties
+    could produce less rounding errors, not due to the operations themselves,
+    but because the compiler can easier recombine the operations
+  void copy_mat(matrix a,matrix b)                 b = a
+  void clear_mat(matrix a)                        a = 0
+  void mmul(matrix a,matrix b,matrix dest)     !  dest = a . b
+  void mmul_ur0(matrix a,matrix b,matrix dest)     dest = a . b
+  void transpose(matrix src,matrix dest)       !  dest = src*
+  void tmmul(matrix a,matrix b,matrix dest)    !  dest = a* . b
+  void mtmul(matrix a,matrix b,matrix dest)    !  dest = a . b*
+  real det(matrix a)                              = det(a)
+  void m_add(matrix a,matrix b,matrix dest)       dest = a + b
+  void m_sub(matrix a,matrix b,matrix dest)       dest = a - b
+  void msmul(matrix m1,real r1,matrix dest)       dest = r1 * m1
+  void m_inv_ur0(matrix src,matrix dest)           dest = src^-1
+  void m_inv(matrix src,matrix dest)           !  dest = src^-1
+  void mvmul(matrix a,rvec src,rvec dest)      !  dest = a . src
+  void mvmul_ur0(matrix a,rvec src,rvec dest)      dest = a . src
+  void tmvmul_ur0(matrix a,rvec src,rvec dest)     dest = a* . src
+  real trace(matrix m)                             = trace(m)
+*/
+
+#include "types/simple.h"
+#include "maths.h"
+#include "typedefs.h"
+#include "sysstuff.h"
+#include "macros.h"
+#include "gmx_fatal.h"
+#include "mpelogging.h"
+#include "physics.h"
+
+#ifdef __cplusplus
+extern "C" {
+#elif 0
+} /* avoid screwing up indentation */
+#endif
+
+
+#define EXP_LSB         0x00800000
+#define EXP_MASK        0x7f800000
+#define EXP_SHIFT       23
+#define FRACT_MASK      0x007fffff
+#define FRACT_SIZE      11              /* significant part of fraction */
+#define FRACT_SHIFT     (EXP_SHIFT-FRACT_SIZE)
+#define EXP_ADDR(val)   (((val)&EXP_MASK)>>EXP_SHIFT)
+#define FRACT_ADDR(val) (((val)&(FRACT_MASK|EXP_LSB))>>FRACT_SHIFT)
+
+#define PR_VEC(a)       a[XX],a[YY],a[ZZ]
+
+#ifdef GMX_SOFTWARE_INVSQRT
+extern const unsigned int *  gmx_invsqrt_exptab;
+extern const unsigned int *  gmx_invsqrt_fracttab;
+#endif
+
+
+typedef union 
+{
+  unsigned int bval;
+  float fval;
+} t_convert;
+
+
+#ifdef GMX_SOFTWARE_INVSQRT
+static real gmx_invsqrt(real x)
+{
+  const real  half=0.5;
+  const real  three=3.0;
+  t_convert   result,bit_pattern;
+  unsigned int exp,fract;
+  real        lu;
+  real        y;
+#ifdef GMX_DOUBLE
+  real        y2;
+#endif
+  bit_pattern.fval=x;
+  exp   = EXP_ADDR(bit_pattern.bval);
+  fract = FRACT_ADDR(bit_pattern.bval);
+  result.bval=gmx_invsqrt_exptab[exp] | gmx_invsqrt_fracttab[fract];
+  lu    = result.fval;
+  
+  y=(half*lu*(three-((x*lu)*lu)));
+#ifdef GMX_DOUBLE
+  y2=(half*y*(three-((x*y)*y)));
+  
+  return y2;                    /* 10 Flops */
+#else
+  return y;                     /* 5  Flops */
+#endif
+}
+#define INVSQRT_DONE 
+#endif /* gmx_invsqrt */
+
+#ifdef GMX_POWERPC_SQRT
+static real gmx_invsqrt(real x)
+{
+  const real  half=0.5;
+  const real  three=3.0;
+  t_convert   result,bit_pattern;
+  unsigned int exp,fract;
+  real        lu;
+  real        y;
+#ifdef GMX_DOUBLE
+  real        y2;
+#endif
+
+  lu = __frsqrte((double)x);
+
+  y=(half*lu*(three-((x*lu)*lu)));
+
+#if (GMX_POWERPC_SQRT==2)
+  /* Extra iteration required */
+  y=(half*y*(three-((x*y)*y)));
+#endif
+
+#ifdef GMX_DOUBLE
+  y2=(half*y*(three-((x*y)*y)));
+
+  return y2;                    /* 10 Flops */
+#else
+  return y;                     /* 5  Flops */
+#endif
+}
+#define INVSQRT_DONE
+#endif /* powerpc_invsqrt */
+
+
+#ifndef INVSQRT_DONE
+#define gmx_invsqrt(x) (1.0f/sqrt(x))
+#endif
+
+
+
+
+
+static real sqr(real x)
+{
+  return (x*x);
+}
+
+static gmx_inline double dsqr(double x)
+{
+  return (x*x);
+}
+
+/* Maclaurin series for sinh(x)/x, useful for NH chains and MTTK pressure control 
+   Here, we compute it to 10th order, which might be overkill, 8th is probably enough, 
+   but it's not very much more expensive. */
+
+static gmx_inline real series_sinhx(real x) 
+{
+  real x2 = x*x;
+  return (1 + (x2/6.0)*(1 + (x2/20.0)*(1 + (x2/42.0)*(1 + (x2/72.0)*(1 + (x2/110.0))))));
+}
+
+void vecinvsqrt(real in[],real out[],int n);
+/* Perform out[i]=1.0/sqrt(in[i]) for n elements */
+
+
+void vecrecip(real in[],real out[],int n);
+/* Perform out[i]=1.0/(in[i]) for n elements */
+
+/* Note: If you need a fast version of vecinvsqrt 
+ * and/or vecrecip, call detectcpu() and run the SSE/3DNow/SSE2/Altivec
+ * versions if your hardware supports it.
+ *
+ * To use those routines, your memory HAS TO BE CACHE-ALIGNED.
+ * Use snew_aligned(ptr,size,32) to allocate and sfree_aligned to free.
+ */
+
+
+static gmx_inline void rvec_add(const rvec a,const rvec b,rvec c)
+{
+  real x,y,z;
+  
+  x=a[XX]+b[XX];
+  y=a[YY]+b[YY];
+  z=a[ZZ]+b[ZZ];
+  
+  c[XX]=x;
+  c[YY]=y;
+  c[ZZ]=z;
+}
+
+static gmx_inline void dvec_add(const dvec a,const dvec b,dvec c)
+{
+  double x,y,z;
+  
+  x=a[XX]+b[XX];
+  y=a[YY]+b[YY];
+  z=a[ZZ]+b[ZZ];
+  
+  c[XX]=x;
+  c[YY]=y;
+  c[ZZ]=z;
+}
+
+static gmx_inline void ivec_add(const ivec a,const ivec b,ivec c)
+{
+  int x,y,z;
+  
+  x=a[XX]+b[XX];
+  y=a[YY]+b[YY];
+  z=a[ZZ]+b[ZZ];
+  
+  c[XX]=x;
+  c[YY]=y;
+  c[ZZ]=z;
+}
+
+static gmx_inline void rvec_inc(rvec a,const rvec b)
+{
+  real x,y,z;
+  
+  x=a[XX]+b[XX];
+  y=a[YY]+b[YY];
+  z=a[ZZ]+b[ZZ];
+  
+  a[XX]=x;
+  a[YY]=y;
+  a[ZZ]=z;
+}
+
+static gmx_inline void dvec_inc(dvec a,const dvec b)
+{
+  double x,y,z;
+
+  x=a[XX]+b[XX];
+  y=a[YY]+b[YY];
+  z=a[ZZ]+b[ZZ];
+
+  a[XX]=x;
+  a[YY]=y;
+  a[ZZ]=z;
+}
+
+static gmx_inline void rvec_sub(const rvec a,const rvec b,rvec c)
+{
+  real x,y,z;
+  
+  x=a[XX]-b[XX];
+  y=a[YY]-b[YY];
+  z=a[ZZ]-b[ZZ];
+  
+  c[XX]=x;
+  c[YY]=y;
+  c[ZZ]=z;
+}
+
+static gmx_inline void dvec_sub(const dvec a,const dvec b,dvec c)
+{
+  double x,y,z;
+  
+  x=a[XX]-b[XX];
+  y=a[YY]-b[YY];
+  z=a[ZZ]-b[ZZ];
+  
+  c[XX]=x;
+  c[YY]=y;
+  c[ZZ]=z;
+}
+
+static gmx_inline void rvec_dec(rvec a,const rvec b)
+{
+  real x,y,z;
+  
+  x=a[XX]-b[XX];
+  y=a[YY]-b[YY];
+  z=a[ZZ]-b[ZZ];
+  
+  a[XX]=x;
+  a[YY]=y;
+  a[ZZ]=z;
+}
+
+static gmx_inline void copy_rvec(const rvec a,rvec b)
+{
+  b[XX]=a[XX];
+  b[YY]=a[YY];
+  b[ZZ]=a[ZZ];
+}
+
+static gmx_inline void copy_rvecn(rvec *a,rvec *b,int startn, int endn)
+{
+  int i;
+  for (i=startn;i<endn;i++) {
+    b[i][XX]=a[i][XX];
+    b[i][YY]=a[i][YY];
+    b[i][ZZ]=a[i][ZZ];
+  }
+}
+
+static gmx_inline void copy_dvec(const dvec a,dvec b)
+{
+  b[XX]=a[XX];
+  b[YY]=a[YY];
+  b[ZZ]=a[ZZ];
+}
+
+static gmx_inline void copy_ivec(const ivec a,ivec b)
+{
+  b[XX]=a[XX];
+  b[YY]=a[YY];
+  b[ZZ]=a[ZZ];
+}
+
+static gmx_inline void ivec_sub(const ivec a,const ivec b,ivec c)
+{
+  int x,y,z;
+  
+  x=a[XX]-b[XX];
+  y=a[YY]-b[YY];
+  z=a[ZZ]-b[ZZ];
+  
+  c[XX]=x;
+  c[YY]=y;
+  c[ZZ]=z;
+}
+
+static gmx_inline void copy_mat(matrix a,matrix b)
+{
+  copy_rvec(a[XX],b[XX]);
+  copy_rvec(a[YY],b[YY]);
+  copy_rvec(a[ZZ],b[ZZ]);
+}
+
+static gmx_inline void svmul(real a,const rvec v1,rvec v2)
+{
+  v2[XX]=a*v1[XX];
+  v2[YY]=a*v1[YY];
+  v2[ZZ]=a*v1[ZZ];
+}
+
+static gmx_inline void dsvmul(double a,const dvec v1,dvec v2)
+{
+  v2[XX]=a*v1[XX];
+  v2[YY]=a*v1[YY];
+  v2[ZZ]=a*v1[ZZ];
+}
+
+static gmx_inline real distance2(const rvec v1,const rvec v2)
+{
+  return sqr(v2[XX]-v1[XX]) + sqr(v2[YY]-v1[YY]) + sqr(v2[ZZ]-v1[ZZ]);
+}
+
+static gmx_inline void clear_rvec(rvec a)
+{
+  /* The ibm compiler has problems with inlining this 
+   * when we use a const real variable
+   */
+  a[XX]=0.0;
+  a[YY]=0.0;
+  a[ZZ]=0.0;
+}
+
+static gmx_inline void clear_dvec(dvec a)
+{
+  /* The ibm compiler has problems with inlining this 
+   * when we use a const real variable
+   */
+  a[XX]=0.0;
+  a[YY]=0.0;
+  a[ZZ]=0.0;
+}
+
+static gmx_inline void clear_ivec(ivec a)
+{
+  a[XX]=0;
+  a[YY]=0;
+  a[ZZ]=0;
+}
+
+static gmx_inline void clear_rvecs(int n,rvec v[])
+{
+/*  memset(v[0],0,DIM*n*sizeof(v[0][0])); */
+  int i;
+
+  GMX_MPE_LOG(ev_clear_rvecs_start);
+    
+  for(i=0; (i<n); i++) 
+    clear_rvec(v[i]);
+    
+  GMX_MPE_LOG(ev_clear_rvecs_finish);  
+}
+
+static gmx_inline void clear_mat(matrix a)
+{
+/*  memset(a[0],0,DIM*DIM*sizeof(a[0][0])); */
+  
+  const real nul=0.0;
+  
+  a[XX][XX]=a[XX][YY]=a[XX][ZZ]=nul;
+  a[YY][XX]=a[YY][YY]=a[YY][ZZ]=nul;
+  a[ZZ][XX]=a[ZZ][YY]=a[ZZ][ZZ]=nul;
+}
+
+static gmx_inline real iprod(const rvec a,const rvec b)
+{
+  return (a[XX]*b[XX]+a[YY]*b[YY]+a[ZZ]*b[ZZ]);
+}
+
+static gmx_inline double diprod(const dvec a,const dvec b)
+{
+  return (a[XX]*b[XX]+a[YY]*b[YY]+a[ZZ]*b[ZZ]);
+}
+
+static gmx_inline int iiprod(const ivec a,const ivec b)
+{
+  return (a[XX]*b[XX]+a[YY]*b[YY]+a[ZZ]*b[ZZ]);
+}
+
+static gmx_inline real norm2(const rvec a)
+{
+  return a[XX]*a[XX]+a[YY]*a[YY]+a[ZZ]*a[ZZ];
+}
+
+static gmx_inline double dnorm2(const dvec a)
+{
+  return a[XX]*a[XX]+a[YY]*a[YY]+a[ZZ]*a[ZZ];
+}
+
+static gmx_inline real norm(const rvec a)
+{
+  return (real)sqrt(a[XX]*a[XX]+a[YY]*a[YY]+a[ZZ]*a[ZZ]);
+}
+
+static gmx_inline double dnorm(const dvec a)
+{
+  return sqrt(a[XX]*a[XX]+a[YY]*a[YY]+a[ZZ]*a[ZZ]);
+}
+
+/* WARNING:
+ * Do _not_ use these routines to calculate the angle between two vectors
+ * as acos(cos_angle(u,v)). While it might seem obvious, the acos function
+ * is very flat close to -1 and 1, which will lead to accuracy-loss.
+ * Instead, use the new gmx_angle() function directly.
+ */
+static gmx_inline real 
+cos_angle(const rvec a,const rvec b)
+{
+  /* 
+   *                  ax*bx + ay*by + az*bz
+   * cos-vec (a,b) =  ---------------------
+   *                      ||a|| * ||b||
+   */
+  real   cosval;
+  int    m;
+  double aa,bb,ip,ipa,ipb,ipab; /* For accuracy these must be double! */
+  
+  ip=ipa=ipb=0.0;
+  for(m=0; (m<DIM); m++) {             /* 18           */
+    aa   = a[m];
+    bb   = b[m];
+    ip  += aa*bb;
+    ipa += aa*aa;
+    ipb += bb*bb;
+  }
+  ipab = ipa*ipb;
+  if (ipab > 0)
+    cosval = ip*gmx_invsqrt(ipab);             /*  7           */
+  else 
+    cosval = 1;
+                                       /* 25 TOTAL     */
+  if (cosval > 1.0) 
+    return  1.0; 
+  if (cosval <-1.0) 
+    return -1.0;
+  
+  return cosval;
+}
+
+/* WARNING:
+ * Do _not_ use these routines to calculate the angle between two vectors
+ * as acos(cos_angle(u,v)). While it might seem obvious, the acos function
+ * is very flat close to -1 and 1, which will lead to accuracy-loss.
+ * Instead, use the new gmx_angle() function directly.
+ */
+static gmx_inline real 
+cos_angle_no_table(const rvec a,const rvec b)
+{
+  /* This version does not need the invsqrt lookup table */
+  real   cosval;
+  int    m;
+  double aa,bb,ip,ipa,ipb; /* For accuracy these must be double! */
+  
+  ip=ipa=ipb=0.0;
+  for(m=0; (m<DIM); m++) {             /* 18           */
+    aa   = a[m];
+    bb   = b[m];
+    ip  += aa*bb;
+    ipa += aa*aa;
+    ipb += bb*bb;
+  }
+  cosval=ip/sqrt(ipa*ipb);             /* 12           */
+                                       /* 30 TOTAL     */
+  if (cosval > 1.0) 
+    return  1.0; 
+  if (cosval <-1.0) 
+    return -1.0;
+  
+  return cosval;
+}
+
+
+static gmx_inline void cprod(const rvec a,const rvec b,rvec c)
+{
+  c[XX]=a[YY]*b[ZZ]-a[ZZ]*b[YY];
+  c[YY]=a[ZZ]*b[XX]-a[XX]*b[ZZ];
+  c[ZZ]=a[XX]*b[YY]-a[YY]*b[XX];
+}
+
+static gmx_inline void dcprod(const dvec a,const dvec b,dvec c)
+{
+  c[XX]=a[YY]*b[ZZ]-a[ZZ]*b[YY];
+  c[YY]=a[ZZ]*b[XX]-a[XX]*b[ZZ];
+  c[ZZ]=a[XX]*b[YY]-a[YY]*b[XX];
+}
+
+/* This routine calculates the angle between a & b without any loss of accuracy close to 0/PI.
+ * If you only need cos(theta), use the cos_angle() routines to save a few cycles.
+ * This routine is faster than it might appear, since atan2 is accelerated on many CPUs (e.g. x86).
+ */
+static gmx_inline real 
+gmx_angle(const rvec a, const rvec b)
+{
+    rvec w;
+    real wlen,s;
+    
+    cprod(a,b,w);
+    
+    wlen  = norm(w);
+    s     = iprod(a,b);
+    
+    return atan2(wlen,s);
+}
+
+static gmx_inline void mmul_ur0(matrix a,matrix b,matrix dest)
+{
+  dest[XX][XX]=a[XX][XX]*b[XX][XX];
+  dest[XX][YY]=0.0;
+  dest[XX][ZZ]=0.0;
+  dest[YY][XX]=a[YY][XX]*b[XX][XX]+a[YY][YY]*b[YY][XX];
+  dest[YY][YY]=                    a[YY][YY]*b[YY][YY];
+  dest[YY][ZZ]=0.0;
+  dest[ZZ][XX]=a[ZZ][XX]*b[XX][XX]+a[ZZ][YY]*b[YY][XX]+a[ZZ][ZZ]*b[ZZ][XX];
+  dest[ZZ][YY]=                    a[ZZ][YY]*b[YY][YY]+a[ZZ][ZZ]*b[ZZ][YY];
+  dest[ZZ][ZZ]=                                        a[ZZ][ZZ]*b[ZZ][ZZ];
+}
+
+static gmx_inline void mmul(matrix a,matrix b,matrix dest)
+{
+  dest[XX][XX]=a[XX][XX]*b[XX][XX]+a[XX][YY]*b[YY][XX]+a[XX][ZZ]*b[ZZ][XX];
+  dest[YY][XX]=a[YY][XX]*b[XX][XX]+a[YY][YY]*b[YY][XX]+a[YY][ZZ]*b[ZZ][XX];
+  dest[ZZ][XX]=a[ZZ][XX]*b[XX][XX]+a[ZZ][YY]*b[YY][XX]+a[ZZ][ZZ]*b[ZZ][XX];
+  dest[XX][YY]=a[XX][XX]*b[XX][YY]+a[XX][YY]*b[YY][YY]+a[XX][ZZ]*b[ZZ][YY];
+  dest[YY][YY]=a[YY][XX]*b[XX][YY]+a[YY][YY]*b[YY][YY]+a[YY][ZZ]*b[ZZ][YY];
+  dest[ZZ][YY]=a[ZZ][XX]*b[XX][YY]+a[ZZ][YY]*b[YY][YY]+a[ZZ][ZZ]*b[ZZ][YY];
+  dest[XX][ZZ]=a[XX][XX]*b[XX][ZZ]+a[XX][YY]*b[YY][ZZ]+a[XX][ZZ]*b[ZZ][ZZ];
+  dest[YY][ZZ]=a[YY][XX]*b[XX][ZZ]+a[YY][YY]*b[YY][ZZ]+a[YY][ZZ]*b[ZZ][ZZ];
+  dest[ZZ][ZZ]=a[ZZ][XX]*b[XX][ZZ]+a[ZZ][YY]*b[YY][ZZ]+a[ZZ][ZZ]*b[ZZ][ZZ];
+}
+
+static gmx_inline void transpose(matrix src,matrix dest)
+{
+  dest[XX][XX]=src[XX][XX];
+  dest[YY][XX]=src[XX][YY];
+  dest[ZZ][XX]=src[XX][ZZ];
+  dest[XX][YY]=src[YY][XX];
+  dest[YY][YY]=src[YY][YY];
+  dest[ZZ][YY]=src[YY][ZZ];
+  dest[XX][ZZ]=src[ZZ][XX];
+  dest[YY][ZZ]=src[ZZ][YY];
+  dest[ZZ][ZZ]=src[ZZ][ZZ];
+}
+
+static gmx_inline void tmmul(matrix a,matrix b,matrix dest)
+{
+  /* Computes dest=mmul(transpose(a),b,dest) - used in do_pr_pcoupl */
+  dest[XX][XX]=a[XX][XX]*b[XX][XX]+a[YY][XX]*b[YY][XX]+a[ZZ][XX]*b[ZZ][XX];
+  dest[XX][YY]=a[XX][XX]*b[XX][YY]+a[YY][XX]*b[YY][YY]+a[ZZ][XX]*b[ZZ][YY];
+  dest[XX][ZZ]=a[XX][XX]*b[XX][ZZ]+a[YY][XX]*b[YY][ZZ]+a[ZZ][XX]*b[ZZ][ZZ];
+  dest[YY][XX]=a[XX][YY]*b[XX][XX]+a[YY][YY]*b[YY][XX]+a[ZZ][YY]*b[ZZ][XX];
+  dest[YY][YY]=a[XX][YY]*b[XX][YY]+a[YY][YY]*b[YY][YY]+a[ZZ][YY]*b[ZZ][YY];
+  dest[YY][ZZ]=a[XX][YY]*b[XX][ZZ]+a[YY][YY]*b[YY][ZZ]+a[ZZ][YY]*b[ZZ][ZZ];
+  dest[ZZ][XX]=a[XX][ZZ]*b[XX][XX]+a[YY][ZZ]*b[YY][XX]+a[ZZ][ZZ]*b[ZZ][XX];
+  dest[ZZ][YY]=a[XX][ZZ]*b[XX][YY]+a[YY][ZZ]*b[YY][YY]+a[ZZ][ZZ]*b[ZZ][YY];
+  dest[ZZ][ZZ]=a[XX][ZZ]*b[XX][ZZ]+a[YY][ZZ]*b[YY][ZZ]+a[ZZ][ZZ]*b[ZZ][ZZ];
+}
+
+static gmx_inline void mtmul(matrix a,matrix b,matrix dest)
+{
+  /* Computes dest=mmul(a,transpose(b),dest) - used in do_pr_pcoupl */
+  dest[XX][XX]=a[XX][XX]*b[XX][XX]+a[XX][YY]*b[XX][YY]+a[XX][ZZ]*b[XX][ZZ];
+  dest[XX][YY]=a[XX][XX]*b[YY][XX]+a[XX][YY]*b[YY][YY]+a[XX][ZZ]*b[YY][ZZ];
+  dest[XX][ZZ]=a[XX][XX]*b[ZZ][XX]+a[XX][YY]*b[ZZ][YY]+a[XX][ZZ]*b[ZZ][ZZ];
+  dest[YY][XX]=a[YY][XX]*b[XX][XX]+a[YY][YY]*b[XX][YY]+a[YY][ZZ]*b[XX][ZZ];
+  dest[YY][YY]=a[YY][XX]*b[YY][XX]+a[YY][YY]*b[YY][YY]+a[YY][ZZ]*b[YY][ZZ];
+  dest[YY][ZZ]=a[YY][XX]*b[ZZ][XX]+a[YY][YY]*b[ZZ][YY]+a[YY][ZZ]*b[ZZ][ZZ];
+  dest[ZZ][XX]=a[ZZ][XX]*b[XX][XX]+a[ZZ][YY]*b[XX][YY]+a[ZZ][ZZ]*b[XX][ZZ];
+  dest[ZZ][YY]=a[ZZ][XX]*b[YY][XX]+a[ZZ][YY]*b[YY][YY]+a[ZZ][ZZ]*b[YY][ZZ];
+  dest[ZZ][ZZ]=a[ZZ][XX]*b[ZZ][XX]+a[ZZ][YY]*b[ZZ][YY]+a[ZZ][ZZ]*b[ZZ][ZZ];
+}
+
+static gmx_inline real det(matrix a)
+{
+  return ( a[XX][XX]*(a[YY][YY]*a[ZZ][ZZ]-a[ZZ][YY]*a[YY][ZZ])
+         -a[YY][XX]*(a[XX][YY]*a[ZZ][ZZ]-a[ZZ][YY]*a[XX][ZZ])
+         +a[ZZ][XX]*(a[XX][YY]*a[YY][ZZ]-a[YY][YY]*a[XX][ZZ]));
+}
+
+static gmx_inline void m_add(matrix a,matrix b,matrix dest)
+{
+  dest[XX][XX]=a[XX][XX]+b[XX][XX];
+  dest[XX][YY]=a[XX][YY]+b[XX][YY];
+  dest[XX][ZZ]=a[XX][ZZ]+b[XX][ZZ];
+  dest[YY][XX]=a[YY][XX]+b[YY][XX];
+  dest[YY][YY]=a[YY][YY]+b[YY][YY];
+  dest[YY][ZZ]=a[YY][ZZ]+b[YY][ZZ];
+  dest[ZZ][XX]=a[ZZ][XX]+b[ZZ][XX];
+  dest[ZZ][YY]=a[ZZ][YY]+b[ZZ][YY];
+  dest[ZZ][ZZ]=a[ZZ][ZZ]+b[ZZ][ZZ];
+}
+
+static gmx_inline void m_sub(matrix a,matrix b,matrix dest)
+{
+  dest[XX][XX]=a[XX][XX]-b[XX][XX];
+  dest[XX][YY]=a[XX][YY]-b[XX][YY];
+  dest[XX][ZZ]=a[XX][ZZ]-b[XX][ZZ];
+  dest[YY][XX]=a[YY][XX]-b[YY][XX];
+  dest[YY][YY]=a[YY][YY]-b[YY][YY];
+  dest[YY][ZZ]=a[YY][ZZ]-b[YY][ZZ];
+  dest[ZZ][XX]=a[ZZ][XX]-b[ZZ][XX];
+  dest[ZZ][YY]=a[ZZ][YY]-b[ZZ][YY];
+  dest[ZZ][ZZ]=a[ZZ][ZZ]-b[ZZ][ZZ];
+}
+
+static gmx_inline void msmul(matrix m1,real r1,matrix dest)
+{
+  dest[XX][XX]=r1*m1[XX][XX];
+  dest[XX][YY]=r1*m1[XX][YY];
+  dest[XX][ZZ]=r1*m1[XX][ZZ];
+  dest[YY][XX]=r1*m1[YY][XX];
+  dest[YY][YY]=r1*m1[YY][YY];
+  dest[YY][ZZ]=r1*m1[YY][ZZ];
+  dest[ZZ][XX]=r1*m1[ZZ][XX];
+  dest[ZZ][YY]=r1*m1[ZZ][YY];
+  dest[ZZ][ZZ]=r1*m1[ZZ][ZZ];
+}
+
+static gmx_inline void m_inv_ur0(matrix src,matrix dest)
+{
+  double tmp = src[XX][XX]*src[YY][YY]*src[ZZ][ZZ];
+  if (fabs(tmp) <= 100*GMX_REAL_MIN)
+    gmx_fatal(FARGS,"Can not invert matrix, determinant is zero");
+
+  dest[XX][XX] = 1/src[XX][XX];
+  dest[YY][YY] = 1/src[YY][YY];
+  dest[ZZ][ZZ] = 1/src[ZZ][ZZ];
+  dest[ZZ][XX] = (src[YY][XX]*src[ZZ][YY]*dest[YY][YY]
+                 - src[ZZ][XX])*dest[XX][XX]*dest[ZZ][ZZ];
+  dest[YY][XX] = -src[YY][XX]*dest[XX][XX]*dest[YY][YY];
+  dest[ZZ][YY] = -src[ZZ][YY]*dest[YY][YY]*dest[ZZ][ZZ];
+  dest[XX][YY] = 0.0;
+  dest[XX][ZZ] = 0.0;
+  dest[YY][ZZ] = 0.0;
+}
+
+static gmx_inline void m_inv(matrix src,matrix dest)
+{
+  const real smallreal = (real)1.0e-24;
+  const real largereal = (real)1.0e24;
+  real  deter,c,fc;
+
+  deter = det(src);
+  c     = (real)1.0/deter;
+  fc    = (real)fabs(c);
+  
+  if ((fc <= smallreal) || (fc >= largereal)) 
+    gmx_fatal(FARGS,"Can not invert matrix, determinant = %e",deter);
+
+  dest[XX][XX]= c*(src[YY][YY]*src[ZZ][ZZ]-src[ZZ][YY]*src[YY][ZZ]);
+  dest[XX][YY]=-c*(src[XX][YY]*src[ZZ][ZZ]-src[ZZ][YY]*src[XX][ZZ]);
+  dest[XX][ZZ]= c*(src[XX][YY]*src[YY][ZZ]-src[YY][YY]*src[XX][ZZ]);
+  dest[YY][XX]=-c*(src[YY][XX]*src[ZZ][ZZ]-src[ZZ][XX]*src[YY][ZZ]);
+  dest[YY][YY]= c*(src[XX][XX]*src[ZZ][ZZ]-src[ZZ][XX]*src[XX][ZZ]);
+  dest[YY][ZZ]=-c*(src[XX][XX]*src[YY][ZZ]-src[YY][XX]*src[XX][ZZ]);
+  dest[ZZ][XX]= c*(src[YY][XX]*src[ZZ][YY]-src[ZZ][XX]*src[YY][YY]);
+  dest[ZZ][YY]=-c*(src[XX][XX]*src[ZZ][YY]-src[ZZ][XX]*src[XX][YY]);
+  dest[ZZ][ZZ]= c*(src[XX][XX]*src[YY][YY]-src[YY][XX]*src[XX][YY]);
+}
+
+static gmx_inline void mvmul(matrix a,const rvec src,rvec dest)
+{
+  dest[XX]=a[XX][XX]*src[XX]+a[XX][YY]*src[YY]+a[XX][ZZ]*src[ZZ];
+  dest[YY]=a[YY][XX]*src[XX]+a[YY][YY]*src[YY]+a[YY][ZZ]*src[ZZ];
+  dest[ZZ]=a[ZZ][XX]*src[XX]+a[ZZ][YY]*src[YY]+a[ZZ][ZZ]*src[ZZ];
+}
+
+static gmx_inline void mvmul_ur0(matrix a,const rvec src,rvec dest)
+{
+  dest[ZZ]=a[ZZ][XX]*src[XX]+a[ZZ][YY]*src[YY]+a[ZZ][ZZ]*src[ZZ];
+  dest[YY]=a[YY][XX]*src[XX]+a[YY][YY]*src[YY];
+  dest[XX]=a[XX][XX]*src[XX];
+}
+
+static gmx_inline void tmvmul_ur0(matrix a,const rvec src,rvec dest)
+{
+  dest[XX]=a[XX][XX]*src[XX]+a[YY][XX]*src[YY]+a[ZZ][XX]*src[ZZ];
+  dest[YY]=                  a[YY][YY]*src[YY]+a[ZZ][YY]*src[ZZ];
+  dest[ZZ]=                                    a[ZZ][ZZ]*src[ZZ];
+}
+
+static gmx_inline void unitv(const rvec src,rvec dest)
+{
+  real linv;
+  
+  linv=gmx_invsqrt(norm2(src));
+  dest[XX]=linv*src[XX];
+  dest[YY]=linv*src[YY];
+  dest[ZZ]=linv*src[ZZ];
+}
+
+static gmx_inline void unitv_no_table(const rvec src,rvec dest)
+{
+  real linv;
+  
+  linv=1.0/sqrt(norm2(src));
+  dest[XX]=linv*src[XX];
+  dest[YY]=linv*src[YY];
+  dest[ZZ]=linv*src[ZZ];
+}
+
+static void calc_lll(rvec box,rvec lll)
+{
+  lll[XX] = 2.0*M_PI/box[XX];
+  lll[YY] = 2.0*M_PI/box[YY];
+  lll[ZZ] = 2.0*M_PI/box[ZZ];
+}
+
+static gmx_inline real trace(matrix m)
+{
+  return (m[XX][XX]+m[YY][YY]+m[ZZ][ZZ]);
+}
+
+static gmx_inline real _divide_err(real a,real b,const char *file,int line)
+{
+    if (fabs(b) <= GMX_REAL_MIN) 
+        gmx_fatal(FARGS,"Dividing by zero, file %s, line %d",file,line);
+    return a/b;
+}
+
+static gmx_inline int _mod(int a,int b,char *file,int line)
+{
+  if(b==0)
+    gmx_fatal(FARGS,"Modulo zero, file %s, line %d",file,line);
+  return a % b;
+}
+
+/* Operations on multidimensional rvecs, used e.g. in edsam.c */
+static void m_rveccopy(int dim, rvec *a, rvec *b)
+{
+    /* b = a */
+    int i;
+
+    for (i=0; i<dim; i++)
+        copy_rvec(a[i],b[i]);
+} 
+
+/*computer matrix vectors from base vectors and angles */
+static void matrix_convert(matrix box, rvec vec, rvec angle)
+{
+    svmul(DEG2RAD,angle,angle);
+    box[XX][XX] = vec[XX];
+    box[YY][XX] = vec[YY]*cos(angle[ZZ]);
+    box[YY][YY] = vec[YY]*sin(angle[ZZ]);
+    box[ZZ][XX] = vec[ZZ]*cos(angle[YY]);
+    box[ZZ][YY] = vec[ZZ]
+                         *(cos(angle[XX])-cos(angle[YY])*cos(angle[ZZ]))/sin(angle[ZZ]);
+    box[ZZ][ZZ] = sqrt(sqr(vec[ZZ])
+                       -box[ZZ][XX]*box[ZZ][XX]-box[ZZ][YY]*box[ZZ][YY]);
+}
+
+#define divide_err(a,b) _divide_err((a),(b),__FILE__,__LINE__)
+#define mod(a,b)    _mod((a),(b),__FILE__,__LINE__)
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* _vec_h */
diff --git a/src/gromacs/libgromacs.pc.cmakein b/src/gromacs/libgromacs.pc.cmakein
new file mode 100644 (file)
index 0000000..97c601f
--- /dev/null
@@ -0,0 +1,12 @@
+libdir=@LIB_INSTALL_DIR@
+includedir=@INCL_INSTALL_DIR@
+
+Name: libgromacs
+Description: Gromacs library
+URL: http://www.gromacs.org
+Version: @PROJECT_VERSION@
+Requires: @PKG_FFT@ @PKG_XML@
+Libs.private: -lm @CMAKE_THREAD_LIBS_INIT@
+Libs: -L${libdir} -lmd@LIBSUFFIX@ @PKG_FFT_LIBS@
+Cflags: -I${includedir} @PKG_CFLAGS@
+
diff --git a/src/gromacs/mdlib/CMakeLists.txt b/src/gromacs/mdlib/CMakeLists.txt
new file mode 100644 (file)
index 0000000..ed6abec
--- /dev/null
@@ -0,0 +1,7 @@
+file(GLOB MDLIB_SOURCES *.c)
+
+# Files        called xxx_test.c are test drivers with a main() function for 
+# module xxx.c, so they should not be included in the library
+file(GLOB_RECURSE NOT_MDLIB_SOURCES *_test.c)
+list(REMOVE_ITEM MDLIB_SOURCES ${NOT_MDLIB_SOURCES})
+set(MDLIB_SOURCES ${MDLIB_SOURCES} PARENT_SCOPE)
diff --git a/src/gromacs/mdlib/domdec.c b/src/gromacs/mdlib/domdec.c
new file mode 100644 (file)
index 0000000..abc0874
--- /dev/null
@@ -0,0 +1,8642 @@
+/* -*- mode: c; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; c-file-style: "stroustrup"; -*-
+ *
+ * 
+ * This file is part of Gromacs        Copyright (c) 1991-2008
+ * David van der Spoel, Erik Lindahl, Berk Hess, University of Groningen.
+ *
+ * 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.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org
+ * 
+ * And Hey:
+ * Gnomes, ROck Monsters And Chili Sauce
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <time.h>
+#include <math.h>
+#include <string.h>
+#include <stdlib.h>
+#include "typedefs.h"
+#include "smalloc.h"
+#include "vec.h"
+#include "domdec.h"
+#include "domdec_network.h"
+#include "nrnb.h"
+#include "pbc.h"
+#include "chargegroup.h"
+#include "constr.h"
+#include "mdatoms.h"
+#include "names.h"
+#include "pdbio.h"
+#include "futil.h"
+#include "force.h"
+#include "pme.h"
+#include "pull.h"
+#include "pull_rotation.h"
+#include "gmx_wallcycle.h"
+#include "mdrun.h"
+#include "nsgrid.h"
+#include "shellfc.h"
+#include "mtop_util.h"
+#include "gmxfio.h"
+#include "gmx_ga2la.h"
+#include "gmx_sort.h"
+
+#ifdef GMX_LIB_MPI
+#include <mpi.h>
+#endif
+#ifdef GMX_THREADS
+#include "tmpi.h"
+#endif
+
+#define DDRANK(dd,rank)    (rank)
+#define DDMASTERRANK(dd)   (dd->masterrank)
+
+typedef struct gmx_domdec_master
+{
+    /* The cell boundaries */
+    real **cell_x;
+    /* The global charge group division */
+    int  *ncg;     /* Number of home charge groups for each node */
+    int  *index;   /* Index of nnodes+1 into cg */
+    int  *cg;      /* Global charge group index */
+    int  *nat;     /* Number of home atoms for each node. */
+    int  *ibuf;    /* Buffer for communication */
+    rvec *vbuf;    /* Buffer for state scattering and gathering */
+} gmx_domdec_master_t;
+
+typedef struct
+{
+    /* The numbers of charge groups to send and receive for each cell
+     * that requires communication, the last entry contains the total
+     * number of atoms that needs to be communicated.
+     */
+    int nsend[DD_MAXIZONE+2];
+    int nrecv[DD_MAXIZONE+2];
+    /* The charge groups to send */
+    int *index;
+    int nalloc;
+    /* The atom range for non-in-place communication */
+    int cell2at0[DD_MAXIZONE];
+    int cell2at1[DD_MAXIZONE];
+} gmx_domdec_ind_t;
+
+typedef struct
+{
+    int  np;                   /* Number of grid pulses in this dimension */
+    int  np_dlb;               /* For dlb, for use with edlbAUTO          */
+    gmx_domdec_ind_t *ind;     /* The indices to communicate, size np     */
+    int  np_nalloc;
+    gmx_bool bInPlace;             /* Can we communicate in place?            */
+} gmx_domdec_comm_dim_t;
+
+typedef struct
+{
+    gmx_bool *bCellMin;    /* Temp. var.: is this cell size at the limit     */
+    real *cell_f;      /* State var.: cell boundaries, box relative      */
+    real *old_cell_f;  /* Temp. var.: old cell size                      */
+    real *cell_f_max0; /* State var.: max lower boundary, incl neighbors */
+    real *cell_f_min1; /* State var.: min upper boundary, incl neighbors */
+    real *bound_min;   /* Temp. var.: lower limit for cell boundary      */
+    real *bound_max;   /* Temp. var.: upper limit for cell boundary      */
+    gmx_bool bLimited;     /* State var.: is DLB limited in this dim and row */
+    real *buf_ncd;     /* Temp. var.                                     */
+} gmx_domdec_root_t;
+
+#define DD_NLOAD_MAX 9
+
+/* Here floats are accurate enough, since these variables
+ * only influence the load balancing, not the actual MD results.
+ */
+typedef struct
+{
+    int  nload;
+    float *load;
+    float sum;
+    float max;
+    float sum_m;
+    float cvol_min;
+    float mdf;
+    float pme;
+    int   flags;
+} gmx_domdec_load_t;
+
+typedef struct
+{
+    int  nsc;
+    int  ind_gl;
+    int  ind;
+} gmx_cgsort_t;
+
+typedef struct
+{
+    gmx_cgsort_t *sort1,*sort2;
+    int  sort_nalloc;
+    gmx_cgsort_t *sort_new;
+    int  sort_new_nalloc;
+    int  *ibuf;
+    int  ibuf_nalloc;
+} gmx_domdec_sort_t;
+
+typedef struct
+{
+    rvec *v;
+    int  nalloc;
+} vec_rvec_t;
+
+/* This enum determines the order of the coordinates.
+ * ddnatHOME and ddnatZONE should be first and second,
+ * the others can be ordered as wanted.
+ */
+enum { ddnatHOME, ddnatZONE, ddnatVSITE, ddnatCON, ddnatNR };
+
+enum { edlbAUTO, edlbNO, edlbYES, edlbNR };
+const char *edlb_names[edlbNR] = { "auto", "no", "yes" };
+
+typedef struct
+{
+    int  dim;      /* The dimension                                          */
+    gmx_bool dim_match;/* Tells if DD and PME dims match                         */
+    int  nslab;    /* The number of PME slabs in this dimension              */
+    real *slb_dim_f; /* Cell sizes for determining the PME comm. with SLB    */
+    int  *pp_min;  /* The minimum pp node location, size nslab               */
+    int  *pp_max;  /* The maximum pp node location,size nslab                */
+    int  maxshift; /* The maximum shift for coordinate redistribution in PME */
+} gmx_ddpme_t;
+
+typedef struct
+{
+    real min0;    /* The minimum bottom of this zone                        */
+    real max1;    /* The maximum top of this zone                           */
+    real mch0;    /* The maximum bottom communicaton height for this zone   */
+    real mch1;    /* The maximum top communicaton height for this zone      */
+    real p1_0;    /* The bottom value of the first cell in this zone        */
+    real p1_1;    /* The top value of the first cell in this zone           */
+} gmx_ddzone_t;
+
+typedef struct gmx_domdec_comm
+{
+    /* All arrays are indexed with 0 to dd->ndim (not Cartesian indexing),
+     * unless stated otherwise.
+     */
+
+    /* The number of decomposition dimensions for PME, 0: no PME */
+    int  npmedecompdim;
+    /* The number of nodes doing PME (PP/PME or only PME) */
+    int  npmenodes;
+    int  npmenodes_x;
+    int  npmenodes_y;
+    /* The communication setup including the PME only nodes */
+    gmx_bool bCartesianPP_PME;
+    ivec ntot;
+    int  cartpmedim;
+    int  *pmenodes;          /* size npmenodes                         */
+    int  *ddindex2simnodeid; /* size npmenodes, only with bCartesianPP
+                              * but with bCartesianPP_PME              */
+    gmx_ddpme_t ddpme[2];
+    
+    /* The DD particle-particle nodes only */
+    gmx_bool bCartesianPP;
+    int  *ddindex2ddnodeid; /* size npmenode, only with bCartesianPP_PME */
+    
+    /* The global charge groups */
+    t_block cgs_gl;
+
+    /* Should we sort the cgs */
+    int  nstSortCG;
+    gmx_domdec_sort_t *sort;
+    
+    /* Are there bonded and multi-body interactions between charge groups? */
+    gmx_bool bInterCGBondeds;
+    gmx_bool bInterCGMultiBody;
+
+    /* Data for the optional bonded interaction atom communication range */
+    gmx_bool bBondComm;
+    t_blocka *cglink;
+    char *bLocalCG;
+
+    /* The DLB option */
+    int  eDLB;
+    /* Are we actually using DLB? */
+    gmx_bool bDynLoadBal;
+
+    /* Cell sizes for static load balancing, first index cartesian */
+    real **slb_frac;
+    
+    /* The width of the communicated boundaries */
+    real cutoff_mbody;
+    real cutoff;
+    /* The minimum cell size (including triclinic correction) */
+    rvec cellsize_min;
+    /* For dlb, for use with edlbAUTO */
+    rvec cellsize_min_dlb;
+    /* The lower limit for the DD cell size with DLB */
+    real cellsize_limit;
+    /* Effectively no NB cut-off limit with DLB for systems without PBC? */
+    gmx_bool bVacDLBNoLimit;
+
+    /* tric_dir is only stored here because dd_get_ns_ranges needs it */
+    ivec tric_dir;
+    /* box0 and box_size are required with dim's without pbc and -gcom */
+    rvec box0;
+    rvec box_size;
+    
+    /* The cell boundaries */
+    rvec cell_x0;
+    rvec cell_x1;
+
+    /* The old location of the cell boundaries, to check cg displacements */
+    rvec old_cell_x0;
+    rvec old_cell_x1;
+
+    /* The communication setup and charge group boundaries for the zones */
+    gmx_domdec_zones_t zones;
+    
+    /* The zone limits for DD dimensions 1 and 2 (not 0), determined from
+     * cell boundaries of neighboring cells for dynamic load balancing.
+     */
+    gmx_ddzone_t zone_d1[2];
+    gmx_ddzone_t zone_d2[2][2];
+    
+    /* The coordinate/force communication setup and indices */
+    gmx_domdec_comm_dim_t cd[DIM];
+    /* The maximum number of cells to communicate with in one dimension */
+    int  maxpulse;
+    
+    /* Which cg distribution is stored on the master node */
+    int master_cg_ddp_count;
+    
+    /* The number of cg's received from the direct neighbors */
+    int  zone_ncg1[DD_MAXZONE];
+    
+    /* The atom counts, the range for each type t is nat[t-1] <= at < nat[t] */
+    int  nat[ddnatNR];
+    
+    /* Communication buffer for general use */
+    int  *buf_int;
+    int  nalloc_int;
+
+     /* Communication buffer for general use */
+    vec_rvec_t vbuf;
+    
+    /* Communication buffers only used with multiple grid pulses */
+    int  *buf_int2;
+    int  nalloc_int2;
+    vec_rvec_t vbuf2;
+    
+    /* Communication buffers for local redistribution */
+    int  **cggl_flag;
+    int  cggl_flag_nalloc[DIM*2];
+    rvec **cgcm_state;
+    int  cgcm_state_nalloc[DIM*2];
+    
+    /* Cell sizes for dynamic load balancing */
+    gmx_domdec_root_t **root;
+    real *cell_f_row;
+    real cell_f0[DIM];
+    real cell_f1[DIM];
+    real cell_f_max0[DIM];
+    real cell_f_min1[DIM];
+    
+    /* Stuff for load communication */
+    gmx_bool bRecordLoad;
+    gmx_domdec_load_t *load;
+#ifdef GMX_MPI
+    MPI_Comm *mpi_comm_load;
+#endif
+    /* Cycle counters */
+    float cycl[ddCyclNr];
+    int   cycl_n[ddCyclNr];
+    float cycl_max[ddCyclNr];
+    /* Flop counter (0=no,1=yes,2=with (eFlop-1)*5% noise */
+    int eFlop;
+    double flop;
+    int    flop_n;
+    /* Have often have did we have load measurements */
+    int    n_load_have;
+    /* Have often have we collected the load measurements */
+    int    n_load_collect;
+    
+    /* Statistics */
+    double sum_nat[ddnatNR-ddnatZONE];
+    int    ndecomp;
+    int    nload;
+    double load_step;
+    double load_sum;
+    double load_max;
+    ivec   load_lim;
+    double load_mdf;
+    double load_pme;
+
+    /* The last partition step */
+    gmx_large_int_t partition_step;
+
+    /* Debugging */
+    int  nstDDDump;
+    int  nstDDDumpGrid;
+    int  DD_debug;
+} gmx_domdec_comm_t;
+
+/* The size per charge group of the cggl_flag buffer in gmx_domdec_comm_t */
+#define DD_CGIBS 2
+
+/* The flags for the cggl_flag buffer in gmx_domdec_comm_t */
+#define DD_FLAG_NRCG  65535
+#define DD_FLAG_FW(d) (1<<(16+(d)*2))
+#define DD_FLAG_BW(d) (1<<(16+(d)*2+1))
+
+/* Zone permutation required to obtain consecutive charge groups
+ * for neighbor searching.
+ */
+static const int zone_perm[3][4] = { {0,0,0,0},{1,0,0,0},{3,0,1,2} };
+
+/* dd_zo and dd_zp3/dd_zp2 are set up such that i zones with non-zero
+ * components see only j zones with that component 0.
+ */
+
+/* The DD zone order */
+static const ivec dd_zo[DD_MAXZONE] =
+  {{0,0,0},{1,0,0},{1,1,0},{0,1,0},{0,1,1},{0,0,1},{1,0,1},{1,1,1}};
+
+/* The 3D setup */
+#define dd_z3n  8
+#define dd_zp3n 4
+static const ivec dd_zp3[dd_zp3n] = {{0,0,8},{1,3,6},{2,5,6},{3,5,7}};
+
+/* The 2D setup */
+#define dd_z2n  4
+#define dd_zp2n 2
+static const ivec dd_zp2[dd_zp2n] = {{0,0,4},{1,3,4}};
+
+/* The 1D setup */
+#define dd_z1n  2
+#define dd_zp1n 1
+static const ivec dd_zp1[dd_zp1n] = {{0,0,2}};
+
+/* Factors used to avoid problems due to rounding issues */
+#define DD_CELL_MARGIN       1.0001
+#define DD_CELL_MARGIN2      1.00005
+/* Factor to account for pressure scaling during nstlist steps */
+#define DD_PRES_SCALE_MARGIN 1.02
+
+/* Allowed performance loss before we DLB or warn */
+#define DD_PERF_LOSS 0.05
+
+#define DD_CELL_F_SIZE(dd,di) ((dd)->nc[(dd)->dim[(di)]]+1+(di)*2+1+(di))
+
+/* Use separate MPI send and receive commands
+ * when nnodes <= GMX_DD_NNODES_SENDRECV.
+ * This saves memory (and some copying for small nnodes).
+ * For high parallelization scatter and gather calls are used.
+ */
+#define GMX_DD_NNODES_SENDRECV 4
+
+
+/*
+#define dd_index(n,i) ((((i)[ZZ]*(n)[YY] + (i)[YY])*(n)[XX]) + (i)[XX])
+
+static void index2xyz(ivec nc,int ind,ivec xyz)
+{
+  xyz[XX] = ind % nc[XX];
+  xyz[YY] = (ind / nc[XX]) % nc[YY];
+  xyz[ZZ] = ind / (nc[YY]*nc[XX]);
+}
+*/
+
+/* This order is required to minimize the coordinate communication in PME
+ * which uses decomposition in the x direction.
+ */
+#define dd_index(n,i) ((((i)[XX]*(n)[YY] + (i)[YY])*(n)[ZZ]) + (i)[ZZ])
+
+static void ddindex2xyz(ivec nc,int ind,ivec xyz)
+{
+    xyz[XX] = ind / (nc[YY]*nc[ZZ]);
+    xyz[YY] = (ind / nc[ZZ]) % nc[YY];
+    xyz[ZZ] = ind % nc[ZZ];
+}
+
+static int ddcoord2ddnodeid(gmx_domdec_t *dd,ivec c)
+{
+    int ddindex;
+    int ddnodeid=-1;
+    
+    ddindex = dd_index(dd->nc,c);
+    if (dd->comm->bCartesianPP_PME)
+    {
+        ddnodeid = dd->comm->ddindex2ddnodeid[ddindex];
+    }
+    else if (dd->comm->bCartesianPP)
+    {
+#ifdef GMX_MPI
+        MPI_Cart_rank(dd->mpi_comm_all,c,&ddnodeid);
+#endif
+    }
+    else
+    {
+        ddnodeid = ddindex;
+    }
+    
+    return ddnodeid;
+}
+
+static gmx_bool dynamic_dd_box(gmx_ddbox_t *ddbox,t_inputrec *ir)
+{
+    return (ddbox->nboundeddim < DIM || DYNAMIC_BOX(*ir));
+}
+
+int ddglatnr(gmx_domdec_t *dd,int i)
+{
+    int atnr;
+    
+    if (dd == NULL)
+    {
+        atnr = i + 1;
+    }
+    else
+    {
+        if (i >= dd->comm->nat[ddnatNR-1])
+        {
+            gmx_fatal(FARGS,"glatnr called with %d, which is larger than the local number of atoms (%d)",i,dd->comm->nat[ddnatNR-1]);
+        }
+        atnr = dd->gatindex[i] + 1;
+    }
+    
+    return atnr;
+}
+
+t_block *dd_charge_groups_global(gmx_domdec_t *dd)
+{
+    return &dd->comm->cgs_gl;
+}
+
+static void vec_rvec_init(vec_rvec_t *v)
+{
+    v->nalloc = 0;
+    v->v      = NULL;
+}
+
+static void vec_rvec_check_alloc(vec_rvec_t *v,int n)
+{
+    if (n > v->nalloc)
+    {
+        v->nalloc = over_alloc_dd(n);
+        srenew(v->v,v->nalloc);
+    }
+}
+
+void dd_store_state(gmx_domdec_t *dd,t_state *state)
+{
+    int i;
+    
+    if (state->ddp_count != dd->ddp_count)
+    {
+        gmx_incons("The state does not the domain decomposition state");
+    }
+    
+    state->ncg_gl = dd->ncg_home;
+    if (state->ncg_gl > state->cg_gl_nalloc)
+    {
+        state->cg_gl_nalloc = over_alloc_dd(state->ncg_gl);
+        srenew(state->cg_gl,state->cg_gl_nalloc);
+    }
+    for(i=0; i<state->ncg_gl; i++)
+    {
+        state->cg_gl[i] = dd->index_gl[i];
+    }
+    
+    state->ddp_count_cg_gl = dd->ddp_count;
+}
+
+gmx_domdec_zones_t *domdec_zones(gmx_domdec_t *dd)
+{
+    return &dd->comm->zones;
+}
+
+void dd_get_ns_ranges(gmx_domdec_t *dd,int icg,
+                      int *jcg0,int *jcg1,ivec shift0,ivec shift1)
+{
+    gmx_domdec_zones_t *zones;
+    int izone,d,dim;
+
+    zones = &dd->comm->zones;
+
+    izone = 0;
+    while (icg >= zones->izone[izone].cg1)
+    {
+        izone++;
+    }
+    
+    if (izone == 0)
+    {
+        *jcg0 = icg;
+    }
+    else if (izone < zones->nizone)
+    {
+        *jcg0 = zones->izone[izone].jcg0;
+    }
+    else
+    {
+        gmx_fatal(FARGS,"DD icg %d out of range: izone (%d) >= nizone (%d)",
+                  icg,izone,zones->nizone);
+    }
+        
+    *jcg1 = zones->izone[izone].jcg1;
+    
+    for(d=0; d<dd->ndim; d++)
+    {
+        dim = dd->dim[d];
+        shift0[dim] = zones->izone[izone].shift0[dim];
+        shift1[dim] = zones->izone[izone].shift1[dim];
+        if (dd->comm->tric_dir[dim] || (dd->bGridJump && d > 0))
+        {
+            /* A conservative approach, this can be optimized */
+            shift0[dim] -= 1;
+            shift1[dim] += 1;
+        }
+    }
+}
+
+int dd_natoms_vsite(gmx_domdec_t *dd)
+{
+    return dd->comm->nat[ddnatVSITE];
+}
+
+void dd_get_constraint_range(gmx_domdec_t *dd,int *at_start,int *at_end)
+{
+    *at_start = dd->comm->nat[ddnatCON-1];
+    *at_end   = dd->comm->nat[ddnatCON];
+}
+
+void dd_move_x(gmx_domdec_t *dd,matrix box,rvec x[])
+{
+    int  nzone,nat_tot,n,d,p,i,j,at0,at1,zone;
+    int  *index,*cgindex;
+    gmx_domdec_comm_t *comm;
+    gmx_domdec_comm_dim_t *cd;
+    gmx_domdec_ind_t *ind;
+    rvec shift={0,0,0},*buf,*rbuf;
+    gmx_bool bPBC,bScrew;
+    
+    comm = dd->comm;
+    
+    cgindex = dd->cgindex;
+    
+    buf = comm->vbuf.v;
+
+    nzone = 1;
+    nat_tot = dd->nat_home;
+    for(d=0; d<dd->ndim; d++)
+    {
+        bPBC   = (dd->ci[dd->dim[d]] == 0);
+        bScrew = (bPBC && dd->bScrewPBC && dd->dim[d] == XX);
+        if (bPBC)
+        {
+            copy_rvec(box[dd->dim[d]],shift);
+        }
+        cd = &comm->cd[d];
+        for(p=0; p<cd->np; p++)
+        {
+            ind = &cd->ind[p];
+            index = ind->index;
+            n = 0;
+            if (!bPBC)
+            {
+                for(i=0; i<ind->nsend[nzone]; i++)
+                {
+                    at0 = cgindex[index[i]];
+                    at1 = cgindex[index[i]+1];
+                    for(j=at0; j<at1; j++)
+                    {
+                        copy_rvec(x[j],buf[n]);
+                        n++;
+                    }
+                }
+            }
+            else if (!bScrew)
+            {
+                for(i=0; i<ind->nsend[nzone]; i++)
+                {
+                    at0 = cgindex[index[i]];
+                    at1 = cgindex[index[i]+1];
+                    for(j=at0; j<at1; j++)
+                    {
+                        /* We need to shift the coordinates */
+                        rvec_add(x[j],shift,buf[n]);
+                        n++;
+                    }
+                }
+            }
+            else
+            {
+                for(i=0; i<ind->nsend[nzone]; i++)
+                {
+                    at0 = cgindex[index[i]];
+                    at1 = cgindex[index[i]+1];
+                    for(j=at0; j<at1; j++)
+                    {
+                        /* Shift x */
+                        buf[n][XX] = x[j][XX] + shift[XX];
+                        /* Rotate y and z.
+                         * This operation requires a special shift force
+                         * treatment, which is performed in calc_vir.
+                         */
+                        buf[n][YY] = box[YY][YY] - x[j][YY];
+                        buf[n][ZZ] = box[ZZ][ZZ] - x[j][ZZ];
+                        n++;
+                    }
+                }
+            }
+            
+            if (cd->bInPlace)
+            {
+                rbuf = x + nat_tot;
+            }
+            else
+            {
+                rbuf = comm->vbuf2.v;
+            }
+            /* Send and receive the coordinates */
+            dd_sendrecv_rvec(dd, d, dddirBackward,
+                             buf,  ind->nsend[nzone+1],
+                             rbuf, ind->nrecv[nzone+1]);
+            if (!cd->bInPlace)
+            {
+                j = 0;
+                for(zone=0; zone<nzone; zone++)
+                {
+                    for(i=ind->cell2at0[zone]; i<ind->cell2at1[zone]; i++)
+                    {
+                        copy_rvec(rbuf[j],x[i]);
+                        j++;
+                    }
+                }
+            }
+            nat_tot += ind->nrecv[nzone+1];
+        }
+        nzone += nzone;
+    }
+}
+
+void dd_move_f(gmx_domdec_t *dd,rvec f[],rvec *fshift)
+{
+    int  nzone,nat_tot,n,d,p,i,j,at0,at1,zone;
+    int  *index,*cgindex;
+    gmx_domdec_comm_t *comm;
+    gmx_domdec_comm_dim_t *cd;
+    gmx_domdec_ind_t *ind;
+    rvec *buf,*sbuf;
+    ivec vis;
+    int  is;
+    gmx_bool bPBC,bScrew;
+    
+    comm = dd->comm;
+    
+    cgindex = dd->cgindex;
+
+    buf = comm->vbuf.v;
+
+    n = 0;
+    nzone = comm->zones.n/2;
+    nat_tot = dd->nat_tot;
+    for(d=dd->ndim-1; d>=0; d--)
+    {
+        bPBC   = (dd->ci[dd->dim[d]] == 0);
+        bScrew = (bPBC && dd->bScrewPBC && dd->dim[d] == XX);
+        if (fshift == NULL && !bScrew)
+        {
+            bPBC = FALSE;
+        }
+        /* Determine which shift vector we need */
+        clear_ivec(vis);
+        vis[dd->dim[d]] = 1;
+        is = IVEC2IS(vis);
+        
+        cd = &comm->cd[d];
+        for(p=cd->np-1; p>=0; p--) {
+            ind = &cd->ind[p];
+            nat_tot -= ind->nrecv[nzone+1];
+            if (cd->bInPlace)
+            {
+                sbuf = f + nat_tot;
+            }
+            else
+            {
+                sbuf = comm->vbuf2.v;
+                j = 0;
+                for(zone=0; zone<nzone; zone++)
+                {
+                    for(i=ind->cell2at0[zone]; i<ind->cell2at1[zone]; i++)
+                    {
+                        copy_rvec(f[i],sbuf[j]);
+                        j++;
+                    }
+                }
+            }
+            /* Communicate the forces */
+            dd_sendrecv_rvec(dd, d, dddirForward,
+                             sbuf, ind->nrecv[nzone+1],
+                             buf,  ind->nsend[nzone+1]);
+            index = ind->index;
+            /* Add the received forces */
+            n = 0;
+            if (!bPBC)
+            {
+                for(i=0; i<ind->nsend[nzone]; i++)
+                {
+                    at0 = cgindex[index[i]];
+                    at1 = cgindex[index[i]+1];
+                    for(j=at0; j<at1; j++)
+                    {
+                        rvec_inc(f[j],buf[n]);
+                        n++;
+                    }
+                } 
+            }
+            else if (!bScrew)
+            {
+                for(i=0; i<ind->nsend[nzone]; i++)
+                {
+                    at0 = cgindex[index[i]];
+                    at1 = cgindex[index[i]+1];
+                    for(j=at0; j<at1; j++)
+                    {
+                        rvec_inc(f[j],buf[n]);
+                        /* Add this force to the shift force */
+                        rvec_inc(fshift[is],buf[n]);
+                        n++;
+                    }
+                }
+            }
+            else
+            {
+                for(i=0; i<ind->nsend[nzone]; i++)
+                {
+                    at0 = cgindex[index[i]];
+                    at1 = cgindex[index[i]+1];
+                    for(j=at0; j<at1; j++)
+                    {
+                        /* Rotate the force */
+                        f[j][XX] += buf[n][XX];
+                        f[j][YY] -= buf[n][YY];
+                        f[j][ZZ] -= buf[n][ZZ];
+                        if (fshift)
+                        {
+                            /* Add this force to the shift force */
+                            rvec_inc(fshift[is],buf[n]);
+                        }
+                        n++;
+                    }
+                }
+            }
+        }
+        nzone /= 2;
+    }
+}
+
+void dd_atom_spread_real(gmx_domdec_t *dd,real v[])
+{
+    int  nzone,nat_tot,n,d,p,i,j,at0,at1,zone;
+    int  *index,*cgindex;
+    gmx_domdec_comm_t *comm;
+    gmx_domdec_comm_dim_t *cd;
+    gmx_domdec_ind_t *ind;
+    real *buf,*rbuf;
+    
+    comm = dd->comm;
+    
+    cgindex = dd->cgindex;
+    
+    buf = &comm->vbuf.v[0][0];
+
+    nzone = 1;
+    nat_tot = dd->nat_home;
+    for(d=0; d<dd->ndim; d++)
+    {
+        cd = &comm->cd[d];
+        for(p=0; p<cd->np; p++)
+        {
+            ind = &cd->ind[p];
+            index = ind->index;
+            n = 0;
+            for(i=0; i<ind->nsend[nzone]; i++)
+            {
+                at0 = cgindex[index[i]];
+                at1 = cgindex[index[i]+1];
+                for(j=at0; j<at1; j++)
+                {
+                    buf[n] = v[j];
+                    n++;
+                }
+            }
+            
+            if (cd->bInPlace)
+            {
+                rbuf = v + nat_tot;
+            }
+            else
+            {
+                rbuf = &comm->vbuf2.v[0][0];
+            }
+            /* Send and receive the coordinates */
+            dd_sendrecv_real(dd, d, dddirBackward,
+                             buf,  ind->nsend[nzone+1],
+                             rbuf, ind->nrecv[nzone+1]);
+            if (!cd->bInPlace)
+            {
+                j = 0;
+                for(zone=0; zone<nzone; zone++)
+                {
+                    for(i=ind->cell2at0[zone]; i<ind->cell2at1[zone]; i++)
+                    {
+                        v[i] = rbuf[j];
+                        j++;
+                    }
+                }
+            }
+            nat_tot += ind->nrecv[nzone+1];
+        }
+        nzone += nzone;
+    }
+}
+
+void dd_atom_sum_real(gmx_domdec_t *dd,real v[])
+{
+    int  nzone,nat_tot,n,d,p,i,j,at0,at1,zone;
+    int  *index,*cgindex;
+    gmx_domdec_comm_t *comm;
+    gmx_domdec_comm_dim_t *cd;
+    gmx_domdec_ind_t *ind;
+    real *buf,*sbuf;
+    
+    comm = dd->comm;
+    
+    cgindex = dd->cgindex;
+
+    buf = &comm->vbuf.v[0][0];
+
+    n = 0;
+    nzone = comm->zones.n/2;
+    nat_tot = dd->nat_tot;
+    for(d=dd->ndim-1; d>=0; d--)
+    {
+        cd = &comm->cd[d];
+        for(p=cd->np-1; p>=0; p--) {
+            ind = &cd->ind[p];
+            nat_tot -= ind->nrecv[nzone+1];
+            if (cd->bInPlace)
+            {
+                sbuf = v + nat_tot;
+            }
+            else
+            {
+                sbuf = &comm->vbuf2.v[0][0];
+                j = 0;
+                for(zone=0; zone<nzone; zone++)
+                {
+                    for(i=ind->cell2at0[zone]; i<ind->cell2at1[zone]; i++)
+                    {
+                        sbuf[j] = v[i];
+                        j++;
+                    }
+                }
+            }
+            /* Communicate the forces */
+            dd_sendrecv_real(dd, d, dddirForward,
+                             sbuf, ind->nrecv[nzone+1],
+                             buf,  ind->nsend[nzone+1]);
+            index = ind->index;
+            /* Add the received forces */
+            n = 0;
+            for(i=0; i<ind->nsend[nzone]; i++)
+            {
+                at0 = cgindex[index[i]];
+                at1 = cgindex[index[i]+1];
+                for(j=at0; j<at1; j++)
+                {
+                    v[j] += buf[n];
+                    n++;
+                }
+            } 
+        }
+        nzone /= 2;
+    }
+}
+
+static void print_ddzone(FILE *fp,int d,int i,int j,gmx_ddzone_t *zone)
+{
+    fprintf(fp,"zone d0 %d d1 %d d2 %d  min0 %6.3f max1 %6.3f mch0 %6.3f mch1 %6.3f p1_0 %6.3f p1_1 %6.3f\n",
+            d,i,j,
+            zone->min0,zone->max1,
+            zone->mch0,zone->mch0,
+            zone->p1_0,zone->p1_1);
+}
+
+static void dd_sendrecv_ddzone(const gmx_domdec_t *dd,
+                               int ddimind,int direction,
+                               gmx_ddzone_t *buf_s,int n_s,
+                               gmx_ddzone_t *buf_r,int n_r)
+{
+    rvec vbuf_s[5*2],vbuf_r[5*2];
+    int i;
+
+    for(i=0; i<n_s; i++)
+    {
+        vbuf_s[i*2  ][0] = buf_s[i].min0;
+        vbuf_s[i*2  ][1] = buf_s[i].max1;
+        vbuf_s[i*2  ][2] = buf_s[i].mch0;
+        vbuf_s[i*2+1][0] = buf_s[i].mch1;
+        vbuf_s[i*2+1][1] = buf_s[i].p1_0;
+        vbuf_s[i*2+1][2] = buf_s[i].p1_1;
+    }
+
+    dd_sendrecv_rvec(dd, ddimind, direction,
+                     vbuf_s, n_s*2,
+                     vbuf_r, n_r*2);
+
+    for(i=0; i<n_r; i++)
+    {
+        buf_r[i].min0 = vbuf_r[i*2  ][0];
+        buf_r[i].max1 = vbuf_r[i*2  ][1];
+        buf_r[i].mch0 = vbuf_r[i*2  ][2];
+        buf_r[i].mch1 = vbuf_r[i*2+1][0];
+        buf_r[i].p1_0 = vbuf_r[i*2+1][1];
+        buf_r[i].p1_1 = vbuf_r[i*2+1][2];
+    }
+}
+
+static void dd_move_cellx(gmx_domdec_t *dd,gmx_ddbox_t *ddbox,
+                          rvec cell_ns_x0,rvec cell_ns_x1)
+{
+    int  d,d1,dim,dim1,pos,buf_size,i,j,k,p,npulse,npulse_min;
+    gmx_ddzone_t *zp,buf_s[5],buf_r[5],buf_e[5];
+    rvec extr_s[2],extr_r[2];
+    rvec dh;
+    real dist_d,c=0,det;
+    gmx_domdec_comm_t *comm;
+    gmx_bool bPBC,bUse;
+
+    comm = dd->comm;
+
+    for(d=1; d<dd->ndim; d++)
+    {
+        dim = dd->dim[d];
+        zp = (d == 1) ? &comm->zone_d1[0] : &comm->zone_d2[0][0];
+        zp->min0 = cell_ns_x0[dim];
+        zp->max1 = cell_ns_x1[dim];
+        zp->mch0 = cell_ns_x0[dim];
+        zp->mch1 = cell_ns_x1[dim];
+        zp->p1_0 = cell_ns_x0[dim];
+        zp->p1_1 = cell_ns_x1[dim];
+    }
+    
+    for(d=dd->ndim-2; d>=0; d--)
+    {
+        dim  = dd->dim[d];
+        bPBC = (dim < ddbox->npbcdim);
+
+        /* Use an rvec to store two reals */
+        extr_s[d][0] = comm->cell_f0[d+1];
+        extr_s[d][1] = comm->cell_f1[d+1];
+        extr_s[d][2] = 0;
+
+        pos = 0;
+        /* Store the extremes in the backward sending buffer,
+         * so the get updated separately from the forward communication.
+         */
+        for(d1=d; d1<dd->ndim-1; d1++)
+        {
+            /* We invert the order to be able to use the same loop for buf_e */
+            buf_s[pos].min0 = extr_s[d1][1];
+            buf_s[pos].max1 = extr_s[d1][0];
+            buf_s[pos].mch0 = 0;
+            buf_s[pos].mch1 = 0;
+            /* Store the cell corner of the dimension we communicate along */
+            buf_s[pos].p1_0 = comm->cell_x0[dim];
+            buf_s[pos].p1_1 = 0;
+            pos++;
+        }
+
+        buf_s[pos] = (dd->ndim == 2) ? comm->zone_d1[0] : comm->zone_d2[0][0];
+        pos++;
+
+        if (dd->ndim == 3 && d == 0)
+        {
+            buf_s[pos] = comm->zone_d2[0][1];
+            pos++;
+            buf_s[pos] = comm->zone_d1[0];
+            pos++;
+        }
+
+        /* We only need to communicate the extremes
+         * in the forward direction
+         */
+        npulse = comm->cd[d].np;
+        if (bPBC)
+        {
+            /* Take the minimum to avoid double communication */
+            npulse_min = min(npulse,dd->nc[dim]-1-npulse);
+        }
+        else
+        {
+            /* Without PBC we should really not communicate over
+             * the boundaries, but implementing that complicates
+             * the communication setup and therefore we simply
+             * do all communication, but ignore some data.
+             */
+            npulse_min = npulse;
+        }
+        for(p=0; p<npulse_min; p++)
+        {
+            /* Communicate the extremes forward */
+            bUse = (bPBC || dd->ci[dim] > 0);
+
+            dd_sendrecv_rvec(dd, d, dddirForward,
+                             extr_s+d, dd->ndim-d-1,
+                             extr_r+d, dd->ndim-d-1);
+
+            if (bUse)
+            {
+                for(d1=d; d1<dd->ndim-1; d1++)
+                {
+                    extr_s[d1][0] = max(extr_s[d1][0],extr_r[d1][0]);
+                    extr_s[d1][1] = min(extr_s[d1][1],extr_r[d1][1]);
+                }
+            }
+        }
+
+        buf_size = pos;
+        for(p=0; p<npulse; p++)
+        {
+            /* Communicate all the zone information backward */
+            bUse = (bPBC || dd->ci[dim] < dd->nc[dim] - 1);
+
+            dd_sendrecv_ddzone(dd, d, dddirBackward,
+                               buf_s, buf_size,
+                               buf_r, buf_size);
+
+            clear_rvec(dh);
+            if (p > 0)
+            {
+                for(d1=d+1; d1<dd->ndim; d1++)
+                {
+                    /* Determine the decrease of maximum required
+                     * communication height along d1 due to the distance along d,
+                     * this avoids a lot of useless atom communication.
+                     */
+                    dist_d = comm->cell_x1[dim] - buf_r[0].p1_0;
+
+                    if (ddbox->tric_dir[dim])
+                    {
+                        /* c is the off-diagonal coupling between the cell planes
+                         * along directions d and d1.
+                         */
+                        c = ddbox->v[dim][dd->dim[d1]][dim];
+                    }
+                    else
+                    {
+                        c = 0;
+                    }
+                    det = (1 + c*c)*comm->cutoff*comm->cutoff - dist_d*dist_d;
+                    if (det > 0)
+                    {
+                        dh[d1] = comm->cutoff - (c*dist_d + sqrt(det))/(1 + c*c);
+                    }
+                    else
+                    {
+                        /* A negative value signals out of range */
+                        dh[d1] = -1;
+                    }
+                }
+            }
+
+            /* Accumulate the extremes over all pulses */
+            for(i=0; i<buf_size; i++)
+            {
+                if (p == 0)
+                {
+                    buf_e[i] = buf_r[i];
+                }
+                else
+                {
+                    if (bUse)
+                    {
+                        buf_e[i].min0 = min(buf_e[i].min0,buf_r[i].min0);
+                        buf_e[i].max1 = max(buf_e[i].max1,buf_r[i].max1);
+                    }
+
+                    if (dd->ndim == 3 && d == 0 && i == buf_size - 1)
+                    {
+                        d1 = 1;
+                    }
+                    else
+                    {
+                        d1 = d + 1;
+                    }
+                    if (bUse && dh[d1] >= 0)
+                    {
+                        buf_e[i].mch0 = max(buf_e[i].mch0,buf_r[i].mch0-dh[d1]);
+                        buf_e[i].mch1 = max(buf_e[i].mch1,buf_r[i].mch1-dh[d1]);
+                    }
+                }
+                /* Copy the received buffer to the send buffer,
+                 * to pass the data through with the next pulse.
+                 */
+                buf_s[i] = buf_r[i];
+            }
+            if (((bPBC || dd->ci[dim]+npulse < dd->nc[dim]) && p == npulse-1) ||
+                (!bPBC && dd->ci[dim]+1+p == dd->nc[dim]-1))
+            {
+                /* Store the extremes */ 
+                pos = 0;
+
+                for(d1=d; d1<dd->ndim-1; d1++)
+                {
+                    extr_s[d1][1] = min(extr_s[d1][1],buf_e[pos].min0);
+                    extr_s[d1][0] = max(extr_s[d1][0],buf_e[pos].max1);
+                    pos++;
+                }
+
+                if (d == 1 || (d == 0 && dd->ndim == 3))
+                {
+                    for(i=d; i<2; i++)
+                    {
+                        comm->zone_d2[1-d][i] = buf_e[pos];
+                        pos++;
+                    }
+                }
+                if (d == 0)
+                {
+                    comm->zone_d1[1] = buf_e[pos];
+                    pos++;
+                }
+            }
+        }
+    }
+    
+    if (dd->ndim >= 2)
+    {
+        dim = dd->dim[1];
+        for(i=0; i<2; i++)
+        {
+            if (debug)
+            {
+                print_ddzone(debug,1,i,0,&comm->zone_d1[i]);
+            }
+            cell_ns_x0[dim] = min(cell_ns_x0[dim],comm->zone_d1[i].min0);
+            cell_ns_x1[dim] = max(cell_ns_x1[dim],comm->zone_d1[i].max1);
+        }
+    }
+    if (dd->ndim >= 3)
+    {
+        dim = dd->dim[2];
+        for(i=0; i<2; i++)
+        {
+            for(j=0; j<2; j++)
+            {
+                if (debug)
+                {
+                    print_ddzone(debug,2,i,j,&comm->zone_d2[i][j]);
+                }
+                cell_ns_x0[dim] = min(cell_ns_x0[dim],comm->zone_d2[i][j].min0);
+                cell_ns_x1[dim] = max(cell_ns_x1[dim],comm->zone_d2[i][j].max1);
+            }
+        }
+    }
+    for(d=1; d<dd->ndim; d++)
+    {
+        comm->cell_f_max0[d] = extr_s[d-1][0];
+        comm->cell_f_min1[d] = extr_s[d-1][1];
+        if (debug)
+        {
+            fprintf(debug,"Cell fraction d %d, max0 %f, min1 %f\n",
+                    d,comm->cell_f_max0[d],comm->cell_f_min1[d]);
+        }
+    }
+}
+
+static void dd_collect_cg(gmx_domdec_t *dd,
+                          t_state *state_local)
+{
+    gmx_domdec_master_t *ma=NULL;
+    int buf2[2],*ibuf,i,ncg_home=0,*cg=NULL,nat_home=0;
+    t_block *cgs_gl;
+
+    if (state_local->ddp_count == dd->comm->master_cg_ddp_count)
+    {
+        /* The master has the correct distribution */
+        return;
+    }
+    
+    if (state_local->ddp_count == dd->ddp_count)
+    {
+        ncg_home = dd->ncg_home;
+        cg       = dd->index_gl;
+        nat_home = dd->nat_home;
+    } 
+    else if (state_local->ddp_count_cg_gl == state_local->ddp_count)
+    {
+        cgs_gl = &dd->comm->cgs_gl;
+
+        ncg_home = state_local->ncg_gl;
+        cg       = state_local->cg_gl;
+        nat_home = 0;
+        for(i=0; i<ncg_home; i++)
+        {
+            nat_home += cgs_gl->index[cg[i]+1] - cgs_gl->index[cg[i]];
+        }
+    }
+    else
+    {
+        gmx_incons("Attempted to collect a vector for a state for which the charge group distribution is unknown");
+    }
+    
+    buf2[0] = dd->ncg_home;
+    buf2[1] = dd->nat_home;
+    if (DDMASTER(dd))
+    {
+        ma = dd->ma;
+        ibuf = ma->ibuf;
+    }
+    else
+    {
+        ibuf = NULL;
+    }
+    /* Collect the charge group and atom counts on the master */
+    dd_gather(dd,2*sizeof(int),buf2,ibuf);
+    
+    if (DDMASTER(dd))
+    {
+        ma->index[0] = 0;
+        for(i=0; i<dd->nnodes; i++)
+        {
+            ma->ncg[i] = ma->ibuf[2*i];
+            ma->nat[i] = ma->ibuf[2*i+1];
+            ma->index[i+1] = ma->index[i] + ma->ncg[i];
+            
+        }
+        /* Make byte counts and indices */
+        for(i=0; i<dd->nnodes; i++)
+        {
+            ma->ibuf[i] = ma->ncg[i]*sizeof(int);
+            ma->ibuf[dd->nnodes+i] = ma->index[i]*sizeof(int);
+        }
+        if (debug)
+        {
+            fprintf(debug,"Initial charge group distribution: ");
+            for(i=0; i<dd->nnodes; i++)
+                fprintf(debug," %d",ma->ncg[i]);
+            fprintf(debug,"\n");
+        }
+    }
+    
+    /* Collect the charge group indices on the master */
+    dd_gatherv(dd,
+               dd->ncg_home*sizeof(int),dd->index_gl,
+               DDMASTER(dd) ? ma->ibuf : NULL,
+               DDMASTER(dd) ? ma->ibuf+dd->nnodes : NULL,
+               DDMASTER(dd) ? ma->cg : NULL);
+    
+    dd->comm->master_cg_ddp_count = state_local->ddp_count;
+}
+
+static void dd_collect_vec_sendrecv(gmx_domdec_t *dd,
+                                    rvec *lv,rvec *v)
+{
+    gmx_domdec_master_t *ma;
+    int  n,i,c,a,nalloc=0;
+    rvec *buf=NULL;
+    t_block *cgs_gl;
+
+    ma = dd->ma;
+    
+    if (!DDMASTER(dd))
+    {
+#ifdef GMX_MPI
+        MPI_Send(lv,dd->nat_home*sizeof(rvec),MPI_BYTE,DDMASTERRANK(dd),
+                 dd->rank,dd->mpi_comm_all);
+#endif
+    } else {
+        /* Copy the master coordinates to the global array */
+        cgs_gl = &dd->comm->cgs_gl;
+
+        n = DDMASTERRANK(dd);
+        a = 0;
+        for(i=ma->index[n]; i<ma->index[n+1]; i++)
+        {
+            for(c=cgs_gl->index[ma->cg[i]]; c<cgs_gl->index[ma->cg[i]+1]; c++)
+            {
+                copy_rvec(lv[a++],v[c]);
+            }
+        }
+        
+        for(n=0; n<dd->nnodes; n++)
+        {
+            if (n != dd->rank)
+            {
+                if (ma->nat[n] > nalloc)
+                {
+                    nalloc = over_alloc_dd(ma->nat[n]);
+                    srenew(buf,nalloc);
+                }
+#ifdef GMX_MPI
+                MPI_Recv(buf,ma->nat[n]*sizeof(rvec),MPI_BYTE,DDRANK(dd,n),
+                         n,dd->mpi_comm_all,MPI_STATUS_IGNORE);
+#endif
+                a = 0;
+                for(i=ma->index[n]; i<ma->index[n+1]; i++)
+                {
+                    for(c=cgs_gl->index[ma->cg[i]]; c<cgs_gl->index[ma->cg[i]+1]; c++)
+                    {
+                        copy_rvec(buf[a++],v[c]);
+                    }
+                }
+            }
+        }
+        sfree(buf);
+    }
+}
+
+static void get_commbuffer_counts(gmx_domdec_t *dd,
+                                  int **counts,int **disps)
+{
+    gmx_domdec_master_t *ma;
+    int n;
+
+    ma = dd->ma;
+    
+    /* Make the rvec count and displacment arrays */
+    *counts  = ma->ibuf;
+    *disps   = ma->ibuf + dd->nnodes;
+    for(n=0; n<dd->nnodes; n++)
+    {
+        (*counts)[n] = ma->nat[n]*sizeof(rvec);
+        (*disps)[n]  = (n == 0 ? 0 : (*disps)[n-1] + (*counts)[n-1]);
+    }
+}
+
+static void dd_collect_vec_gatherv(gmx_domdec_t *dd,
+                                   rvec *lv,rvec *v)
+{
+    gmx_domdec_master_t *ma;
+    int  *rcounts=NULL,*disps=NULL;
+    int  n,i,c,a;
+    rvec *buf=NULL;
+    t_block *cgs_gl;
+    
+    ma = dd->ma;
+    
+    if (DDMASTER(dd))
+    {
+        get_commbuffer_counts(dd,&rcounts,&disps);
+
+        buf = ma->vbuf;
+    }
+    
+    dd_gatherv(dd,dd->nat_home*sizeof(rvec),lv,rcounts,disps,buf);
+
+    if (DDMASTER(dd))
+    {
+        cgs_gl = &dd->comm->cgs_gl;
+
+        a = 0;
+        for(n=0; n<dd->nnodes; n++)
+        {
+            for(i=ma->index[n]; i<ma->index[n+1]; i++)
+            {
+                for(c=cgs_gl->index[ma->cg[i]]; c<cgs_gl->index[ma->cg[i]+1]; c++)
+                {
+                    copy_rvec(buf[a++],v[c]);
+                }
+            }
+        }
+    }
+}
+
+void dd_collect_vec(gmx_domdec_t *dd,
+                    t_state *state_local,rvec *lv,rvec *v)
+{
+    gmx_domdec_master_t *ma;
+    int  n,i,c,a,nalloc=0;
+    rvec *buf=NULL;
+    
+    dd_collect_cg(dd,state_local);
+
+    if (dd->nnodes <= GMX_DD_NNODES_SENDRECV)
+    {
+        dd_collect_vec_sendrecv(dd,lv,v);
+    }
+    else
+    {
+        dd_collect_vec_gatherv(dd,lv,v);
+    }
+}
+
+
+void dd_collect_state(gmx_domdec_t *dd,
+                      t_state *state_local,t_state *state)
+{
+    int est,i,j,nh;
+
+    nh = state->nhchainlength;
+
+    if (DDMASTER(dd))
+    {
+        state->lambda = state_local->lambda;
+        state->veta = state_local->veta;
+        state->vol0 = state_local->vol0;
+        copy_mat(state_local->box,state->box);
+        copy_mat(state_local->boxv,state->boxv);
+        copy_mat(state_local->svir_prev,state->svir_prev);
+        copy_mat(state_local->fvir_prev,state->fvir_prev);
+        copy_mat(state_local->pres_prev,state->pres_prev);
+
+
+        for(i=0; i<state_local->ngtc; i++)
+        {
+            for(j=0; j<nh; j++) {
+                state->nosehoover_xi[i*nh+j]        = state_local->nosehoover_xi[i*nh+j];
+                state->nosehoover_vxi[i*nh+j]       = state_local->nosehoover_vxi[i*nh+j];
+            }
+            state->therm_integral[i] = state_local->therm_integral[i];            
+        }
+        for(i=0; i<state_local->nnhpres; i++) 
+        {
+            for(j=0; j<nh; j++) {
+                state->nhpres_xi[i*nh+j]        = state_local->nhpres_xi[i*nh+j];
+                state->nhpres_vxi[i*nh+j]       = state_local->nhpres_vxi[i*nh+j];
+            }
+        }
+    }
+    for(est=0; est<estNR; est++)
+    {
+        if (EST_DISTR(est) && state_local->flags & (1<<est))
+        {
+            switch (est) {
+            case estX:
+                dd_collect_vec(dd,state_local,state_local->x,state->x);
+                break;
+            case estV:
+                dd_collect_vec(dd,state_local,state_local->v,state->v);
+                break;
+            case estSDX:
+                dd_collect_vec(dd,state_local,state_local->sd_X,state->sd_X);
+                break;
+            case estCGP:
+                dd_collect_vec(dd,state_local,state_local->cg_p,state->cg_p);
+                break;
+            case estLD_RNG:
+                if (state->nrngi == 1)
+                {
+                    if (DDMASTER(dd))
+                    {
+                        for(i=0; i<state_local->nrng; i++)
+                        {
+                            state->ld_rng[i] = state_local->ld_rng[i];
+                        }
+                    }
+                }
+                else
+                {
+                    dd_gather(dd,state_local->nrng*sizeof(state->ld_rng[0]),
+                              state_local->ld_rng,state->ld_rng);
+                }
+                break;
+            case estLD_RNGI:
+                if (state->nrngi == 1)
+                {
+                   if (DDMASTER(dd))
+                    {
+                        state->ld_rngi[0] = state_local->ld_rngi[0];
+                    } 
+                }
+                else
+                {
+                    dd_gather(dd,sizeof(state->ld_rngi[0]),
+                              state_local->ld_rngi,state->ld_rngi);
+                }
+                break;
+            case estDISRE_INITF:
+            case estDISRE_RM3TAV:
+            case estORIRE_INITF:
+            case estORIRE_DTAV:
+                break;
+            default:
+                gmx_incons("Unknown state entry encountered in dd_collect_state");
+            }
+        }
+    }
+}
+
+static void dd_realloc_fr_cg(t_forcerec *fr,int nalloc)
+{
+    if (debug)
+    {
+        fprintf(debug,"Reallocating forcerec: currently %d, required %d, allocating %d\n",fr->cg_nalloc,nalloc,over_alloc_dd(nalloc));
+    }
+    fr->cg_nalloc = over_alloc_dd(nalloc);
+    srenew(fr->cg_cm,fr->cg_nalloc);
+    srenew(fr->cginfo,fr->cg_nalloc);
+}
+
+static void dd_realloc_state(t_state *state,rvec **f,int nalloc)
+{
+    int est;
+
+    if (debug)
+    {
+        fprintf(debug,"Reallocating state: currently %d, required %d, allocating %d\n",state->nalloc,nalloc,over_alloc_dd(nalloc));
+    }
+
+    state->nalloc = over_alloc_dd(nalloc);
+    
+    for(est=0; est<estNR; est++)
+    {
+        if (EST_DISTR(est) && state->flags & (1<<est))
+        {
+            switch(est) {
+            case estX:
+                srenew(state->x,state->nalloc);
+                break;
+            case estV:
+                srenew(state->v,state->nalloc);
+                break;
+            case estSDX:
+                srenew(state->sd_X,state->nalloc);
+                break;
+            case estCGP:
+                srenew(state->cg_p,state->nalloc);
+                break;
+            case estLD_RNG:
+            case estLD_RNGI:
+            case estDISRE_INITF:
+            case estDISRE_RM3TAV:
+            case estORIRE_INITF:
+            case estORIRE_DTAV:
+                /* No reallocation required */
+                break;
+            default:
+                gmx_incons("Unknown state entry encountered in dd_realloc_state");            
+            }
+        }
+    }
+    
+    if (f != NULL)
+    {
+        srenew(*f,state->nalloc);
+    }
+}
+
+static void dd_distribute_vec_sendrecv(gmx_domdec_t *dd,t_block *cgs,
+                                       rvec *v,rvec *lv)
+{
+    gmx_domdec_master_t *ma;
+    int  n,i,c,a,nalloc=0;
+    rvec *buf=NULL;
+    
+    if (DDMASTER(dd))
+    {
+        ma  = dd->ma;
+        
+        for(n=0; n<dd->nnodes; n++)
+        {
+            if (n != dd->rank)
+            {
+                if (ma->nat[n] > nalloc)
+                {
+                    nalloc = over_alloc_dd(ma->nat[n]);
+                    srenew(buf,nalloc);
+                }
+                /* Use lv as a temporary buffer */
+                a = 0;
+                for(i=ma->index[n]; i<ma->index[n+1]; i++)
+                {
+                    for(c=cgs->index[ma->cg[i]]; c<cgs->index[ma->cg[i]+1]; c++)
+                    {
+                        copy_rvec(v[c],buf[a++]);
+                    }
+                }
+                if (a != ma->nat[n])
+                {
+                    gmx_fatal(FARGS,"Internal error a (%d) != nat (%d)",
+                              a,ma->nat[n]);
+                }
+                
+#ifdef GMX_MPI
+                MPI_Send(buf,ma->nat[n]*sizeof(rvec),MPI_BYTE,
+                         DDRANK(dd,n),n,dd->mpi_comm_all);
+#endif
+            }
+        }
+        sfree(buf);
+        n = DDMASTERRANK(dd);
+        a = 0;
+        for(i=ma->index[n]; i<ma->index[n+1]; i++)
+        {
+            for(c=cgs->index[ma->cg[i]]; c<cgs->index[ma->cg[i]+1]; c++)
+            {
+                copy_rvec(v[c],lv[a++]);
+            }
+        }
+    }
+    else
+    {
+#ifdef GMX_MPI
+        MPI_Recv(lv,dd->nat_home*sizeof(rvec),MPI_BYTE,DDMASTERRANK(dd),
+                 MPI_ANY_TAG,dd->mpi_comm_all,MPI_STATUS_IGNORE);
+#endif
+    }
+}
+
+static void dd_distribute_vec_scatterv(gmx_domdec_t *dd,t_block *cgs,
+                                       rvec *v,rvec *lv)
+{
+    gmx_domdec_master_t *ma;
+    int  *scounts=NULL,*disps=NULL;
+    int  n,i,c,a,nalloc=0;
+    rvec *buf=NULL;
+    
+    if (DDMASTER(dd))
+    {
+        ma  = dd->ma;
+     
+        get_commbuffer_counts(dd,&scounts,&disps);
+
+        buf = ma->vbuf;
+        a = 0;
+        for(n=0; n<dd->nnodes; n++)
+        {
+            for(i=ma->index[n]; i<ma->index[n+1]; i++)
+            {
+                for(c=cgs->index[ma->cg[i]]; c<cgs->index[ma->cg[i]+1]; c++)
+                {
+                    copy_rvec(v[c],buf[a++]);
+                }
+            }
+        }
+    }
+
+    dd_scatterv(dd,scounts,disps,buf,dd->nat_home*sizeof(rvec),lv);
+}
+
+static void dd_distribute_vec(gmx_domdec_t *dd,t_block *cgs,rvec *v,rvec *lv)
+{
+    if (dd->nnodes <= GMX_DD_NNODES_SENDRECV)
+    {
+        dd_distribute_vec_sendrecv(dd,cgs,v,lv);
+    }
+    else
+    {
+        dd_distribute_vec_scatterv(dd,cgs,v,lv);
+    }
+}
+
+static void dd_distribute_state(gmx_domdec_t *dd,t_block *cgs,
+                                t_state *state,t_state *state_local,
+                                rvec **f)
+{
+    int  i,j,ngtch,ngtcp,nh;
+
+    nh = state->nhchainlength;
+
+    if (DDMASTER(dd))
+    {
+        state_local->lambda = state->lambda;
+        state_local->veta   = state->veta;
+        state_local->vol0   = state->vol0;
+        copy_mat(state->box,state_local->box);
+        copy_mat(state->box_rel,state_local->box_rel);
+        copy_mat(state->boxv,state_local->boxv);
+        copy_mat(state->svir_prev,state_local->svir_prev);
+        copy_mat(state->fvir_prev,state_local->fvir_prev);
+        for(i=0; i<state_local->ngtc; i++)
+        {
+            for(j=0; j<nh; j++) {
+                state_local->nosehoover_xi[i*nh+j]        = state->nosehoover_xi[i*nh+j];
+                state_local->nosehoover_vxi[i*nh+j]       = state->nosehoover_vxi[i*nh+j];
+            }
+            state_local->therm_integral[i] = state->therm_integral[i];
+        }
+        for(i=0; i<state_local->nnhpres; i++)
+        {
+            for(j=0; j<nh; j++) {
+                state_local->nhpres_xi[i*nh+j]        = state->nhpres_xi[i*nh+j];
+                state_local->nhpres_vxi[i*nh+j]       = state->nhpres_vxi[i*nh+j];
+            }
+        }
+    }
+    dd_bcast(dd,sizeof(real),&state_local->lambda);
+    dd_bcast(dd,sizeof(real),&state_local->veta);
+    dd_bcast(dd,sizeof(real),&state_local->vol0);
+    dd_bcast(dd,sizeof(state_local->box),state_local->box);
+    dd_bcast(dd,sizeof(state_local->box_rel),state_local->box_rel);
+    dd_bcast(dd,sizeof(state_local->boxv),state_local->boxv);
+    dd_bcast(dd,sizeof(state_local->svir_prev),state_local->svir_prev);
+    dd_bcast(dd,sizeof(state_local->fvir_prev),state_local->fvir_prev);
+    dd_bcast(dd,((state_local->ngtc*nh)*sizeof(double)),state_local->nosehoover_xi);
+    dd_bcast(dd,((state_local->ngtc*nh)*sizeof(double)),state_local->nosehoover_vxi);
+    dd_bcast(dd,state_local->ngtc*sizeof(double),state_local->therm_integral);
+    dd_bcast(dd,((state_local->nnhpres*nh)*sizeof(double)),state_local->nhpres_xi);
+    dd_bcast(dd,((state_local->nnhpres*nh)*sizeof(double)),state_local->nhpres_vxi);
+
+    if (dd->nat_home > state_local->nalloc)
+    {
+        dd_realloc_state(state_local,f,dd->nat_home);
+    }
+    for(i=0; i<estNR; i++)
+    {
+        if (EST_DISTR(i) && state_local->flags & (1<<i))
+        {
+            switch (i) {
+            case estX:
+                dd_distribute_vec(dd,cgs,state->x,state_local->x);
+                break;
+            case estV:
+                dd_distribute_vec(dd,cgs,state->v,state_local->v);
+                break;
+            case estSDX:
+                dd_distribute_vec(dd,cgs,state->sd_X,state_local->sd_X);
+                break;
+            case estCGP:
+                dd_distribute_vec(dd,cgs,state->cg_p,state_local->cg_p);
+                break;
+            case estLD_RNG:
+                if (state->nrngi == 1)
+                {
+                    dd_bcastc(dd,
+                              state_local->nrng*sizeof(state_local->ld_rng[0]),
+                              state->ld_rng,state_local->ld_rng);
+                }
+                else
+                {
+                    dd_scatter(dd,
+                               state_local->nrng*sizeof(state_local->ld_rng[0]),
+                               state->ld_rng,state_local->ld_rng);
+                }
+                break;
+            case estLD_RNGI:
+                if (state->nrngi == 1)
+                {
+                    dd_bcastc(dd,sizeof(state_local->ld_rngi[0]),
+                              state->ld_rngi,state_local->ld_rngi);
+                }
+                else
+                {
+                     dd_scatter(dd,sizeof(state_local->ld_rngi[0]),
+                               state->ld_rngi,state_local->ld_rngi);
+                }   
+                break;
+            case estDISRE_INITF:
+            case estDISRE_RM3TAV:
+            case estORIRE_INITF:
+            case estORIRE_DTAV:
+                /* Not implemented yet */
+                break;
+            default:
+                gmx_incons("Unknown state entry encountered in dd_distribute_state");
+            }
+        }
+    }
+}
+
+static char dim2char(int dim)
+{
+    char c='?';
+    
+    switch (dim)
+    {
+    case XX: c = 'X'; break;
+    case YY: c = 'Y'; break;
+    case ZZ: c = 'Z'; break;
+    default: gmx_fatal(FARGS,"Unknown dim %d",dim);
+    }
+    
+    return c;
+}
+
+static void write_dd_grid_pdb(const char *fn,gmx_large_int_t step,
+                              gmx_domdec_t *dd,matrix box,gmx_ddbox_t *ddbox)
+{
+    rvec grid_s[2],*grid_r=NULL,cx,r;
+    char fname[STRLEN],format[STRLEN],buf[22];
+    FILE *out;
+    int  a,i,d,z,y,x;
+    matrix tric;
+    real vol;
+
+    copy_rvec(dd->comm->cell_x0,grid_s[0]);
+    copy_rvec(dd->comm->cell_x1,grid_s[1]);
+    
+    if (DDMASTER(dd))
+    {
+        snew(grid_r,2*dd->nnodes);
+    }
+    
+    dd_gather(dd,2*sizeof(rvec),grid_s[0],DDMASTER(dd) ? grid_r[0] : NULL);
+    
+    if (DDMASTER(dd))
+    {
+        for(d=0; d<DIM; d++)
+        {
+            for(i=0; i<DIM; i++)
+            {
+                if (d == i)
+                {
+                    tric[d][i] = 1;
+                }
+                else
+                {
+                    if (dd->nc[d] > 1 && d < ddbox->npbcdim)
+                    {
+                        tric[d][i] = box[i][d]/box[i][i];
+                    }
+                    else
+                    {
+                        tric[d][i] = 0;
+                    }
+                }
+            }
+        }
+        sprintf(fname,"%s_%s.pdb",fn,gmx_step_str(step,buf));
+        sprintf(format,"%s%s\n",pdbformat,"%6.2f%6.2f");
+        out = gmx_fio_fopen(fname,"w");
+        gmx_write_pdb_box(out,dd->bScrewPBC ? epbcSCREW : epbcXYZ,box);
+        a = 1;
+        for(i=0; i<dd->nnodes; i++)
+        {
+            vol = dd->nnodes/(box[XX][XX]*box[YY][YY]*box[ZZ][ZZ]);
+            for(d=0; d<DIM; d++)
+            {
+                vol *= grid_r[i*2+1][d] - grid_r[i*2][d];
+            }
+            for(z=0; z<2; z++)
+            {
+                for(y=0; y<2; y++)
+                {
+                    for(x=0; x<2; x++)
+                    {
+                        cx[XX] = grid_r[i*2+x][XX];
+                        cx[YY] = grid_r[i*2+y][YY];
+                        cx[ZZ] = grid_r[i*2+z][ZZ];
+                        mvmul(tric,cx,r);
+                        fprintf(out,format,"ATOM",a++,"CA","GLY",' ',1+i,
+                                10*r[XX],10*r[YY],10*r[ZZ],1.0,vol);
+                    }
+                }
+            }
+            for(d=0; d<DIM; d++)
+            {
+                for(x=0; x<4; x++)
+                {
+                    switch(d)
+                    {
+                    case 0: y = 1 + i*8 + 2*x; break;
+                    case 1: y = 1 + i*8 + 2*x - (x % 2); break;
+                    case 2: y = 1 + i*8 + x; break;
+                    }
+                    fprintf(out,"%6s%5d%5d\n","CONECT",y,y+(1<<d));
+                }
+            }
+        }
+        gmx_fio_fclose(out);
+        sfree(grid_r);
+    }
+}
+
+void write_dd_pdb(const char *fn,gmx_large_int_t step,const char *title,
+                  gmx_mtop_t *mtop,t_commrec *cr,
+                  int natoms,rvec x[],matrix box)
+{
+    char fname[STRLEN],format[STRLEN],format4[STRLEN],buf[22];
+    FILE *out;
+    int  i,ii,resnr,c;
+    char *atomname,*resname;
+    real b;
+    gmx_domdec_t *dd;
+    
+    dd = cr->dd;
+    if (natoms == -1)
+    {
+        natoms = dd->comm->nat[ddnatVSITE];
+    }
+    
+    sprintf(fname,"%s_%s_n%d.pdb",fn,gmx_step_str(step,buf),cr->sim_nodeid);
+    
+    sprintf(format,"%s%s\n",pdbformat,"%6.2f%6.2f");
+    sprintf(format4,"%s%s\n",pdbformat4,"%6.2f%6.2f");
+    
+    out = gmx_fio_fopen(fname,"w");
+    
+    fprintf(out,"TITLE     %s\n",title);
+    gmx_write_pdb_box(out,dd->bScrewPBC ? epbcSCREW : epbcXYZ,box);
+    for(i=0; i<natoms; i++)
+    {
+        ii = dd->gatindex[i];
+        gmx_mtop_atominfo_global(mtop,ii,&atomname,&resnr,&resname);
+        if (i < dd->comm->nat[ddnatZONE])
+        {
+            c = 0;
+            while (i >= dd->cgindex[dd->comm->zones.cg_range[c+1]])
+            {
+                c++;
+            }
+            b = c;
+        }
+        else if (i < dd->comm->nat[ddnatVSITE])
+        {
+            b = dd->comm->zones.n;
+        }
+        else
+        {
+            b = dd->comm->zones.n + 1;
+        }
+        fprintf(out,strlen(atomname)<4 ? format : format4,
+                "ATOM",(ii+1)%100000,
+                atomname,resname,' ',resnr%10000,' ',
+                10*x[i][XX],10*x[i][YY],10*x[i][ZZ],1.0,b);
+    }
+    fprintf(out,"TER\n");
+    
+    gmx_fio_fclose(out);
+}
+
+real dd_cutoff_mbody(gmx_domdec_t *dd)
+{
+    gmx_domdec_comm_t *comm;
+    int  di;
+    real r;
+
+    comm = dd->comm;
+
+    r = -1;
+    if (comm->bInterCGBondeds)
+    {
+        if (comm->cutoff_mbody > 0)
+        {
+            r = comm->cutoff_mbody;
+        }
+        else
+        {
+            /* cutoff_mbody=0 means we do not have DLB */
+            r = comm->cellsize_min[dd->dim[0]];
+            for(di=1; di<dd->ndim; di++)
+            {
+                r = min(r,comm->cellsize_min[dd->dim[di]]);
+            }
+            if (comm->bBondComm)
+            {
+                r = max(r,comm->cutoff_mbody);
+            }
+            else
+            {
+                r = min(r,comm->cutoff);
+            }
+        }
+    }
+
+    return r;
+}
+
+real dd_cutoff_twobody(gmx_domdec_t *dd)
+{
+    real r_mb;
+
+    r_mb = dd_cutoff_mbody(dd);
+
+    return max(dd->comm->cutoff,r_mb);
+}
+
+
+static void dd_cart_coord2pmecoord(gmx_domdec_t *dd,ivec coord,ivec coord_pme)
+{
+    int nc,ntot;
+    
+    nc   = dd->nc[dd->comm->cartpmedim];
+    ntot = dd->comm->ntot[dd->comm->cartpmedim];
+    copy_ivec(coord,coord_pme);
+    coord_pme[dd->comm->cartpmedim] =
+        nc + (coord[dd->comm->cartpmedim]*(ntot - nc) + (ntot - nc)/2)/nc;
+}
+
+static int low_ddindex2pmeindex(int ndd,int npme,int ddindex)
+{
+    /* Here we assign a PME node to communicate with this DD node
+     * by assuming that the major index of both is x.
+     * We add cr->npmenodes/2 to obtain an even distribution.
+     */
+    return (ddindex*npme + npme/2)/ndd;
+}
+
+static int ddindex2pmeindex(const gmx_domdec_t *dd,int ddindex)
+{
+    return low_ddindex2pmeindex(dd->nnodes,dd->comm->npmenodes,ddindex);
+}
+
+static int cr_ddindex2pmeindex(const t_commrec *cr,int ddindex)
+{
+    return low_ddindex2pmeindex(cr->dd->nnodes,cr->npmenodes,ddindex);
+}
+
+static int *dd_pmenodes(t_commrec *cr)
+{
+    int *pmenodes;
+    int n,i,p0,p1;
+    
+    snew(pmenodes,cr->npmenodes);
+    n = 0;
+    for(i=0; i<cr->dd->nnodes; i++) {
+        p0 = cr_ddindex2pmeindex(cr,i);
+        p1 = cr_ddindex2pmeindex(cr,i+1);
+        if (i+1 == cr->dd->nnodes || p1 > p0) {
+            if (debug)
+                fprintf(debug,"pmenode[%d] = %d\n",n,i+1+n);
+            pmenodes[n] = i + 1 + n;
+            n++;
+        }
+    }
+
+    return pmenodes;
+}
+
+static int gmx_ddcoord2pmeindex(t_commrec *cr,int x,int y,int z)
+{
+    gmx_domdec_t *dd;
+    ivec coords,coords_pme,nc;
+    int  slab;
+    
+    dd = cr->dd;
+    /*
+      if (dd->comm->bCartesian) {
+      gmx_ddindex2xyz(dd->nc,ddindex,coords);
+      dd_coords2pmecoords(dd,coords,coords_pme);
+      copy_ivec(dd->ntot,nc);
+      nc[dd->cartpmedim]         -= dd->nc[dd->cartpmedim];
+      coords_pme[dd->cartpmedim] -= dd->nc[dd->cartpmedim];
+      
+      slab = (coords_pme[XX]*nc[YY] + coords_pme[YY])*nc[ZZ] + coords_pme[ZZ];
+      } else {
+      slab = (ddindex*cr->npmenodes + cr->npmenodes/2)/dd->nnodes;
+      }
+    */
+    coords[XX] = x;
+    coords[YY] = y;
+    coords[ZZ] = z;
+    slab = ddindex2pmeindex(dd,dd_index(dd->nc,coords));
+    
+    return slab;
+}
+
+static int ddcoord2simnodeid(t_commrec *cr,int x,int y,int z)
+{
+    gmx_domdec_comm_t *comm;
+    ivec coords;
+    int  ddindex,nodeid=-1;
+    
+    comm = cr->dd->comm;
+    
+    coords[XX] = x;
+    coords[YY] = y;
+    coords[ZZ] = z;
+    if (comm->bCartesianPP_PME)
+    {
+#ifdef GMX_MPI
+        MPI_Cart_rank(cr->mpi_comm_mysim,coords,&nodeid);
+#endif
+    }
+    else
+    {
+        ddindex = dd_index(cr->dd->nc,coords);
+        if (comm->bCartesianPP)
+        {
+            nodeid = comm->ddindex2simnodeid[ddindex];
+        }
+        else
+        {
+            if (comm->pmenodes)
+            {
+                nodeid = ddindex + gmx_ddcoord2pmeindex(cr,x,y,z);
+            }
+            else
+            {
+                nodeid = ddindex;
+            }
+        }
+    }
+  
+    return nodeid;
+}
+
+static int dd_simnode2pmenode(t_commrec *cr,int sim_nodeid)
+{
+    gmx_domdec_t *dd;
+    gmx_domdec_comm_t *comm;
+    ivec coord,coord_pme;
+    int  i;
+    int  pmenode=-1;
+    
+    dd = cr->dd;
+    comm = dd->comm;
+    
+    /* This assumes a uniform x domain decomposition grid cell size */
+    if (comm->bCartesianPP_PME)
+    {
+#ifdef GMX_MPI
+        MPI_Cart_coords(cr->mpi_comm_mysim,sim_nodeid,DIM,coord);
+        if (coord[comm->cartpmedim] < dd->nc[comm->cartpmedim])
+        {
+            /* This is a PP node */
+            dd_cart_coord2pmecoord(dd,coord,coord_pme);
+            MPI_Cart_rank(cr->mpi_comm_mysim,coord_pme,&pmenode);
+        }
+#endif
+    }
+    else if (comm->bCartesianPP)
+    {
+        if (sim_nodeid < dd->nnodes)
+        {
+            pmenode = dd->nnodes + ddindex2pmeindex(dd,sim_nodeid);
+        }
+    }
+    else
+    {
+        /* This assumes DD cells with identical x coordinates
+         * are numbered sequentially.
+         */
+        if (dd->comm->pmenodes == NULL)
+        {
+            if (sim_nodeid < dd->nnodes)
+            {
+                /* The DD index equals the nodeid */
+                pmenode = dd->nnodes + ddindex2pmeindex(dd,sim_nodeid);
+            }
+        }
+        else
+        {
+            i = 0;
+            while (sim_nodeid > dd->comm->pmenodes[i])
+            {
+                i++;
+            }
+            if (sim_nodeid < dd->comm->pmenodes[i])
+            {
+                pmenode = dd->comm->pmenodes[i];
+            }
+        }
+    }
+    
+    return pmenode;
+}
+
+gmx_bool gmx_pmeonlynode(t_commrec *cr,int sim_nodeid)
+{
+    gmx_bool bPMEOnlyNode;
+    
+    if (DOMAINDECOMP(cr))
+    {
+        bPMEOnlyNode = (dd_simnode2pmenode(cr,sim_nodeid) == -1);
+    }
+    else
+    {
+        bPMEOnlyNode = FALSE;
+    }
+    
+    return bPMEOnlyNode;
+}
+
+void get_pme_ddnodes(t_commrec *cr,int pmenodeid,
+                     int *nmy_ddnodes,int **my_ddnodes,int *node_peer)
+{
+    gmx_domdec_t *dd;
+    int x,y,z;
+    ivec coord,coord_pme;
+    
+    dd = cr->dd;
+    
+    snew(*my_ddnodes,(dd->nnodes+cr->npmenodes-1)/cr->npmenodes);
+    
+    *nmy_ddnodes = 0;
+    for(x=0; x<dd->nc[XX]; x++)
+    {
+        for(y=0; y<dd->nc[YY]; y++)
+        {
+            for(z=0; z<dd->nc[ZZ]; z++)
+            {
+                if (dd->comm->bCartesianPP_PME)
+                {
+                    coord[XX] = x;
+                    coord[YY] = y;
+                    coord[ZZ] = z;
+                    dd_cart_coord2pmecoord(dd,coord,coord_pme);
+                    if (dd->ci[XX] == coord_pme[XX] &&
+                        dd->ci[YY] == coord_pme[YY] &&
+                        dd->ci[ZZ] == coord_pme[ZZ])
+                        (*my_ddnodes)[(*nmy_ddnodes)++] = ddcoord2simnodeid(cr,x,y,z);
+                }
+                else
+                {
+                    /* The slab corresponds to the nodeid in the PME group */
+                    if (gmx_ddcoord2pmeindex(cr,x,y,z) == pmenodeid)
+                    {
+                        (*my_ddnodes)[(*nmy_ddnodes)++] = ddcoord2simnodeid(cr,x,y,z);
+                    }
+                }
+            }
+        }
+    }
+    
+    /* The last PP-only node is the peer node */
+    *node_peer = (*my_ddnodes)[*nmy_ddnodes-1];
+    
+    if (debug)
+    {
+        fprintf(debug,"Receive coordinates from PP nodes:");
+        for(x=0; x<*nmy_ddnodes; x++)
+        {
+            fprintf(debug," %d",(*my_ddnodes)[x]);
+        }
+        fprintf(debug,"\n");
+    }
+}
+
+static gmx_bool receive_vir_ener(t_commrec *cr)
+{
+    gmx_domdec_comm_t *comm;
+    int  pmenode,coords[DIM],rank;
+    gmx_bool bReceive;
+    
+    bReceive = TRUE;
+    if (cr->npmenodes < cr->dd->nnodes)
+    {
+        comm = cr->dd->comm;
+        if (comm->bCartesianPP_PME)
+        {
+            pmenode = dd_simnode2pmenode(cr,cr->sim_nodeid);
+#ifdef GMX_MPI
+            MPI_Cart_coords(cr->mpi_comm_mysim,cr->sim_nodeid,DIM,coords);
+            coords[comm->cartpmedim]++;
+            if (coords[comm->cartpmedim] < cr->dd->nc[comm->cartpmedim])
+            {
+                MPI_Cart_rank(cr->mpi_comm_mysim,coords,&rank);
+                if (dd_simnode2pmenode(cr,rank) == pmenode)
+                {
+                    /* This is not the last PP node for pmenode */
+                    bReceive = FALSE;
+                }
+            }
+#endif  
+        }
+        else
+        {
+            pmenode = dd_simnode2pmenode(cr,cr->sim_nodeid);
+            if (cr->sim_nodeid+1 < cr->nnodes &&
+                dd_simnode2pmenode(cr,cr->sim_nodeid+1) == pmenode)
+            {
+                /* This is not the last PP node for pmenode */
+                bReceive = FALSE;
+            }
+        }
+    }
+    
+    return bReceive;
+}
+
+static void set_zones_ncg_home(gmx_domdec_t *dd)
+{
+    gmx_domdec_zones_t *zones;
+    int i;
+
+    zones = &dd->comm->zones;
+
+    zones->cg_range[0] = 0;
+    for(i=1; i<zones->n+1; i++)
+    {
+        zones->cg_range[i] = dd->ncg_home;
+    }
+}
+
+static void rebuild_cgindex(gmx_domdec_t *dd,int *gcgs_index,t_state *state)
+{
+    int nat,i,*ind,*dd_cg_gl,*cgindex,cg_gl;
+    
+    ind = state->cg_gl;
+    dd_cg_gl = dd->index_gl;
+    cgindex  = dd->cgindex;
+    nat = 0;
+    cgindex[0] = nat;
+    for(i=0; i<state->ncg_gl; i++)
+    {
+        cgindex[i] = nat;
+        cg_gl = ind[i];
+        dd_cg_gl[i] = cg_gl;
+        nat += gcgs_index[cg_gl+1] - gcgs_index[cg_gl];
+    }
+    cgindex[i] = nat;
+    
+    dd->ncg_home = state->ncg_gl;
+    dd->nat_home = nat;
+
+    set_zones_ncg_home(dd);
+}
+
+static int ddcginfo(const cginfo_mb_t *cginfo_mb,int cg)
+{
+    while (cg >= cginfo_mb->cg_end)
+    {
+        cginfo_mb++;
+    }
+
+    return cginfo_mb->cginfo[(cg - cginfo_mb->cg_start) % cginfo_mb->cg_mod];
+}
+
+static void dd_set_cginfo(int *index_gl,int cg0,int cg1,
+                          t_forcerec *fr,char *bLocalCG)
+{
+    cginfo_mb_t *cginfo_mb;
+    int *cginfo;
+    int cg;
+
+    if (fr != NULL)
+    {
+        cginfo_mb = fr->cginfo_mb;
+        cginfo    = fr->cginfo;
+
+        for(cg=cg0; cg<cg1; cg++)
+        {
+            cginfo[cg] = ddcginfo(cginfo_mb,index_gl[cg]);
+        }
+    }
+
+    if (bLocalCG != NULL)
+    {
+        for(cg=cg0; cg<cg1; cg++)
+        {
+            bLocalCG[index_gl[cg]] = TRUE;
+        }
+    }
+}
+
+static void make_dd_indices(gmx_domdec_t *dd,int *gcgs_index,int cg_start)
+{
+    int nzone,zone,zone1,cg0,cg,cg_gl,a,a_gl;
+    int *zone2cg,*zone_ncg1,*index_gl,*gatindex;
+    gmx_ga2la_t *ga2la;
+    char *bLocalCG;
+
+    bLocalCG = dd->comm->bLocalCG;
+
+    if (dd->nat_tot > dd->gatindex_nalloc)
+    {
+        dd->gatindex_nalloc = over_alloc_dd(dd->nat_tot);
+        srenew(dd->gatindex,dd->gatindex_nalloc);
+    }
+
+    nzone      = dd->comm->zones.n;
+    zone2cg    = dd->comm->zones.cg_range;
+    zone_ncg1  = dd->comm->zone_ncg1;
+    index_gl   = dd->index_gl;
+    gatindex   = dd->gatindex;
+
+    if (zone2cg[1] != dd->ncg_home)
+    {
+        gmx_incons("dd->ncg_zone is not up to date");
+    }
+    
+    /* Make the local to global and global to local atom index */
+    a = dd->cgindex[cg_start];
+    for(zone=0; zone<nzone; zone++)
+    {
+        if (zone == 0)
+        {
+            cg0 = cg_start;
+        }
+        else
+        {
+            cg0 = zone2cg[zone];
+        }
+        for(cg=cg0; cg<zone2cg[zone+1]; cg++)
+        {
+            zone1 = zone;
+            if (cg - cg0 >= zone_ncg1[zone])
+            {
+                /* Signal that this cg is from more than one zone away */
+                zone1 += nzone;
+            }
+            cg_gl = index_gl[cg];
+            for(a_gl=gcgs_index[cg_gl]; a_gl<gcgs_index[cg_gl+1]; a_gl++)
+            {
+                gatindex[a] = a_gl;
+                ga2la_set(dd->ga2la,a_gl,a,zone1);
+                a++;
+            }
+        }
+    }
+}
+
+static int check_bLocalCG(gmx_domdec_t *dd,int ncg_sys,const char *bLocalCG,
+                          const char *where)
+{
+    int ncg,i,ngl,nerr;
+
+    nerr = 0;
+    if (bLocalCG == NULL)
+    {
+        return nerr;
+    }
+    for(i=0; i<dd->ncg_tot; i++)
+    {
+        if (!bLocalCG[dd->index_gl[i]])
+        {
+            fprintf(stderr,
+                    "DD node %d, %s: cg %d, global cg %d is not marked in bLocalCG (ncg_home %d)\n",dd->rank,where,i+1,dd->index_gl[i]+1,dd->ncg_home);
+            nerr++;
+        }
+    }
+    ngl = 0;
+    for(i=0; i<ncg_sys; i++)
+    {
+        if (bLocalCG[i])
+        {
+            ngl++;
+        }
+    }
+    if (ngl != dd->ncg_tot)
+    {
+        fprintf(stderr,"DD node %d, %s: In bLocalCG %d cgs are marked as local, whereas there are %d\n",dd->rank,where,ngl,dd->ncg_tot);
+        nerr++;
+    }
+
+    return nerr;
+}
+
+static void check_index_consistency(gmx_domdec_t *dd,
+                                    int natoms_sys,int ncg_sys,
+                                    const char *where)
+{
+    int  nerr,ngl,i,a,cell;
+    int  *have;
+
+    nerr = 0;
+
+    if (dd->comm->DD_debug > 1)
+    {
+        snew(have,natoms_sys);
+        for(a=0; a<dd->nat_tot; a++)
+        {
+            if (have[dd->gatindex[a]] > 0)
+            {
+                fprintf(stderr,"DD node %d: global atom %d occurs twice: index %d and %d\n",dd->rank,dd->gatindex[a]+1,have[dd->gatindex[a]],a+1);
+            }
+            else
+            {
+                have[dd->gatindex[a]] = a + 1;
+            }
+        }
+        sfree(have);
+    }
+
+    snew(have,dd->nat_tot);
+
+    ngl  = 0;
+    for(i=0; i<natoms_sys; i++)
+    {
+        if (ga2la_get(dd->ga2la,i,&a,&cell))
+        {
+            if (a >= dd->nat_tot)
+            {
+                fprintf(stderr,"DD node %d: global atom %d marked as local atom %d, which is larger than nat_tot (%d)\n",dd->rank,i+1,a+1,dd->nat_tot);
+                nerr++;
+            }
+            else
+            {
+                have[a] = 1;
+                if (dd->gatindex[a] != i)
+                {
+                    fprintf(stderr,"DD node %d: global atom %d marked as local atom %d, which has global atom index %d\n",dd->rank,i+1,a+1,dd->gatindex[a]+1);
+                    nerr++;
+                }
+            }
+            ngl++;
+        }
+    }
+    if (ngl != dd->nat_tot)
+    {
+        fprintf(stderr,
+                "DD node %d, %s: %d global atom indices, %d local atoms\n",
+                dd->rank,where,ngl,dd->nat_tot);
+    }
+    for(a=0; a<dd->nat_tot; a++)
+    {
+        if (have[a] == 0)
+        {
+            fprintf(stderr,
+                    "DD node %d, %s: local atom %d, global %d has no global index\n",
+                    dd->rank,where,a+1,dd->gatindex[a]+1);
+        }
+    }
+    sfree(have);
+
+    nerr += check_bLocalCG(dd,ncg_sys,dd->comm->bLocalCG,where);
+
+    if (nerr > 0) {
+        gmx_fatal(FARGS,"DD node %d, %s: %d atom/cg index inconsistencies",
+                  dd->rank,where,nerr);
+    }
+}
+
+static void clear_dd_indices(gmx_domdec_t *dd,int cg_start,int a_start)
+{
+    int  i;
+    char *bLocalCG;
+
+    if (a_start == 0)
+    {
+        /* Clear the whole list without searching */
+        ga2la_clear(dd->ga2la);
+    }
+    else
+    {
+        for(i=a_start; i<dd->nat_tot; i++)
+        {
+            ga2la_del(dd->ga2la,dd->gatindex[i]);
+        }
+    }
+
+    bLocalCG = dd->comm->bLocalCG;
+    if (bLocalCG)
+    {
+        for(i=cg_start; i<dd->ncg_tot; i++)
+        {
+            bLocalCG[dd->index_gl[i]] = FALSE;
+        }
+    }
+
+    dd_clear_local_vsite_indices(dd);
+    
+    if (dd->constraints)
+    {
+        dd_clear_local_constraint_indices(dd);
+    }
+}
+
+static real grid_jump_limit(gmx_domdec_comm_t *comm,int dim_ind)
+{
+    real grid_jump_limit;
+
+    /* The distance between the boundaries of cells at distance
+     * x+-1,y+-1 or y+-1,z+-1 is limited by the cut-off restrictions
+     * and by the fact that cells should not be shifted by more than
+     * half their size, such that cg's only shift by one cell
+     * at redecomposition.
+     */
+    grid_jump_limit = comm->cellsize_limit;
+    if (!comm->bVacDLBNoLimit)
+    {
+        grid_jump_limit = max(grid_jump_limit,
+                              comm->cutoff/comm->cd[dim_ind].np);
+    }
+
+    return grid_jump_limit;
+}
+
+static void check_grid_jump(gmx_large_int_t step,gmx_domdec_t *dd,gmx_ddbox_t *ddbox)
+{
+    gmx_domdec_comm_t *comm;
+    int  d,dim;
+    real limit,bfac;
+    
+    comm = dd->comm;
+    
+    for(d=1; d<dd->ndim; d++)
+    {
+        dim = dd->dim[d];
+        limit = grid_jump_limit(comm,d);
+        bfac = ddbox->box_size[dim];
+        if (ddbox->tric_dir[dim])
+        {
+            bfac *= ddbox->skew_fac[dim];
+        }
+        if ((comm->cell_f1[d] - comm->cell_f_max0[d])*bfac <  limit ||
+            (comm->cell_f0[d] - comm->cell_f_min1[d])*bfac > -limit)
+        {
+            char buf[22];
+            gmx_fatal(FARGS,"Step %s: The domain decomposition grid has shifted too much in the %c-direction around cell %d %d %d\n",
+                      gmx_step_str(step,buf),
+                      dim2char(dim),dd->ci[XX],dd->ci[YY],dd->ci[ZZ]);
+        }
+    }
+}
+
+static int dd_load_count(gmx_domdec_comm_t *comm)
+{
+    return (comm->eFlop ? comm->flop_n : comm->cycl_n[ddCyclF]);
+}
+
+static float dd_force_load(gmx_domdec_comm_t *comm)
+{
+    float load;
+    
+    if (comm->eFlop)
+    {
+        load = comm->flop;
+        if (comm->eFlop > 1)
+        {
+            load *= 1.0 + (comm->eFlop - 1)*(0.1*rand()/RAND_MAX - 0.05);
+        }
+    } 
+    else
+    {
+        load = comm->cycl[ddCyclF];
+        if (comm->cycl_n[ddCyclF] > 1)
+        {
+            /* Subtract the maximum of the last n cycle counts
+             * to get rid of possible high counts due to other soures,
+             * for instance system activity, that would otherwise
+             * affect the dynamic load balancing.
+             */
+            load -= comm->cycl_max[ddCyclF];
+        }
+    }
+    
+    return load;
+}
+
+static void set_slb_pme_dim_f(gmx_domdec_t *dd,int dim,real **dim_f)
+{
+    gmx_domdec_comm_t *comm;
+    int i;
+    
+    comm = dd->comm;
+    
+    snew(*dim_f,dd->nc[dim]+1);
+    (*dim_f)[0] = 0;
+    for(i=1; i<dd->nc[dim]; i++)
+    {
+        if (comm->slb_frac[dim])
+        {
+            (*dim_f)[i] = (*dim_f)[i-1] + comm->slb_frac[dim][i-1];
+        }
+        else
+        {
+            (*dim_f)[i] = (real)i/(real)dd->nc[dim];
+        }
+    }
+    (*dim_f)[dd->nc[dim]] = 1;
+}
+
+static void init_ddpme(gmx_domdec_t *dd,gmx_ddpme_t *ddpme,int dimind)
+{
+    int         pmeindex,slab,nso,i;
+    ivec xyz;
+    
+    if (dimind == 0 && dd->dim[0] == YY && dd->comm->npmenodes_x == 1)
+    {
+        ddpme->dim = YY;
+    }
+    else
+    {
+        ddpme->dim = dimind;
+    }
+    ddpme->dim_match = (ddpme->dim == dd->dim[dimind]);
+    
+    ddpme->nslab = (ddpme->dim == 0 ?
+                    dd->comm->npmenodes_x :
+                    dd->comm->npmenodes_y);
+
+    if (ddpme->nslab <= 1)
+    {
+        return;
+    }
+
+    nso = dd->comm->npmenodes/ddpme->nslab;
+    /* Determine for each PME slab the PP location range for dimension dim */
+    snew(ddpme->pp_min,ddpme->nslab);
+    snew(ddpme->pp_max,ddpme->nslab);
+    for(slab=0; slab<ddpme->nslab; slab++) {
+        ddpme->pp_min[slab] = dd->nc[dd->dim[dimind]] - 1;
+        ddpme->pp_max[slab] = 0;
+    }
+    for(i=0; i<dd->nnodes; i++) {
+        ddindex2xyz(dd->nc,i,xyz);
+        /* For y only use our y/z slab.
+         * This assumes that the PME x grid size matches the DD grid size.
+         */
+        if (dimind == 0 || xyz[XX] == dd->ci[XX]) {
+            pmeindex = ddindex2pmeindex(dd,i);
+            if (dimind == 0) {
+                slab = pmeindex/nso;
+            } else {
+                slab = pmeindex % ddpme->nslab;
+            }
+            ddpme->pp_min[slab] = min(ddpme->pp_min[slab],xyz[dimind]);
+            ddpme->pp_max[slab] = max(ddpme->pp_max[slab],xyz[dimind]);
+        }
+    }
+
+    set_slb_pme_dim_f(dd,ddpme->dim,&ddpme->slb_dim_f);
+}
+
+int dd_pme_maxshift_x(gmx_domdec_t *dd)
+{
+    if (dd->comm->ddpme[0].dim == XX)
+    {
+        return dd->comm->ddpme[0].maxshift;
+    }
+    else
+    {
+        return 0;
+    }
+}
+
+int dd_pme_maxshift_y(gmx_domdec_t *dd)
+{
+    if (dd->comm->ddpme[0].dim == YY)
+    {
+        return dd->comm->ddpme[0].maxshift;
+    }
+    else if (dd->comm->npmedecompdim >= 2 && dd->comm->ddpme[1].dim == YY)
+    {
+        return dd->comm->ddpme[1].maxshift;
+    }
+    else
+    {
+        return 0;
+    }
+}
+
+static void set_pme_maxshift(gmx_domdec_t *dd,gmx_ddpme_t *ddpme,
+                             gmx_bool bUniform,gmx_ddbox_t *ddbox,real *cell_f)
+{
+    gmx_domdec_comm_t *comm;
+    int  nc,ns,s;
+    int  *xmin,*xmax;
+    real range,pme_boundary;
+    int  sh;
+    
+    comm = dd->comm;
+    nc  = dd->nc[ddpme->dim];
+    ns  = ddpme->nslab;
+    
+    if (!ddpme->dim_match)
+    {
+        /* PP decomposition is not along dim: the worst situation */
+        sh = ns/2;
+    }
+    else if (ns <= 3 || (bUniform && ns == nc))
+    {
+        /* The optimal situation */
+        sh = 1;
+    }
+    else
+    {
+        /* We need to check for all pme nodes which nodes they
+         * could possibly need to communicate with.
+         */
+        xmin = ddpme->pp_min;
+        xmax = ddpme->pp_max;
+        /* Allow for atoms to be maximally 2/3 times the cut-off
+         * out of their DD cell. This is a reasonable balance between
+         * between performance and support for most charge-group/cut-off
+         * combinations.
+         */
+        range  = 2.0/3.0*comm->cutoff/ddbox->box_size[ddpme->dim];
+        /* Avoid extra communication when we are exactly at a boundary */
+        range *= 0.999;
+        
+        sh = 1;
+        for(s=0; s<ns; s++)
+        {
+            /* PME slab s spreads atoms between box frac. s/ns and (s+1)/ns */
+            pme_boundary = (real)s/ns;
+            while (sh+1 < ns &&
+                   ((s-(sh+1) >= 0 &&
+                     cell_f[xmax[s-(sh+1)   ]+1]     + range > pme_boundary) ||
+                    (s-(sh+1) <  0 &&
+                     cell_f[xmax[s-(sh+1)+ns]+1] - 1 + range > pme_boundary)))
+            {
+                sh++;
+            }
+            pme_boundary = (real)(s+1)/ns;
+            while (sh+1 < ns &&
+                   ((s+(sh+1) <  ns &&
+                     cell_f[xmin[s+(sh+1)   ]  ]     - range < pme_boundary) ||
+                    (s+(sh+1) >= ns &&
+                     cell_f[xmin[s+(sh+1)-ns]  ] + 1 - range < pme_boundary)))
+            {
+                sh++;
+            }
+        }
+    }
+    
+    ddpme->maxshift = sh;
+    
+    if (debug)
+    {
+        fprintf(debug,"PME slab communication range for dim %d is %d\n",
+                ddpme->dim,ddpme->maxshift);
+    }
+}
+
+static void check_box_size(gmx_domdec_t *dd,gmx_ddbox_t *ddbox)
+{
+    int d,dim;
+    
+    for(d=0; d<dd->ndim; d++)
+    {
+        dim = dd->dim[d];
+        if (dim < ddbox->nboundeddim &&
+            ddbox->box_size[dim]*ddbox->skew_fac[dim] <
+            dd->nc[dim]*dd->comm->cellsize_limit*DD_CELL_MARGIN)
+        {
+            gmx_fatal(FARGS,"The %c-size of the box (%f) times the triclinic skew factor (%f) is smaller than the number of DD cells (%d) times the smallest allowed cell size (%f)\n",
+                      dim2char(dim),ddbox->box_size[dim],ddbox->skew_fac[dim],
+                      dd->nc[dim],dd->comm->cellsize_limit);
+        }
+    }
+}
+
+static void set_dd_cell_sizes_slb(gmx_domdec_t *dd,gmx_ddbox_t *ddbox,
+                                  gmx_bool bMaster,ivec npulse)
+{
+    gmx_domdec_comm_t *comm;
+    int  d,j;
+    rvec cellsize_min;
+    real *cell_x,cell_dx,cellsize;
+    
+    comm = dd->comm;
+    
+    for(d=0; d<DIM; d++)
+    {
+        cellsize_min[d] = ddbox->box_size[d]*ddbox->skew_fac[d];
+        npulse[d] = 1;
+        if (dd->nc[d] == 1 || comm->slb_frac[d] == NULL)
+        {
+            /* Uniform grid */
+            cell_dx = ddbox->box_size[d]/dd->nc[d];
+            if (bMaster)
+            {
+                for(j=0; j<dd->nc[d]+1; j++)
+                {
+                    dd->ma->cell_x[d][j] = ddbox->box0[d] + j*cell_dx;
+                }
+            }
+            else
+            {
+                comm->cell_x0[d] = ddbox->box0[d] + (dd->ci[d]  )*cell_dx;
+                comm->cell_x1[d] = ddbox->box0[d] + (dd->ci[d]+1)*cell_dx;
+            }
+            cellsize = cell_dx*ddbox->skew_fac[d];
+            while (cellsize*npulse[d] < comm->cutoff && npulse[d] < dd->nc[d]-1)
+            {
+                npulse[d]++;
+            }
+            cellsize_min[d] = cellsize;
+        }
+        else
+        {
+            /* Statically load balanced grid */
+            /* Also when we are not doing a master distribution we determine
+             * all cell borders in a loop to obtain identical values
+             * to the master distribution case and to determine npulse.
+             */
+            if (bMaster)
+            {
+                cell_x = dd->ma->cell_x[d];
+            }
+            else
+            {
+                snew(cell_x,dd->nc[d]+1);
+            }
+            cell_x[0] = ddbox->box0[d];
+            for(j=0; j<dd->nc[d]; j++)
+            {
+                cell_dx = ddbox->box_size[d]*comm->slb_frac[d][j];
+                cell_x[j+1] = cell_x[j] + cell_dx;
+                cellsize = cell_dx*ddbox->skew_fac[d];
+                while (cellsize*npulse[d] < comm->cutoff &&
+                       npulse[d] < dd->nc[d]-1)
+                {
+                    npulse[d]++;
+                }
+                cellsize_min[d] = min(cellsize_min[d],cellsize);
+            }
+            if (!bMaster)
+            {
+                comm->cell_x0[d] = cell_x[dd->ci[d]];
+                comm->cell_x1[d] = cell_x[dd->ci[d]+1];
+                sfree(cell_x);
+            }
+        }
+        /* The following limitation is to avoid that a cell would receive
+         * some of its own home charge groups back over the periodic boundary.
+         * Double charge groups cause trouble with the global indices.
+         */
+        if (d < ddbox->npbcdim &&
+            dd->nc[d] > 1 && npulse[d] >= dd->nc[d])
+        {
+            gmx_fatal_collective(FARGS,NULL,dd,
+                                 "The box size in direction %c (%f) times the triclinic skew factor (%f) is too small for a cut-off of %f with %d domain decomposition cells, use 1 or more than %d %s or increase the box size in this direction",
+                                 dim2char(d),ddbox->box_size[d],ddbox->skew_fac[d],
+                                 comm->cutoff,
+                                 dd->nc[d],dd->nc[d],
+                                 dd->nnodes > dd->nc[d] ? "cells" : "processors");
+        }
+    }
+    
+    if (!comm->bDynLoadBal)
+    {
+        copy_rvec(cellsize_min,comm->cellsize_min);
+    }
+   
+    for(d=0; d<comm->npmedecompdim; d++)
+    {
+        set_pme_maxshift(dd,&comm->ddpme[d],
+                         comm->slb_frac[dd->dim[d]]==NULL,ddbox,
+                         comm->ddpme[d].slb_dim_f);
+    }
+}
+
+
+static void dd_cell_sizes_dlb_root_enforce_limits(gmx_domdec_t *dd,
+                                       int d,int dim,gmx_domdec_root_t *root,
+                                       gmx_ddbox_t *ddbox,
+                                       gmx_bool bUniform,gmx_large_int_t step, real cellsize_limit_f, int range[])
+{
+    gmx_domdec_comm_t *comm;
+    int  ncd,i,j,nmin,nmin_old;
+    gmx_bool bLimLo,bLimHi;
+    real *cell_size;
+    real fac,halfway,cellsize_limit_f_i,region_size;
+    gmx_bool bPBC,bLastHi=FALSE;
+    int nrange[]={range[0],range[1]};
+
+    region_size= root->cell_f[range[1]]-root->cell_f[range[0]];  
+
+    comm = dd->comm;
+
+    ncd = dd->nc[dim];
+
+    bPBC = (dim < ddbox->npbcdim);
+
+    cell_size = root->buf_ncd;
+
+    if (debug) 
+    {
+        fprintf(debug,"enforce_limits: %d %d\n",range[0],range[1]);
+    }
+
+    /* First we need to check if the scaling does not make cells
+     * smaller than the smallest allowed size.
+     * We need to do this iteratively, since if a cell is too small,
+     * it needs to be enlarged, which makes all the other cells smaller,
+     * which could in turn make another cell smaller than allowed.
+     */
+    for(i=range[0]; i<range[1]; i++)
+    {
+        root->bCellMin[i] = FALSE;
+    }
+    nmin = 0;
+    do
+    {
+        nmin_old = nmin;
+        /* We need the total for normalization */
+        fac = 0;
+        for(i=range[0]; i<range[1]; i++)
+        {
+            if (root->bCellMin[i] == FALSE)
+            {
+                fac += cell_size[i];
+            }
+        }
+        fac = ( region_size - nmin*cellsize_limit_f)/fac; /* substracting cells already set to cellsize_limit_f */
+        /* Determine the cell boundaries */
+        for(i=range[0]; i<range[1]; i++)
+        {
+            if (root->bCellMin[i] == FALSE)
+            {
+                cell_size[i] *= fac;
+                if (!bPBC && (i == 0 || i == dd->nc[dim] -1))
+                {
+                    cellsize_limit_f_i = 0;
+                }
+                else
+                {
+                    cellsize_limit_f_i = cellsize_limit_f;
+                }
+                if (cell_size[i] < cellsize_limit_f_i)
+                {
+                    root->bCellMin[i] = TRUE;
+                    cell_size[i] = cellsize_limit_f_i;
+                    nmin++;
+                }
+            }
+            root->cell_f[i+1] = root->cell_f[i] + cell_size[i];
+        }
+    }
+    while (nmin > nmin_old);
+    
+    i=range[1]-1;
+    cell_size[i] = root->cell_f[i+1] - root->cell_f[i];
+    /* For this check we should not use DD_CELL_MARGIN,
+     * but a slightly smaller factor,
+     * since rounding could get use below the limit.
+     */
+    if (bPBC && cell_size[i] < cellsize_limit_f*DD_CELL_MARGIN2/DD_CELL_MARGIN)
+    {
+        char buf[22];
+        gmx_fatal(FARGS,"Step %s: the dynamic load balancing could not balance dimension %c: box size %f, triclinic skew factor %f, #cells %d, minimum cell size %f\n",
+                  gmx_step_str(step,buf),
+                  dim2char(dim),ddbox->box_size[dim],ddbox->skew_fac[dim],
+                  ncd,comm->cellsize_min[dim]);
+    }
+    
+    root->bLimited = (nmin > 0) || (range[0]>0) || (range[1]<ncd);
+    
+    if (!bUniform)
+    {
+        /* Check if the boundary did not displace more than halfway
+         * each of the cells it bounds, as this could cause problems,
+         * especially when the differences between cell sizes are large.
+         * If changes are applied, they will not make cells smaller
+         * than the cut-off, as we check all the boundaries which
+         * might be affected by a change and if the old state was ok,
+         * the cells will at most be shrunk back to their old size.
+         */
+        for(i=range[0]+1; i<range[1]; i++)
+        {
+            halfway = 0.5*(root->old_cell_f[i] + root->old_cell_f[i-1]);
+            if (root->cell_f[i] < halfway)
+            {
+                root->cell_f[i] = halfway;
+                /* Check if the change also causes shifts of the next boundaries */
+                for(j=i+1; j<range[1]; j++)
+                {
+                    if (root->cell_f[j] < root->cell_f[j-1] + cellsize_limit_f)
+                        root->cell_f[j] =  root->cell_f[j-1] + cellsize_limit_f;
+                }
+            }
+            halfway = 0.5*(root->old_cell_f[i] + root->old_cell_f[i+1]);
+            if (root->cell_f[i] > halfway)
+            {
+                root->cell_f[i] = halfway;
+                /* Check if the change also causes shifts of the next boundaries */
+                for(j=i-1; j>=range[0]+1; j--)
+                {
+                    if (root->cell_f[j] > root->cell_f[j+1] - cellsize_limit_f)
+                        root->cell_f[j] = root->cell_f[j+1] - cellsize_limit_f;
+                }
+            }
+        }
+    }
+    
+    /* nrange is defined as [lower, upper) range for new call to enforce_limits */
+    /* find highest violation of LimLo (a) and the following violation of LimHi (thus the lowest following) (b)
+     * then call enforce_limits for (oldb,a), (a,b). In the next step: (b,nexta). oldb and nexta can be the boundaries.
+     * for a and b nrange is used */
+    if (d > 0)
+    {
+        /* Take care of the staggering of the cell boundaries */
+        if (bUniform)
+        {
+            for(i=range[0]; i<range[1]; i++)
+            {
+                root->cell_f_max0[i] = root->cell_f[i];
+                root->cell_f_min1[i] = root->cell_f[i+1];
+            }
+        }
+        else
+        {
+            for(i=range[0]+1; i<range[1]; i++)
+            {
+                bLimLo = (root->cell_f[i] < root->bound_min[i]);
+                bLimHi = (root->cell_f[i] > root->bound_max[i]);
+                if (bLimLo && bLimHi)
+                {
+                    /* Both limits violated, try the best we can */
+                    /* For this case we split the original range (range) in two parts and care about the other limitiations in the next iteration. */
+                    root->cell_f[i] = 0.5*(root->bound_min[i] + root->bound_max[i]);
+                    nrange[0]=range[0];
+                    nrange[1]=i;
+                    dd_cell_sizes_dlb_root_enforce_limits(dd, d, dim, root, ddbox, bUniform, step, cellsize_limit_f, nrange);
+
+                    nrange[0]=i;
+                    nrange[1]=range[1];
+                    dd_cell_sizes_dlb_root_enforce_limits(dd, d, dim, root, ddbox, bUniform, step, cellsize_limit_f, nrange);
+
+                    return;
+                }
+                else if (bLimLo)
+                {
+                    /* root->cell_f[i] = root->bound_min[i]; */
+                    nrange[1]=i;  /* only store violation location. There could be a LimLo violation following with an higher index */
+                    bLastHi=FALSE;
+                }
+                else if (bLimHi && !bLastHi)
+                {
+                    bLastHi=TRUE;
+                    if (nrange[1] < range[1])   /* found a LimLo before */
+                    {
+                        root->cell_f[nrange[1]] = root->bound_min[nrange[1]];
+                        dd_cell_sizes_dlb_root_enforce_limits(dd, d, dim, root, ddbox, bUniform, step, cellsize_limit_f, nrange);
+                        nrange[0]=nrange[1];
+                    }
+                    root->cell_f[i] = root->bound_max[i];
+                    nrange[1]=i; 
+                    dd_cell_sizes_dlb_root_enforce_limits(dd, d, dim, root, ddbox, bUniform, step, cellsize_limit_f, nrange);
+                    nrange[0]=i;
+                    nrange[1]=range[1];
+                }
+            }
+            if (nrange[1] < range[1])   /* found last a LimLo */
+            {
+                root->cell_f[nrange[1]] = root->bound_min[nrange[1]];
+                dd_cell_sizes_dlb_root_enforce_limits(dd, d, dim, root, ddbox, bUniform, step, cellsize_limit_f, nrange);
+                nrange[0]=nrange[1];
+                nrange[1]=range[1];
+                dd_cell_sizes_dlb_root_enforce_limits(dd, d, dim, root, ddbox, bUniform, step, cellsize_limit_f, nrange);
+            } 
+            else if (nrange[0] > range[0]) /* found at least one LimHi */
+            {
+                dd_cell_sizes_dlb_root_enforce_limits(dd, d, dim, root, ddbox, bUniform, step, cellsize_limit_f, nrange);
+            }
+        }
+    }
+}
+
+
+static void set_dd_cell_sizes_dlb_root(gmx_domdec_t *dd,
+                                       int d,int dim,gmx_domdec_root_t *root,
+                                       gmx_ddbox_t *ddbox,gmx_bool bDynamicBox,
+                                       gmx_bool bUniform,gmx_large_int_t step)
+{
+    gmx_domdec_comm_t *comm;
+    int  ncd,d1,i,j,pos;
+    real *cell_size;
+    real load_aver,load_i,imbalance,change,change_max,sc;
+    real cellsize_limit_f,dist_min_f,dist_min_f_hard,space;
+    real change_limit = 0.1;
+    real relax = 0.5;
+    gmx_bool bPBC;
+    int range[] = { 0, 0 };
+
+    comm = dd->comm;
+
+    ncd = dd->nc[dim];
+
+    bPBC = (dim < ddbox->npbcdim);
+
+    cell_size = root->buf_ncd;
+
+    /* Store the original boundaries */
+    for(i=0; i<ncd+1; i++)
+    {
+        root->old_cell_f[i] = root->cell_f[i];
+    }
+    if (bUniform) {
+        for(i=0; i<ncd; i++)
+        {
+            cell_size[i] = 1.0/ncd;
+        }
+    }
+    else if (dd_load_count(comm))
+    {
+        load_aver = comm->load[d].sum_m/ncd;
+        change_max = 0;
+        for(i=0; i<ncd; i++)
+        {
+            /* Determine the relative imbalance of cell i */
+            load_i = comm->load[d].load[i*comm->load[d].nload+2];
+            imbalance = (load_i - load_aver)/(load_aver>0 ? load_aver : 1);
+            /* Determine the change of the cell size using underrelaxation */
+            change = -relax*imbalance;
+            change_max = max(change_max,max(change,-change));
+        }
+        /* Limit the amount of scaling.
+         * We need to use the same rescaling for all cells in one row,
+         * otherwise the load balancing might not converge.
+         */
+        sc = relax;
+        if (change_max > change_limit)
+        {
+            sc *= change_limit/change_max;
+        }
+        for(i=0; i<ncd; i++)
+        {
+            /* Determine the relative imbalance of cell i */
+            load_i = comm->load[d].load[i*comm->load[d].nload+2];
+            imbalance = (load_i - load_aver)/(load_aver>0 ? load_aver : 1);
+            /* Determine the change of the cell size using underrelaxation */
+            change = -sc*imbalance;
+            cell_size[i] = (root->cell_f[i+1]-root->cell_f[i])*(1 + change);
+        }
+    }
+    
+    cellsize_limit_f  = comm->cellsize_min[dim]/ddbox->box_size[dim];
+    cellsize_limit_f *= DD_CELL_MARGIN;
+    dist_min_f_hard        = grid_jump_limit(comm,d)/ddbox->box_size[dim];
+    dist_min_f       = dist_min_f_hard * DD_CELL_MARGIN;
+    if (ddbox->tric_dir[dim])
+    {
+        cellsize_limit_f /= ddbox->skew_fac[dim];
+        dist_min_f       /= ddbox->skew_fac[dim];
+    }
+    if (bDynamicBox && d > 0)
+    {
+        dist_min_f *= DD_PRES_SCALE_MARGIN;
+    }
+    if (d > 0 && !bUniform)
+    {
+        /* Make sure that the grid is not shifted too much */
+        for(i=1; i<ncd; i++) {
+            if (root->cell_f_min1[i] - root->cell_f_max0[i-1] < 2 * dist_min_f_hard) 
+            {
+                gmx_incons("Inconsistent DD boundary staggering limits!");
+            }
+            root->bound_min[i] = root->cell_f_max0[i-1] + dist_min_f;
+            space = root->cell_f[i] - (root->cell_f_max0[i-1] + dist_min_f);
+            if (space > 0) {
+                root->bound_min[i] += 0.5*space;
+            }
+            root->bound_max[i] = root->cell_f_min1[i] - dist_min_f;
+            space = root->cell_f[i] - (root->cell_f_min1[i] - dist_min_f);
+            if (space < 0) {
+                root->bound_max[i] += 0.5*space;
+            }
+            if (debug)
+            {
+                fprintf(debug,
+                        "dim %d boundary %d %.3f < %.3f < %.3f < %.3f < %.3f\n",
+                        d,i,
+                        root->cell_f_max0[i-1] + dist_min_f,
+                        root->bound_min[i],root->cell_f[i],root->bound_max[i],
+                        root->cell_f_min1[i] - dist_min_f);
+            }
+        }
+    }
+    range[1]=ncd;
+    root->cell_f[0] = 0;
+    root->cell_f[ncd] = 1;
+    dd_cell_sizes_dlb_root_enforce_limits(dd, d, dim, root, ddbox, bUniform, step, cellsize_limit_f, range);
+
+
+    /* After the checks above, the cells should obey the cut-off
+     * restrictions, but it does not hurt to check.
+     */
+    for(i=0; i<ncd; i++)
+    {
+        if (debug)
+        {
+            fprintf(debug,"Relative bounds dim %d  cell %d: %f %f\n",
+                    dim,i,root->cell_f[i],root->cell_f[i+1]);
+        }
+
+        if ((bPBC || (i != 0 && i != dd->nc[dim]-1)) &&
+            root->cell_f[i+1] - root->cell_f[i] <
+            cellsize_limit_f/DD_CELL_MARGIN)
+        {
+            char buf[22];
+            fprintf(stderr,
+                    "\nWARNING step %s: direction %c, cell %d too small: %f\n",
+                    gmx_step_str(step,buf),dim2char(dim),i,
+                    (root->cell_f[i+1] - root->cell_f[i])
+                    *ddbox->box_size[dim]*ddbox->skew_fac[dim]);
+        }
+    }
+    
+    pos = ncd + 1;
+    /* Store the cell boundaries of the lower dimensions at the end */
+    for(d1=0; d1<d; d1++)
+    {
+        root->cell_f[pos++] = comm->cell_f0[d1];
+        root->cell_f[pos++] = comm->cell_f1[d1];
+    }
+    
+    if (d < comm->npmedecompdim)
+    {
+        /* The master determines the maximum shift for
+         * the coordinate communication between separate PME nodes.
+         */
+        set_pme_maxshift(dd,&comm->ddpme[d],bUniform,ddbox,root->cell_f);
+    }
+    root->cell_f[pos++] = comm->ddpme[0].maxshift;
+    if (d >= 1)
+    {
+        root->cell_f[pos++] = comm->ddpme[1].maxshift;
+    }
+}    
+
+static void relative_to_absolute_cell_bounds(gmx_domdec_t *dd,
+                                             gmx_ddbox_t *ddbox,int dimind)
+{
+    gmx_domdec_comm_t *comm;
+    int dim;
+
+    comm = dd->comm;
+
+    /* Set the cell dimensions */
+    dim = dd->dim[dimind];
+    comm->cell_x0[dim] = comm->cell_f0[dimind]*ddbox->box_size[dim];
+    comm->cell_x1[dim] = comm->cell_f1[dimind]*ddbox->box_size[dim];
+    if (dim >= ddbox->nboundeddim)
+    {
+        comm->cell_x0[dim] += ddbox->box0[dim];
+        comm->cell_x1[dim] += ddbox->box0[dim];
+    }
+}
+
+static void distribute_dd_cell_sizes_dlb(gmx_domdec_t *dd,
+                                         int d,int dim,real *cell_f_row,
+                                         gmx_ddbox_t *ddbox)
+{
+    gmx_domdec_comm_t *comm;
+    int d1,dim1,pos;
+
+    comm = dd->comm;
+
+#ifdef GMX_MPI
+    /* Each node would only need to know two fractions,
+     * but it is probably cheaper to broadcast the whole array.
+     */
+    MPI_Bcast(cell_f_row,DD_CELL_F_SIZE(dd,d)*sizeof(real),MPI_BYTE,
+              0,comm->mpi_comm_load[d]);
+#endif
+    /* Copy the fractions for this dimension from the buffer */
+    comm->cell_f0[d] = cell_f_row[dd->ci[dim]  ];
+    comm->cell_f1[d] = cell_f_row[dd->ci[dim]+1];
+    /* The whole array was communicated, so set the buffer position */
+    pos = dd->nc[dim] + 1;
+    for(d1=0; d1<=d; d1++)
+    {
+        if (d1 < d)
+        {
+            /* Copy the cell fractions of the lower dimensions */
+            comm->cell_f0[d1] = cell_f_row[pos++];
+            comm->cell_f1[d1] = cell_f_row[pos++];
+        }
+        relative_to_absolute_cell_bounds(dd,ddbox,d1);
+    }
+    /* Convert the communicated shift from float to int */
+    comm->ddpme[0].maxshift = (int)(cell_f_row[pos++] + 0.5);
+    if (d >= 1)
+    {
+        comm->ddpme[1].maxshift = (int)(cell_f_row[pos++] + 0.5);
+    }
+}
+
+static void set_dd_cell_sizes_dlb_change(gmx_domdec_t *dd,
+                                         gmx_ddbox_t *ddbox,gmx_bool bDynamicBox,
+                                         gmx_bool bUniform,gmx_large_int_t step)
+{
+    gmx_domdec_comm_t *comm;
+    int d,dim,d1;
+    gmx_bool bRowMember,bRowRoot;
+    real *cell_f_row;
+    
+    comm = dd->comm;
+
+    for(d=0; d<dd->ndim; d++)
+    {
+        dim = dd->dim[d];
+        bRowMember = TRUE;
+        bRowRoot = TRUE;
+        for(d1=d; d1<dd->ndim; d1++)
+        {
+            if (dd->ci[dd->dim[d1]] > 0)
+            {
+                if (d1 > d)
+                {
+                    bRowMember = FALSE;
+                }
+                bRowRoot = FALSE;
+            }
+        }
+        if (bRowMember)
+        {
+            if (bRowRoot)
+            {
+                set_dd_cell_sizes_dlb_root(dd,d,dim,comm->root[d],
+                                           ddbox,bDynamicBox,bUniform,step);
+                cell_f_row = comm->root[d]->cell_f;
+            }
+            else
+            {
+                cell_f_row = comm->cell_f_row;
+            }
+            distribute_dd_cell_sizes_dlb(dd,d,dim,cell_f_row,ddbox);
+        }
+    }
+}    
+
+static void set_dd_cell_sizes_dlb_nochange(gmx_domdec_t *dd,gmx_ddbox_t *ddbox)
+{
+    int d;
+
+    /* This function assumes the box is static and should therefore
+     * not be called when the box has changed since the last
+     * call to dd_partition_system.
+     */
+    for(d=0; d<dd->ndim; d++)
+    {
+        relative_to_absolute_cell_bounds(dd,ddbox,d); 
+    }
+}
+
+
+
+static void set_dd_cell_sizes_dlb(gmx_domdec_t *dd,
+                                  gmx_ddbox_t *ddbox,gmx_bool bDynamicBox,
+                                  gmx_bool bUniform,gmx_bool bDoDLB,gmx_large_int_t step,
+                                  gmx_wallcycle_t wcycle)
+{
+    gmx_domdec_comm_t *comm;
+    int dim;
+
+    comm = dd->comm;
+    
+    if (bDoDLB)
+    {
+        wallcycle_start(wcycle,ewcDDCOMMBOUND);
+        set_dd_cell_sizes_dlb_change(dd,ddbox,bDynamicBox,bUniform,step);
+        wallcycle_stop(wcycle,ewcDDCOMMBOUND);
+    }
+    else if (bDynamicBox)
+    {
+        set_dd_cell_sizes_dlb_nochange(dd,ddbox);
+    }
+    
+    /* Set the dimensions for which no DD is used */
+    for(dim=0; dim<DIM; dim++) {
+        if (dd->nc[dim] == 1) {
+            comm->cell_x0[dim] = 0;
+            comm->cell_x1[dim] = ddbox->box_size[dim];
+            if (dim >= ddbox->nboundeddim)
+            {
+                comm->cell_x0[dim] += ddbox->box0[dim];
+                comm->cell_x1[dim] += ddbox->box0[dim];
+            }
+        }
+    }
+}
+
+static void realloc_comm_ind(gmx_domdec_t *dd,ivec npulse)
+{
+    int d,np,i;
+    gmx_domdec_comm_dim_t *cd;
+    
+    for(d=0; d<dd->ndim; d++)
+    {
+        cd = &dd->comm->cd[d];
+        np = npulse[dd->dim[d]];
+        if (np > cd->np_nalloc)
+        {
+            if (debug)
+            {
+                fprintf(debug,"(Re)allocing cd for %c to %d pulses\n",
+                        dim2char(dd->dim[d]),np);
+            }
+            if (DDMASTER(dd) && cd->np_nalloc > 0)
+            {
+                fprintf(stderr,"\nIncreasing the number of cell to communicate in dimension %c to %d for the first time\n",dim2char(dd->dim[d]),np);
+            }
+            srenew(cd->ind,np);
+            for(i=cd->np_nalloc; i<np; i++)
+            {
+                cd->ind[i].index  = NULL;
+                cd->ind[i].nalloc = 0;
+            }
+            cd->np_nalloc = np;
+        }
+        cd->np = np;
+    }
+}
+
+
+static void set_dd_cell_sizes(gmx_domdec_t *dd,
+                              gmx_ddbox_t *ddbox,gmx_bool bDynamicBox,
+                              gmx_bool bUniform,gmx_bool bDoDLB,gmx_large_int_t step,
+                              gmx_wallcycle_t wcycle)
+{
+    gmx_domdec_comm_t *comm;
+    int  d;
+    ivec npulse;
+    
+    comm = dd->comm;
+
+    /* Copy the old cell boundaries for the cg displacement check */
+    copy_rvec(comm->cell_x0,comm->old_cell_x0);
+    copy_rvec(comm->cell_x1,comm->old_cell_x1);
+    
+    if (comm->bDynLoadBal)
+    {
+        if (DDMASTER(dd))
+        {
+            check_box_size(dd,ddbox);
+        }
+        set_dd_cell_sizes_dlb(dd,ddbox,bDynamicBox,bUniform,bDoDLB,step,wcycle);
+    }
+    else
+    {
+        set_dd_cell_sizes_slb(dd,ddbox,FALSE,npulse);
+        realloc_comm_ind(dd,npulse);
+    }
+    
+    if (debug)
+    {
+        for(d=0; d<DIM; d++)
+        {
+            fprintf(debug,"cell_x[%d] %f - %f skew_fac %f\n",
+                    d,comm->cell_x0[d],comm->cell_x1[d],ddbox->skew_fac[d]);
+        }
+    }
+}
+
+static void comm_dd_ns_cell_sizes(gmx_domdec_t *dd,
+                                  gmx_ddbox_t *ddbox,
+                                  rvec cell_ns_x0,rvec cell_ns_x1,
+                                  gmx_large_int_t step)
+{
+    gmx_domdec_comm_t *comm;
+    int dim_ind,dim;
+    
+    comm = dd->comm;
+
+    for(dim_ind=0; dim_ind<dd->ndim; dim_ind++)
+    {
+        dim = dd->dim[dim_ind];
+        
+        /* Without PBC we don't have restrictions on the outer cells */
+        if (!(dim >= ddbox->npbcdim && 
+              (dd->ci[dim] == 0 || dd->ci[dim] == dd->nc[dim] - 1)) &&
+            comm->bDynLoadBal &&
+            (comm->cell_x1[dim] - comm->cell_x0[dim])*ddbox->skew_fac[dim] <
+            comm->cellsize_min[dim])
+        {
+            char buf[22];
+            gmx_fatal(FARGS,"Step %s: The %c-size (%f) times the triclinic skew factor (%f) is smaller than the smallest allowed cell size (%f) for domain decomposition grid cell %d %d %d",
+                      gmx_step_str(step,buf),dim2char(dim),
+                      comm->cell_x1[dim] - comm->cell_x0[dim],
+                      ddbox->skew_fac[dim],
+                      dd->comm->cellsize_min[dim],
+                      dd->ci[XX],dd->ci[YY],dd->ci[ZZ]);
+        }
+    }
+    
+    if ((dd->bGridJump && dd->ndim > 1) || ddbox->nboundeddim < DIM)
+    {
+        /* Communicate the boundaries and update cell_ns_x0/1 */
+        dd_move_cellx(dd,ddbox,cell_ns_x0,cell_ns_x1);
+        if (dd->bGridJump && dd->ndim > 1)
+        {
+            check_grid_jump(step,dd,ddbox);
+        }
+    }
+}
+
+static void make_tric_corr_matrix(int npbcdim,matrix box,matrix tcm)
+{
+    if (YY < npbcdim)
+    {
+        tcm[YY][XX] = -box[YY][XX]/box[YY][YY];
+    }
+    else
+    {
+        tcm[YY][XX] = 0;
+    }
+    if (ZZ < npbcdim)
+    {
+        tcm[ZZ][XX] = -(box[ZZ][YY]*tcm[YY][XX] + box[ZZ][XX])/box[ZZ][ZZ];
+        tcm[ZZ][YY] = -box[ZZ][YY]/box[ZZ][ZZ];
+    }
+    else
+    {
+        tcm[ZZ][XX] = 0;
+        tcm[ZZ][YY] = 0;
+    }
+}
+
+static void check_screw_box(matrix box)
+{
+    /* Mathematical limitation */
+    if (box[YY][XX] != 0 || box[ZZ][XX] != 0)
+    {
+        gmx_fatal(FARGS,"With screw pbc the unit cell can not have non-zero off-diagonal x-components");
+    }
+    
+    /* Limitation due to the asymmetry of the eighth shell method */
+    if (box[ZZ][YY] != 0)
+    {
+        gmx_fatal(FARGS,"pbc=screw with non-zero box_zy is not supported");
+    }
+}
+
+static void distribute_cg(FILE *fplog,gmx_large_int_t step,
+                          matrix box,ivec tric_dir,t_block *cgs,rvec pos[],
+                          gmx_domdec_t *dd)
+{
+    gmx_domdec_master_t *ma;
+    int **tmp_ind=NULL,*tmp_nalloc=NULL;
+    int  i,icg,j,k,k0,k1,d,npbcdim;
+    matrix tcm;
+    rvec box_size,cg_cm;
+    ivec ind;
+    real nrcg,inv_ncg,pos_d;
+    atom_id *cgindex;
+    gmx_bool bUnbounded,bScrew;
+
+    ma = dd->ma;
+    
+    if (tmp_ind == NULL)
+    {
+        snew(tmp_nalloc,dd->nnodes);
+        snew(tmp_ind,dd->nnodes);
+        for(i=0; i<dd->nnodes; i++)
+        {
+            tmp_nalloc[i] = over_alloc_large(cgs->nr/dd->nnodes+1);
+            snew(tmp_ind[i],tmp_nalloc[i]);
+        }
+    }
+    
+    /* Clear the count */
+    for(i=0; i<dd->nnodes; i++)
+    {
+        ma->ncg[i] = 0;
+        ma->nat[i] = 0;
+    }
+    
+    make_tric_corr_matrix(dd->npbcdim,box,tcm);
+    
+    cgindex = cgs->index;
+    
+    /* Compute the center of geometry for all charge groups */
+    for(icg=0; icg<cgs->nr; icg++)
+    {
+        k0      = cgindex[icg];
+        k1      = cgindex[icg+1];
+        nrcg    = k1 - k0;
+        if (nrcg == 1)
+        {
+            copy_rvec(pos[k0],cg_cm);
+        }
+        else
+        {
+            inv_ncg = 1.0/nrcg;
+            
+            clear_rvec(cg_cm);
+            for(k=k0; (k<k1); k++)
+            {
+                rvec_inc(cg_cm,pos[k]);
+            }
+            for(d=0; (d<DIM); d++)
+            {
+                cg_cm[d] *= inv_ncg;
+            }
+        }
+        /* Put the charge group in the box and determine the cell index */
+        for(d=DIM-1; d>=0; d--) {
+            pos_d = cg_cm[d];
+            if (d < dd->npbcdim)
+            {
+                bScrew = (dd->bScrewPBC && d == XX);
+                if (tric_dir[d] && dd->nc[d] > 1)
+                {
+                    /* Use triclinic coordintates for this dimension */
+                    for(j=d+1; j<DIM; j++)
+                    {
+                        pos_d += cg_cm[j]*tcm[j][d];
+                    }
+                }
+                while(pos_d >= box[d][d])
+                {
+                    pos_d -= box[d][d];
+                    rvec_dec(cg_cm,box[d]);
+                    if (bScrew)
+                    {
+                        cg_cm[YY] = box[YY][YY] - cg_cm[YY];
+                        cg_cm[ZZ] = box[ZZ][ZZ] - cg_cm[ZZ];
+                    }
+                    for(k=k0; (k<k1); k++)
+                    {
+                        rvec_dec(pos[k],box[d]);
+                        if (bScrew)
+                        {
+                            pos[k][YY] = box[YY][YY] - pos[k][YY];
+                            pos[k][ZZ] = box[ZZ][ZZ] - pos[k][ZZ];
+                        }
+                    }
+                }
+                while(pos_d < 0)
+                {
+                    pos_d += box[d][d];
+                    rvec_inc(cg_cm,box[d]);
+                    if (bScrew)
+                    {
+                        cg_cm[YY] = box[YY][YY] - cg_cm[YY];
+                        cg_cm[ZZ] = box[ZZ][ZZ] - cg_cm[ZZ];
+                    }
+                    for(k=k0; (k<k1); k++)
+                    {
+                        rvec_inc(pos[k],box[d]);
+                        if (bScrew) {
+                            pos[k][YY] = box[YY][YY] - pos[k][YY];
+                            pos[k][ZZ] = box[ZZ][ZZ] - pos[k][ZZ];
+                        }
+                    }
+                }
+            }
+            /* This could be done more efficiently */
+            ind[d] = 0;
+            while(ind[d]+1 < dd->nc[d] && pos_d >= ma->cell_x[d][ind[d]+1])
+            {
+                ind[d]++;
+            }
+        }
+        i = dd_index(dd->nc,ind);
+        if (ma->ncg[i] == tmp_nalloc[i])
+        {
+            tmp_nalloc[i] = over_alloc_large(ma->ncg[i]+1);
+            srenew(tmp_ind[i],tmp_nalloc[i]);
+        }
+        tmp_ind[i][ma->ncg[i]] = icg;
+        ma->ncg[i]++;
+        ma->nat[i] += cgindex[icg+1] - cgindex[icg];
+    }
+    
+    k1 = 0;
+    for(i=0; i<dd->nnodes; i++)
+    {
+        ma->index[i] = k1;
+        for(k=0; k<ma->ncg[i]; k++)
+        {
+            ma->cg[k1++] = tmp_ind[i][k];
+        }
+    }
+    ma->index[dd->nnodes] = k1;
+    
+    for(i=0; i<dd->nnodes; i++)
+    {
+        sfree(tmp_ind[i]);
+    }
+    sfree(tmp_ind);
+    sfree(tmp_nalloc);
+    
+    if (fplog)
+    {
+        char buf[22];
+        fprintf(fplog,"Charge group distribution at step %s:",
+                gmx_step_str(step,buf));
+        for(i=0; i<dd->nnodes; i++)
+        {
+            fprintf(fplog," %d",ma->ncg[i]);
+        }
+        fprintf(fplog,"\n");
+    }
+}
+
+static void get_cg_distribution(FILE *fplog,gmx_large_int_t step,gmx_domdec_t *dd,
+                                t_block *cgs,matrix box,gmx_ddbox_t *ddbox,
+                                rvec pos[])
+{
+    gmx_domdec_master_t *ma=NULL;
+    ivec npulse;
+    int  i,cg_gl;
+    int  *ibuf,buf2[2] = { 0, 0 };
+    
+    if (DDMASTER(dd))
+    {
+        ma = dd->ma;
+        
+        if (dd->bScrewPBC)
+        {
+            check_screw_box(box);
+        }
+    
+        set_dd_cell_sizes_slb(dd,ddbox,TRUE,npulse);
+    
+        distribute_cg(fplog,step,box,ddbox->tric_dir,cgs,pos,dd);
+        for(i=0; i<dd->nnodes; i++)
+        {
+            ma->ibuf[2*i]   = ma->ncg[i];
+            ma->ibuf[2*i+1] = ma->nat[i];
+        }
+        ibuf = ma->ibuf;
+    }
+    else
+    {
+        ibuf = NULL;
+    }
+    dd_scatter(dd,2*sizeof(int),ibuf,buf2);
+    
+    dd->ncg_home = buf2[0];
+    dd->nat_home = buf2[1];
+    dd->ncg_tot  = dd->ncg_home;
+    dd->nat_tot  = dd->nat_home;
+    if (dd->ncg_home > dd->cg_nalloc || dd->cg_nalloc == 0)
+    {
+        dd->cg_nalloc = over_alloc_dd(dd->ncg_home);
+        srenew(dd->index_gl,dd->cg_nalloc);
+        srenew(dd->cgindex,dd->cg_nalloc+1);
+    }
+    if (DDMASTER(dd))
+    {
+        for(i=0; i<dd->nnodes; i++)
+        {
+            ma->ibuf[i] = ma->ncg[i]*sizeof(int);
+            ma->ibuf[dd->nnodes+i] = ma->index[i]*sizeof(int);
+        }
+    }
+    
+    dd_scatterv(dd,
+                DDMASTER(dd) ? ma->ibuf : NULL,
+                DDMASTER(dd) ? ma->ibuf+dd->nnodes : NULL,
+                DDMASTER(dd) ? ma->cg : NULL,
+                dd->ncg_home*sizeof(int),dd->index_gl);
+    
+    /* Determine the home charge group sizes */
+    dd->cgindex[0] = 0;
+    for(i=0; i<dd->ncg_home; i++)
+    {
+        cg_gl = dd->index_gl[i];
+        dd->cgindex[i+1] =
+            dd->cgindex[i] + cgs->index[cg_gl+1] - cgs->index[cg_gl];
+    }
+    
+    if (debug)
+    {
+        fprintf(debug,"Home charge groups:\n");
+        for(i=0; i<dd->ncg_home; i++)
+        {
+            fprintf(debug," %d",dd->index_gl[i]);
+            if (i % 10 == 9) 
+                fprintf(debug,"\n");
+        }
+        fprintf(debug,"\n");
+    }
+}
+
+static int compact_and_copy_vec_at(int ncg,int *move,
+                                   int *cgindex,
+                                   int nvec,int vec,
+                                   rvec *src,gmx_domdec_comm_t *comm,
+                                   gmx_bool bCompact)
+{
+    int m,icg,i,i0,i1,nrcg;
+    int home_pos;
+    int pos_vec[DIM*2];
+    
+    home_pos = 0;
+
+    for(m=0; m<DIM*2; m++)
+    {
+        pos_vec[m] = 0;
+    }
+    
+    i0 = 0;
+    for(icg=0; icg<ncg; icg++)
+    {
+        i1 = cgindex[icg+1];
+        m = move[icg];
+        if (m == -1)
+        {
+            if (bCompact)
+            {
+                /* Compact the home array in place */
+                for(i=i0; i<i1; i++)
+                {
+                    copy_rvec(src[i],src[home_pos++]);
+                }
+            }
+        }
+        else
+        {
+            /* Copy to the communication buffer */
+            nrcg = i1 - i0;
+            pos_vec[m] += 1 + vec*nrcg;
+            for(i=i0; i<i1; i++)
+            {
+                copy_rvec(src[i],comm->cgcm_state[m][pos_vec[m]++]);
+            }
+            pos_vec[m] += (nvec - vec - 1)*nrcg;
+        }
+        if (!bCompact)
+        {
+            home_pos += i1 - i0;
+        }
+        i0 = i1;
+    }
+    
+    return home_pos;
+}
+
+static int compact_and_copy_vec_cg(int ncg,int *move,
+                                   int *cgindex,
+                                   int nvec,rvec *src,gmx_domdec_comm_t *comm,
+                                   gmx_bool bCompact)
+{
+    int m,icg,i0,i1,nrcg;
+    int home_pos;
+    int pos_vec[DIM*2];
+    
+    home_pos = 0;
+    
+    for(m=0; m<DIM*2; m++)
+    {
+        pos_vec[m] = 0;
+    }
+    
+    i0 = 0;
+    for(icg=0; icg<ncg; icg++)
+    {
+        i1 = cgindex[icg+1];
+        m = move[icg];
+        if (m == -1)
+        {
+            if (bCompact)
+            {
+                /* Compact the home array in place */
+                copy_rvec(src[icg],src[home_pos++]);
+            }
+        }
+        else
+        {
+            nrcg = i1 - i0;
+            /* Copy to the communication buffer */
+            copy_rvec(src[icg],comm->cgcm_state[m][pos_vec[m]]);
+            pos_vec[m] += 1 + nrcg*nvec;
+        }
+        i0 = i1;
+    }
+    if (!bCompact)
+    {
+        home_pos = ncg;
+    }
+    
+    return home_pos;
+}
+
+static int compact_ind(int ncg,int *move,
+                       int *index_gl,int *cgindex,
+                       int *gatindex,
+                       gmx_ga2la_t ga2la,char *bLocalCG,
+                       int *cginfo)
+{
+    int cg,nat,a0,a1,a,a_gl;
+    int home_pos;
+
+    home_pos = 0;
+    nat = 0;
+    for(cg=0; cg<ncg; cg++)
+    {
+        a0 = cgindex[cg];
+        a1 = cgindex[cg+1];
+        if (move[cg] == -1)
+        {
+            /* Compact the home arrays in place.
+             * Anything that can be done here avoids access to global arrays.
+             */
+            cgindex[home_pos] = nat;
+            for(a=a0; a<a1; a++)
+            {
+                a_gl = gatindex[a];
+                gatindex[nat] = a_gl;
+                /* The cell number stays 0, so we don't need to set it */
+                ga2la_change_la(ga2la,a_gl,nat);
+                nat++;
+            }
+            index_gl[home_pos] = index_gl[cg];
+            cginfo[home_pos]   = cginfo[cg];
+            /* The charge group remains local, so bLocalCG does not change */
+            home_pos++;
+        }
+        else
+        {
+            /* Clear the global indices */
+            for(a=a0; a<a1; a++)
+            {
+                ga2la_del(ga2la,gatindex[a]);
+            }
+            if (bLocalCG)
+            {
+                bLocalCG[index_gl[cg]] = FALSE;
+            }
+        }
+    }
+    cgindex[home_pos] = nat;
+    
+    return home_pos;
+}
+
+static void clear_and_mark_ind(int ncg,int *move,
+                               int *index_gl,int *cgindex,int *gatindex,
+                               gmx_ga2la_t ga2la,char *bLocalCG,
+                               int *cell_index)
+{
+    int cg,a0,a1,a;
+    
+    for(cg=0; cg<ncg; cg++)
+    {
+        if (move[cg] >= 0)
+        {
+            a0 = cgindex[cg];
+            a1 = cgindex[cg+1];
+            /* Clear the global indices */
+            for(a=a0; a<a1; a++)
+            {
+                ga2la_del(ga2la,gatindex[a]);
+            }
+            if (bLocalCG)
+            {
+                bLocalCG[index_gl[cg]] = FALSE;
+            }
+            /* Signal that this cg has moved using the ns cell index.
+             * Here we set it to -1.
+             * fill_grid will change it from -1 to 4*grid->ncells.
+             */
+            cell_index[cg] = -1;
+        }
+    }
+}
+
+static void print_cg_move(FILE *fplog,
+                          gmx_domdec_t *dd,
+                          gmx_large_int_t step,int cg,int dim,int dir,
+                          gmx_bool bHaveLimitdAndCMOld,real limitd,
+                          rvec cm_old,rvec cm_new,real pos_d)
+{
+    gmx_domdec_comm_t *comm;
+    char buf[22];
+
+    comm = dd->comm;
+
+    fprintf(fplog,"\nStep %s:\n",gmx_step_str(step,buf));
+    if (bHaveLimitdAndCMOld)
+    {
+        fprintf(fplog,"The charge group starting at atom %d moved than the distance allowed by the domain decomposition (%f) in direction %c\n",
+                ddglatnr(dd,dd->cgindex[cg]),limitd,dim2char(dim));
+    }
+    else
+    {
+        fprintf(fplog,"The charge group starting at atom %d moved than the distance allowed by the domain decomposition in direction %c\n",
+                ddglatnr(dd,dd->cgindex[cg]),dim2char(dim));
+    }
+    fprintf(fplog,"distance out of cell %f\n",
+            dir==1 ? pos_d - comm->cell_x1[dim] : pos_d - comm->cell_x0[dim]);
+    if (bHaveLimitdAndCMOld)
+    {
+        fprintf(fplog,"Old coordinates: %8.3f %8.3f %8.3f\n",
+                cm_old[XX],cm_old[YY],cm_old[ZZ]);
+    }
+    fprintf(fplog,"New coordinates: %8.3f %8.3f %8.3f\n",
+            cm_new[XX],cm_new[YY],cm_new[ZZ]);
+    fprintf(fplog,"Old cell boundaries in direction %c: %8.3f %8.3f\n",
+            dim2char(dim),
+            comm->old_cell_x0[dim],comm->old_cell_x1[dim]);
+    fprintf(fplog,"New cell boundaries in direction %c: %8.3f %8.3f\n",
+            dim2char(dim),
+            comm->cell_x0[dim],comm->cell_x1[dim]);
+}
+
+static void cg_move_error(FILE *fplog,
+                          gmx_domdec_t *dd,
+                          gmx_large_int_t step,int cg,int dim,int dir,
+                          gmx_bool bHaveLimitdAndCMOld,real limitd,
+                          rvec cm_old,rvec cm_new,real pos_d)
+{
+    if (fplog)
+    {
+        print_cg_move(fplog, dd,step,cg,dim,dir,
+                      bHaveLimitdAndCMOld,limitd,cm_old,cm_new,pos_d);
+    }
+    print_cg_move(stderr,dd,step,cg,dim,dir,
+                  bHaveLimitdAndCMOld,limitd,cm_old,cm_new,pos_d);
+    gmx_fatal(FARGS,
+              "A charge group moved too far between two domain decomposition steps\n"
+              "This usually means that your system is not well equilibrated");
+}
+
+static void rotate_state_atom(t_state *state,int a)
+{
+    int est;
+
+    for(est=0; est<estNR; est++)
+    {
+        if (EST_DISTR(est) && state->flags & (1<<est)) {
+            switch (est) {
+            case estX:
+                /* Rotate the complete state; for a rectangular box only */
+                state->x[a][YY] = state->box[YY][YY] - state->x[a][YY];
+                state->x[a][ZZ] = state->box[ZZ][ZZ] - state->x[a][ZZ];
+                break;
+            case estV:
+                state->v[a][YY] = -state->v[a][YY];
+                state->v[a][ZZ] = -state->v[a][ZZ];
+                break;
+            case estSDX:
+                state->sd_X[a][YY] = -state->sd_X[a][YY];
+                state->sd_X[a][ZZ] = -state->sd_X[a][ZZ];
+                break;
+            case estCGP:
+                state->cg_p[a][YY] = -state->cg_p[a][YY];
+                state->cg_p[a][ZZ] = -state->cg_p[a][ZZ];
+                break;
+            case estDISRE_INITF:
+            case estDISRE_RM3TAV:
+            case estORIRE_INITF:
+            case estORIRE_DTAV:
+                /* These are distances, so not affected by rotation */
+                break;
+            default:
+                gmx_incons("Unknown state entry encountered in rotate_state_atom");            
+            }
+        }
+    }
+}
+
+static int dd_redistribute_cg(FILE *fplog,gmx_large_int_t step,
+                              gmx_domdec_t *dd,ivec tric_dir,
+                              t_state *state,rvec **f,
+                              t_forcerec *fr,t_mdatoms *md,
+                              gmx_bool bCompact,
+                              t_nrnb *nrnb)
+{
+    int  *move;
+    int  npbcdim;
+    int  ncg[DIM*2],nat[DIM*2];
+    int  c,i,cg,k,k0,k1,d,dim,dim2,dir,d2,d3,d4,cell_d;
+    int  mc,cdd,nrcg,ncg_recv,nat_recv,nvs,nvr,nvec,vec;
+    int  sbuf[2],rbuf[2];
+    int  home_pos_cg,home_pos_at,ncg_stay_home,buf_pos;
+    int  flag;
+    gmx_bool bV=FALSE,bSDX=FALSE,bCGP=FALSE;
+    gmx_bool bScrew;
+    ivec dev;
+    real inv_ncg,pos_d;
+    matrix tcm;
+    rvec *cg_cm,cell_x0,cell_x1,limitd,limit0,limit1,cm_new;
+    atom_id *cgindex;
+    cginfo_mb_t *cginfo_mb;
+    gmx_domdec_comm_t *comm;
+    
+    if (dd->bScrewPBC)
+    {
+        check_screw_box(state->box);
+    }
+    
+    comm  = dd->comm;
+    cg_cm = fr->cg_cm;
+    
+    for(i=0; i<estNR; i++)
+    {
+        if (EST_DISTR(i))
+        {
+            switch (i)
+            {
+            case estX:   /* Always present */            break;
+            case estV:   bV   = (state->flags & (1<<i)); break;
+            case estSDX: bSDX = (state->flags & (1<<i)); break;
+            case estCGP: bCGP = (state->flags & (1<<i)); break;
+            case estLD_RNG:
+            case estLD_RNGI:
+            case estDISRE_INITF:
+            case estDISRE_RM3TAV:
+            case estORIRE_INITF:
+            case estORIRE_DTAV:
+                /* No processing required */
+                break;
+            default:
+            gmx_incons("Unknown state entry encountered in dd_redistribute_cg");
+            }
+        }
+    }
+    
+    if (dd->ncg_tot > comm->nalloc_int)
+    {
+        comm->nalloc_int = over_alloc_dd(dd->ncg_tot);
+        srenew(comm->buf_int,comm->nalloc_int);
+    }
+    move = comm->buf_int;
+    
+    /* Clear the count */
+    for(c=0; c<dd->ndim*2; c++)
+    {
+        ncg[c] = 0;
+        nat[c] = 0;
+    }
+
+    npbcdim = dd->npbcdim;
+
+    for(d=0; (d<DIM); d++)
+    {
+        limitd[d] = dd->comm->cellsize_min[d];
+        if (d >= npbcdim && dd->ci[d] == 0)
+        {
+            cell_x0[d] = -GMX_FLOAT_MAX;
+        }
+        else
+        {
+            cell_x0[d] = comm->cell_x0[d];
+        }
+        if (d >= npbcdim && dd->ci[d] == dd->nc[d] - 1)
+        {
+            cell_x1[d] = GMX_FLOAT_MAX;
+        }
+        else
+        {
+            cell_x1[d] = comm->cell_x1[d];
+        }
+        if (d < npbcdim)
+        {
+            limit0[d] = comm->old_cell_x0[d] - limitd[d];
+            limit1[d] = comm->old_cell_x1[d] + limitd[d];
+        }
+        else
+        {
+            /* We check after communication if a charge group moved
+             * more than one cell. Set the pre-comm check limit to float_max.
+             */
+            limit0[d] = -GMX_FLOAT_MAX;
+            limit1[d] =  GMX_FLOAT_MAX;
+        }
+    }
+    
+    make_tric_corr_matrix(npbcdim,state->box,tcm);
+    
+    cgindex = dd->cgindex;
+    
+    /* Compute the center of geometry for all home charge groups
+     * and put them in the box and determine where they should go.
+     */
+    for(cg=0; cg<dd->ncg_home; cg++)
+    {
+        k0   = cgindex[cg];
+        k1   = cgindex[cg+1];
+        nrcg = k1 - k0;
+        if (nrcg == 1)
+        {
+            copy_rvec(state->x[k0],cm_new);
+        }
+        else
+        {
+            inv_ncg = 1.0/nrcg;
+            
+            clear_rvec(cm_new);
+            for(k=k0; (k<k1); k++)
+            {
+                rvec_inc(cm_new,state->x[k]);
+            }
+            for(d=0; (d<DIM); d++)
+            {
+                cm_new[d] = inv_ncg*cm_new[d];
+            }
+        }
+        
+        clear_ivec(dev);
+        /* Do pbc and check DD cell boundary crossings */
+        for(d=DIM-1; d>=0; d--)
+        {
+            if (dd->nc[d] > 1)
+            {
+                bScrew = (dd->bScrewPBC && d == XX);
+                /* Determine the location of this cg in lattice coordinates */
+                pos_d = cm_new[d];
+                if (tric_dir[d])
+                {
+                    for(d2=d+1; d2<DIM; d2++)
+                    {
+                        pos_d += cm_new[d2]*tcm[d2][d];
+                    }
+                }
+                /* Put the charge group in the triclinic unit-cell */
+                if (pos_d >= cell_x1[d])
+                {
+                    if (pos_d >= limit1[d])
+                    {
+                        cg_move_error(fplog,dd,step,cg,d,1,TRUE,limitd[d],
+                                      cg_cm[cg],cm_new,pos_d);
+                    }
+                    dev[d] = 1;
+                    if (dd->ci[d] == dd->nc[d] - 1)
+                    {
+                        rvec_dec(cm_new,state->box[d]);
+                        if (bScrew)
+                        {
+                            cm_new[YY] = state->box[YY][YY] - cm_new[YY];
+                            cm_new[ZZ] = state->box[ZZ][ZZ] - cm_new[ZZ];
+                        }
+                        for(k=k0; (k<k1); k++)
+                        {
+                            rvec_dec(state->x[k],state->box[d]);
+                            if (bScrew)
+                            {
+                                rotate_state_atom(state,k);
+                            }
+                        }
+                    }
+                }
+                else if (pos_d < cell_x0[d])
+                {
+                    if (pos_d < limit0[d])
+                    {
+                        cg_move_error(fplog,dd,step,cg,d,-1,TRUE,limitd[d],
+                                      cg_cm[cg],cm_new,pos_d);
+                    }
+                    dev[d] = -1;
+                    if (dd->ci[d] == 0)
+                    {
+                        rvec_inc(cm_new,state->box[d]);
+                        if (bScrew)
+                        {
+                            cm_new[YY] = state->box[YY][YY] - cm_new[YY];
+                            cm_new[ZZ] = state->box[ZZ][ZZ] - cm_new[ZZ];
+                        }
+                        for(k=k0; (k<k1); k++)
+                        {
+                            rvec_inc(state->x[k],state->box[d]);
+                            if (bScrew)
+                            {
+                                rotate_state_atom(state,k);
+                            }
+                        }
+                    }
+                }
+            }
+            else if (d < npbcdim)
+            {
+                /* Put the charge group in the rectangular unit-cell */
+                while (cm_new[d] >= state->box[d][d])
+                {
+                    rvec_dec(cm_new,state->box[d]);
+                    for(k=k0; (k<k1); k++)
+                    {
+                        rvec_dec(state->x[k],state->box[d]);
+                    }
+                }
+                while (cm_new[d] < 0)
+                {
+                    rvec_inc(cm_new,state->box[d]);
+                    for(k=k0; (k<k1); k++)
+                    {
+                        rvec_inc(state->x[k],state->box[d]);
+                    }
+                }
+            }
+        }
+    
+        copy_rvec(cm_new,cg_cm[cg]);
+        
+        /* Determine where this cg should go */
+        flag = 0;
+        mc = -1;
+        for(d=0; d<dd->ndim; d++)
+        {
+            dim = dd->dim[d];
+            if (dev[dim] == 1)
+            {
+                flag |= DD_FLAG_FW(d);
+                if (mc == -1)
+                {
+                    mc = d*2;
+                }
+            }
+            else if (dev[dim] == -1)
+            {
+                flag |= DD_FLAG_BW(d);
+                if (mc == -1) {
+                    if (dd->nc[dim] > 2)
+                    {
+                        mc = d*2 + 1;
+                    }
+                    else
+                    {
+                        mc = d*2;
+                    }
+                }
+            }
+        }
+        move[cg] = mc;
+        if (mc >= 0)
+        {
+            if (ncg[mc]+1 > comm->cggl_flag_nalloc[mc])
+            {
+                comm->cggl_flag_nalloc[mc] = over_alloc_dd(ncg[mc]+1);
+                srenew(comm->cggl_flag[mc],comm->cggl_flag_nalloc[mc]*DD_CGIBS);
+            }
+            comm->cggl_flag[mc][ncg[mc]*DD_CGIBS  ] = dd->index_gl[cg];
+            /* We store the cg size in the lower 16 bits
+             * and the place where the charge group should go
+             * in the next 6 bits. This saves some communication volume.
+             */
+            comm->cggl_flag[mc][ncg[mc]*DD_CGIBS+1] = nrcg | flag;
+            ncg[mc] += 1;
+            nat[mc] += nrcg;
+        }
+    }
+    
+    inc_nrnb(nrnb,eNR_CGCM,dd->nat_home);
+    inc_nrnb(nrnb,eNR_RESETX,dd->ncg_home);
+    
+    nvec = 1;
+    if (bV)
+    {
+        nvec++;
+    }
+    if (bSDX)
+    {
+        nvec++;
+    }
+    if (bCGP)
+    {
+        nvec++;
+    }
+    
+    /* Make sure the communication buffers are large enough */
+    for(mc=0; mc<dd->ndim*2; mc++)
+    {
+        nvr = ncg[mc] + nat[mc]*nvec;
+        if (nvr > comm->cgcm_state_nalloc[mc])
+        {
+            comm->cgcm_state_nalloc[mc] = over_alloc_dd(nvr);
+            srenew(comm->cgcm_state[mc],comm->cgcm_state_nalloc[mc]);
+        }
+    }
+    
+    /* Recalculating cg_cm might be cheaper than communicating,
+     * but that could give rise to rounding issues.
+     */
+    home_pos_cg =
+        compact_and_copy_vec_cg(dd->ncg_home,move,cgindex,
+                                nvec,cg_cm,comm,bCompact);
+    
+    vec = 0;
+    home_pos_at =
+        compact_and_copy_vec_at(dd->ncg_home,move,cgindex,
+                                nvec,vec++,state->x,comm,bCompact);
+    if (bV)
+    {
+        compact_and_copy_vec_at(dd->ncg_home,move,cgindex,
+                                nvec,vec++,state->v,comm,bCompact);
+    }
+    if (bSDX)
+    {
+        compact_and_copy_vec_at(dd->ncg_home,move,cgindex,
+                                nvec,vec++,state->sd_X,comm,bCompact);
+    }
+    if (bCGP)
+    {
+        compact_and_copy_vec_at(dd->ncg_home,move,cgindex,
+                                nvec,vec++,state->cg_p,comm,bCompact);
+    }
+    
+    if (bCompact)
+    {
+        compact_ind(dd->ncg_home,move,
+                    dd->index_gl,dd->cgindex,dd->gatindex,
+                    dd->ga2la,comm->bLocalCG,
+                    fr->cginfo);
+    }
+    else
+    {
+        clear_and_mark_ind(dd->ncg_home,move,
+                           dd->index_gl,dd->cgindex,dd->gatindex,
+                           dd->ga2la,comm->bLocalCG,
+                           fr->ns.grid->cell_index);
+    }
+    
+    cginfo_mb = fr->cginfo_mb;
+
+    ncg_stay_home = home_pos_cg;
+    for(d=0; d<dd->ndim; d++)
+    {
+        dim = dd->dim[d];
+        ncg_recv = 0;
+        nat_recv = 0;
+        nvr      = 0;
+        for(dir=0; dir<(dd->nc[dim]==2 ? 1 : 2); dir++)
+        {
+            cdd = d*2 + dir;
+            /* Communicate the cg and atom counts */
+            sbuf[0] = ncg[cdd];
+            sbuf[1] = nat[cdd];
+            if (debug)
+            {
+                fprintf(debug,"Sending ddim %d dir %d: ncg %d nat %d\n",
+                        d,dir,sbuf[0],sbuf[1]);
+            }
+            dd_sendrecv_int(dd, d, dir, sbuf, 2, rbuf, 2);
+            
+            if ((ncg_recv+rbuf[0])*DD_CGIBS > comm->nalloc_int)
+            {
+                comm->nalloc_int = over_alloc_dd((ncg_recv+rbuf[0])*DD_CGIBS);
+                srenew(comm->buf_int,comm->nalloc_int);
+            }
+            
+            /* Communicate the charge group indices, sizes and flags */
+            dd_sendrecv_int(dd, d, dir,
+                            comm->cggl_flag[cdd], sbuf[0]*DD_CGIBS,
+                            comm->buf_int+ncg_recv*DD_CGIBS, rbuf[0]*DD_CGIBS);
+            
+            nvs = ncg[cdd] + nat[cdd]*nvec;
+            i   = rbuf[0]  + rbuf[1] *nvec;
+            vec_rvec_check_alloc(&comm->vbuf,nvr+i);
+            
+            /* Communicate cgcm and state */
+            dd_sendrecv_rvec(dd, d, dir,
+                             comm->cgcm_state[cdd], nvs,
+                             comm->vbuf.v+nvr, i);
+            ncg_recv += rbuf[0];
+            nat_recv += rbuf[1];
+            nvr      += i;
+        }
+        
+        /* Process the received charge groups */
+        buf_pos = 0;
+        for(cg=0; cg<ncg_recv; cg++)
+        {
+            flag = comm->buf_int[cg*DD_CGIBS+1];
+
+            if (dim >= npbcdim && dd->nc[dim] > 2)
+            {
+                /* No pbc in this dim and more than one domain boundary.
+                 * We to a separate check if a charge did not move too far.
+                 */
+                if (((flag & DD_FLAG_FW(d)) &&
+                     comm->vbuf.v[buf_pos][d] > cell_x1[dim]) ||
+                    ((flag & DD_FLAG_BW(d)) &&
+                     comm->vbuf.v[buf_pos][d] < cell_x0[dim]))
+                {
+                    cg_move_error(fplog,dd,step,cg,d,
+                                  (flag & DD_FLAG_FW(d)) ? 1 : 0,
+                                   FALSE,0,
+                                   comm->vbuf.v[buf_pos],
+                                   comm->vbuf.v[buf_pos],
+                                   comm->vbuf.v[buf_pos][d]);
+                }
+            }
+
+            mc = -1;
+            if (d < dd->ndim-1)
+            {
+                /* Check which direction this cg should go */
+                for(d2=d+1; (d2<dd->ndim && mc==-1); d2++)
+                {
+                    if (dd->bGridJump)
+                    {
+                        /* The cell boundaries for dimension d2 are not equal
+                         * for each cell row of the lower dimension(s),
+                         * therefore we might need to redetermine where
+                         * this cg should go.
+                         */
+                        dim2 = dd->dim[d2];
+                        /* If this cg crosses the box boundary in dimension d2
+                         * we can use the communicated flag, so we do not
+                         * have to worry about pbc.
+                         */
+                        if (!((dd->ci[dim2] == dd->nc[dim2]-1 &&
+                               (flag & DD_FLAG_FW(d2))) ||
+                              (dd->ci[dim2] == 0 &&
+                               (flag & DD_FLAG_BW(d2)))))
+                        {
+                            /* Clear the two flags for this dimension */
+                            flag &= ~(DD_FLAG_FW(d2) | DD_FLAG_BW(d2));
+                            /* Determine the location of this cg
+                             * in lattice coordinates
+                             */
+                            pos_d = comm->vbuf.v[buf_pos][dim2];
+                            if (tric_dir[dim2])
+                            {
+                                for(d3=dim2+1; d3<DIM; d3++)
+                                {
+                                    pos_d +=
+                                        comm->vbuf.v[buf_pos][d3]*tcm[d3][dim2];
+                                }
+                            }
+                            /* Check of we are not at the box edge.
+                             * pbc is only handled in the first step above,
+                             * but this check could move over pbc while
+                             * the first step did not due to different rounding.
+                             */
+                            if (pos_d >= cell_x1[dim2] &&
+                                dd->ci[dim2] != dd->nc[dim2]-1)
+                            {
+                                flag |= DD_FLAG_FW(d2);
+                            }
+                            else if (pos_d < cell_x0[dim2] &&
+                                     dd->ci[dim2] != 0)
+                            {
+                                flag |= DD_FLAG_BW(d2);
+                            }
+                            comm->buf_int[cg*DD_CGIBS+1] = flag;
+                        }
+                    }
+                    /* Set to which neighboring cell this cg should go */
+                    if (flag & DD_FLAG_FW(d2))
+                    {
+                        mc = d2*2;
+                    }
+                    else if (flag & DD_FLAG_BW(d2))
+                    {
+                        if (dd->nc[dd->dim[d2]] > 2)
+                        {
+                            mc = d2*2+1;
+                        }
+                        else
+                        {
+                            mc = d2*2;
+                        }
+                    }
+                }
+            }
+            
+            nrcg = flag & DD_FLAG_NRCG;
+            if (mc == -1)
+            {
+                if (home_pos_cg+1 > dd->cg_nalloc)
+                {
+                    dd->cg_nalloc = over_alloc_dd(home_pos_cg+1);
+                    srenew(dd->index_gl,dd->cg_nalloc);
+                    srenew(dd->cgindex,dd->cg_nalloc+1);
+                }
+                /* Set the global charge group index and size */
+                dd->index_gl[home_pos_cg] = comm->buf_int[cg*DD_CGIBS];
+                dd->cgindex[home_pos_cg+1] = dd->cgindex[home_pos_cg] + nrcg;
+                /* Copy the state from the buffer */
+                if (home_pos_cg >= fr->cg_nalloc)
+                {
+                    dd_realloc_fr_cg(fr,home_pos_cg+1);
+                    cg_cm = fr->cg_cm;
+                }
+                copy_rvec(comm->vbuf.v[buf_pos++],cg_cm[home_pos_cg]);
+                /* Set the cginfo */
+                fr->cginfo[home_pos_cg] = ddcginfo(cginfo_mb,
+                                                   dd->index_gl[home_pos_cg]);
+                if (comm->bLocalCG)
+                {
+                    comm->bLocalCG[dd->index_gl[home_pos_cg]] = TRUE;
+                }
+
+                if (home_pos_at+nrcg > state->nalloc)
+                {
+                    dd_realloc_state(state,f,home_pos_at+nrcg);
+                }
+                for(i=0; i<nrcg; i++)
+                {
+                    copy_rvec(comm->vbuf.v[buf_pos++],
+                              state->x[home_pos_at+i]);
+                }
+                if (bV)
+                {
+                    for(i=0; i<nrcg; i++)
+                    {
+                        copy_rvec(comm->vbuf.v[buf_pos++],
+                                  state->v[home_pos_at+i]);
+                    }
+                }
+                if (bSDX)
+                {
+                    for(i=0; i<nrcg; i++)
+                    {
+                        copy_rvec(comm->vbuf.v[buf_pos++],
+                                  state->sd_X[home_pos_at+i]);
+                    }
+                }
+                if (bCGP)
+                {
+                    for(i=0; i<nrcg; i++)
+                    {
+                        copy_rvec(comm->vbuf.v[buf_pos++],
+                                  state->cg_p[home_pos_at+i]);
+                    }
+                }
+                home_pos_cg += 1;
+                home_pos_at += nrcg;
+            }
+            else
+            {
+                /* Reallocate the buffers if necessary  */
+                if (ncg[mc]+1 > comm->cggl_flag_nalloc[mc])
+                {
+                    comm->cggl_flag_nalloc[mc] = over_alloc_dd(ncg[mc]+1);
+                    srenew(comm->cggl_flag[mc],comm->cggl_flag_nalloc[mc]*DD_CGIBS);
+                }
+                nvr = ncg[mc] + nat[mc]*nvec;
+                if (nvr + 1 + nrcg*nvec > comm->cgcm_state_nalloc[mc])
+                {
+                    comm->cgcm_state_nalloc[mc] = over_alloc_dd(nvr + 1 + nrcg*nvec);
+                    srenew(comm->cgcm_state[mc],comm->cgcm_state_nalloc[mc]);
+                }
+                /* Copy from the receive to the send buffers */
+                memcpy(comm->cggl_flag[mc] + ncg[mc]*DD_CGIBS,
+                       comm->buf_int + cg*DD_CGIBS,
+                       DD_CGIBS*sizeof(int));
+                memcpy(comm->cgcm_state[mc][nvr],
+                       comm->vbuf.v[buf_pos],
+                       (1+nrcg*nvec)*sizeof(rvec));
+                buf_pos += 1 + nrcg*nvec;
+                ncg[mc] += 1;
+                nat[mc] += nrcg;
+            }
+        }
+    }
+    
+    /* With sorting (!bCompact) the indices are now only partially up to date
+     * and ncg_home and nat_home are not the real count, since there are
+     * "holes" in the arrays for the charge groups that moved to neighbors.
+     */
+    dd->ncg_home = home_pos_cg;
+    dd->nat_home = home_pos_at;
+
+    if (debug)
+    {
+        fprintf(debug,"Finished repartitioning\n");
+    }
+
+    return ncg_stay_home;
+}
+
+void dd_cycles_add(gmx_domdec_t *dd,float cycles,int ddCycl)
+{
+    dd->comm->cycl[ddCycl] += cycles;
+    dd->comm->cycl_n[ddCycl]++;
+    if (cycles > dd->comm->cycl_max[ddCycl])
+    {
+        dd->comm->cycl_max[ddCycl] = cycles;
+    }
+}
+
+static double force_flop_count(t_nrnb *nrnb)
+{
+    int i;
+    double sum;
+    const char *name;
+
+    sum = 0;
+    for(i=eNR_NBKERNEL010; i<eNR_NBKERNEL_FREE_ENERGY; i++)
+    {
+        /* To get closer to the real timings, we half the count
+         * for the normal loops and again half it for water loops.
+         */
+        name = nrnb_str(i);
+        if (strstr(name,"W3") != NULL || strstr(name,"W4") != NULL)
+        {
+            sum += nrnb->n[i]*0.25*cost_nrnb(i);
+        }
+        else
+        {
+            sum += nrnb->n[i]*0.50*cost_nrnb(i);
+        }
+    }
+    for(i=eNR_NBKERNEL_FREE_ENERGY; i<=eNR_NB14; i++)
+    {
+        name = nrnb_str(i);
+        if (strstr(name,"W3") != NULL || strstr(name,"W4") != NULL)
+        sum += nrnb->n[i]*cost_nrnb(i);
+    }
+    for(i=eNR_BONDS; i<=eNR_WALLS; i++)
+    {
+        sum += nrnb->n[i]*cost_nrnb(i);
+    }
+
+    return sum;
+}
+
+void dd_force_flop_start(gmx_domdec_t *dd,t_nrnb *nrnb)
+{
+    if (dd->comm->eFlop)
+    {
+        dd->comm->flop -= force_flop_count(nrnb);
+    }
+}
+void dd_force_flop_stop(gmx_domdec_t *dd,t_nrnb *nrnb)
+{
+    if (dd->comm->eFlop)
+    {
+        dd->comm->flop += force_flop_count(nrnb);
+        dd->comm->flop_n++;
+    }
+}  
+
+static void clear_dd_cycle_counts(gmx_domdec_t *dd)
+{
+    int i;
+    
+    for(i=0; i<ddCyclNr; i++)
+    {
+        dd->comm->cycl[i] = 0;
+        dd->comm->cycl_n[i] = 0;
+        dd->comm->cycl_max[i] = 0;
+    }
+    dd->comm->flop = 0;
+    dd->comm->flop_n = 0;
+}
+
+static void get_load_distribution(gmx_domdec_t *dd,gmx_wallcycle_t wcycle)
+{
+    gmx_domdec_comm_t *comm;
+    gmx_domdec_load_t *load;
+    gmx_domdec_root_t *root=NULL;
+    int  d,dim,cid,i,pos;
+    float cell_frac=0,sbuf[DD_NLOAD_MAX];
+    gmx_bool bSepPME;
+    
+    if (debug)
+    {
+        fprintf(debug,"get_load_distribution start\n");
+    }
+
+    wallcycle_start(wcycle,ewcDDCOMMLOAD);
+    
+    comm = dd->comm;
+    
+    bSepPME = (dd->pme_nodeid >= 0);
+    
+    for(d=dd->ndim-1; d>=0; d--)
+    {
+        dim = dd->dim[d];
+        /* Check if we participate in the communication in this dimension */
+        if (d == dd->ndim-1 || 
+            (dd->ci[dd->dim[d+1]]==0 && dd->ci[dd->dim[dd->ndim-1]]==0))
+        {
+            load = &comm->load[d];
+            if (dd->bGridJump)
+            {
+                cell_frac = comm->cell_f1[d] - comm->cell_f0[d];
+            }
+            pos = 0;
+            if (d == dd->ndim-1)
+            {
+                sbuf[pos++] = dd_force_load(comm);
+                sbuf[pos++] = sbuf[0];
+                if (dd->bGridJump)
+                {
+                    sbuf[pos++] = sbuf[0];
+                    sbuf[pos++] = cell_frac;
+                    if (d > 0)
+                    {
+                        sbuf[pos++] = comm->cell_f_max0[d];
+                        sbuf[pos++] = comm->cell_f_min1[d];
+                    }
+                }
+                if (bSepPME)
+                {
+                    sbuf[pos++] = comm->cycl[ddCyclPPduringPME];
+                    sbuf[pos++] = comm->cycl[ddCyclPME];
+                }
+            }
+            else
+            {
+                sbuf[pos++] = comm->load[d+1].sum;
+                sbuf[pos++] = comm->load[d+1].max;
+                if (dd->bGridJump)
+                {
+                    sbuf[pos++] = comm->load[d+1].sum_m;
+                    sbuf[pos++] = comm->load[d+1].cvol_min*cell_frac;
+                    sbuf[pos++] = comm->load[d+1].flags;
+                    if (d > 0)
+                    {
+                        sbuf[pos++] = comm->cell_f_max0[d];
+                        sbuf[pos++] = comm->cell_f_min1[d];
+                    }
+                }
+                if (bSepPME)
+                {
+                    sbuf[pos++] = comm->load[d+1].mdf;
+                    sbuf[pos++] = comm->load[d+1].pme;
+                }
+            }
+            load->nload = pos;
+            /* Communicate a row in DD direction d.
+             * The communicators are setup such that the root always has rank 0.
+             */
+#ifdef GMX_MPI
+            MPI_Gather(sbuf      ,load->nload*sizeof(float),MPI_BYTE,
+                       load->load,load->nload*sizeof(float),MPI_BYTE,
+                       0,comm->mpi_comm_load[d]);
+#endif
+            if (dd->ci[dim] == dd->master_ci[dim])
+            {
+                /* We are the root, process this row */
+                if (comm->bDynLoadBal)
+                {
+                    root = comm->root[d];
+                }
+                load->sum = 0;
+                load->max = 0;
+                load->sum_m = 0;
+                load->cvol_min = 1;
+                load->flags = 0;
+                load->mdf = 0;
+                load->pme = 0;
+                pos = 0;
+                for(i=0; i<dd->nc[dim]; i++)
+                {
+                    load->sum += load->load[pos++];
+                    load->max = max(load->max,load->load[pos]);
+                    pos++;
+                    if (dd->bGridJump)
+                    {
+                        if (root->bLimited)
+                        {
+                            /* This direction could not be load balanced properly,
+                             * therefore we need to use the maximum iso the average load.
+                             */
+                            load->sum_m = max(load->sum_m,load->load[pos]);
+                        }
+                        else
+                        {
+                            load->sum_m += load->load[pos];
+                        }
+                        pos++;
+                        load->cvol_min = min(load->cvol_min,load->load[pos]);
+                        pos++;
+                        if (d < dd->ndim-1)
+                        {
+                            load->flags = (int)(load->load[pos++] + 0.5);
+                        }
+                        if (d > 0)
+                        {
+                            root->cell_f_max0[i] = load->load[pos++];
+                            root->cell_f_min1[i] = load->load[pos++];
+                        }
+                    }
+                    if (bSepPME)
+                    {
+                        load->mdf = max(load->mdf,load->load[pos]);
+                        pos++;
+                        load->pme = max(load->pme,load->load[pos]);
+                        pos++;
+                    }
+                }
+                if (comm->bDynLoadBal && root->bLimited)
+                {
+                    load->sum_m *= dd->nc[dim];
+                    load->flags |= (1<<d);
+                }
+            }
+        }
+    }
+
+    if (DDMASTER(dd))
+    {
+        comm->nload      += dd_load_count(comm);
+        comm->load_step  += comm->cycl[ddCyclStep];
+        comm->load_sum   += comm->load[0].sum;
+        comm->load_max   += comm->load[0].max;
+        if (comm->bDynLoadBal)
+        {
+            for(d=0; d<dd->ndim; d++)
+            {
+                if (comm->load[0].flags & (1<<d))
+                {
+                    comm->load_lim[d]++;
+                }
+            }
+        }
+        if (bSepPME)
+        {
+            comm->load_mdf += comm->load[0].mdf;
+            comm->load_pme += comm->load[0].pme;
+        }
+    }
+
+    wallcycle_stop(wcycle,ewcDDCOMMLOAD);
+    
+    if (debug)
+    {
+        fprintf(debug,"get_load_distribution finished\n");
+    }
+}
+
+static float dd_force_imb_perf_loss(gmx_domdec_t *dd)
+{
+    /* Return the relative performance loss on the total run time
+     * due to the force calculation load imbalance.
+     */
+    if (dd->comm->nload > 0)
+    {
+        return
+            (dd->comm->load_max*dd->nnodes - dd->comm->load_sum)/
+            (dd->comm->load_step*dd->nnodes);
+    }
+    else
+    {
+        return 0;
+    }
+}
+
+static void print_dd_load_av(FILE *fplog,gmx_domdec_t *dd)
+{
+    char  buf[STRLEN];
+    int   npp,npme,nnodes,d,limp;
+    float imbal,pme_f_ratio,lossf,lossp=0;
+    gmx_bool  bLim;
+    gmx_domdec_comm_t *comm;
+
+    comm = dd->comm;
+    if (DDMASTER(dd) && comm->nload > 0)
+    {
+        npp    = dd->nnodes;
+        npme   = (dd->pme_nodeid >= 0) ? comm->npmenodes : 0;
+        nnodes = npp + npme;
+        imbal = comm->load_max*npp/comm->load_sum - 1;
+        lossf = dd_force_imb_perf_loss(dd);
+        sprintf(buf," Average load imbalance: %.1f %%\n",imbal*100);
+        fprintf(fplog,"%s",buf);
+        fprintf(stderr,"\n");
+        fprintf(stderr,"%s",buf);
+        sprintf(buf," Part of the total run time spent waiting due to load imbalance: %.1f %%\n",lossf*100);
+        fprintf(fplog,"%s",buf);
+        fprintf(stderr,"%s",buf);
+        bLim = FALSE;
+        if (comm->bDynLoadBal)
+        {
+            sprintf(buf," Steps where the load balancing was limited by -rdd, -rcon and/or -dds:");
+            for(d=0; d<dd->ndim; d++)
+            {
+                limp = (200*comm->load_lim[d]+1)/(2*comm->nload);
+                sprintf(buf+strlen(buf)," %c %d %%",dim2char(dd->dim[d]),limp);
+                if (limp >= 50)
+                {
+                    bLim = TRUE;
+                }
+            }
+            sprintf(buf+strlen(buf),"\n");
+            fprintf(fplog,"%s",buf);
+            fprintf(stderr,"%s",buf);
+        }
+        if (npme > 0)
+        {
+            pme_f_ratio = comm->load_pme/comm->load_mdf;
+            lossp = (comm->load_pme -comm->load_mdf)/comm->load_step;
+            if (lossp <= 0)
+            {
+                lossp *= (float)npme/(float)nnodes;
+            }
+            else
+            {
+                lossp *= (float)npp/(float)nnodes;
+            }
+            sprintf(buf," Average PME mesh/force load: %5.3f\n",pme_f_ratio);
+            fprintf(fplog,"%s",buf);
+            fprintf(stderr,"%s",buf);
+            sprintf(buf," Part of the total run time spent waiting due to PP/PME imbalance: %.1f %%\n",fabs(lossp)*100);
+            fprintf(fplog,"%s",buf);
+            fprintf(stderr,"%s",buf);
+        }
+        fprintf(fplog,"\n");
+        fprintf(stderr,"\n");
+        
+        if (lossf >= DD_PERF_LOSS)
+        {
+            sprintf(buf,
+                    "NOTE: %.1f %% performance was lost due to load imbalance\n"
+                    "      in the domain decomposition.\n",lossf*100);
+            if (!comm->bDynLoadBal)
+            {
+                sprintf(buf+strlen(buf),"      You might want to use dynamic load balancing (option -dlb.)\n");
+            }
+            else if (bLim)
+            {
+                sprintf(buf+strlen(buf),"      You might want to decrease the cell size limit (options -rdd, -rcon and/or -dds).\n");
+            }
+            fprintf(fplog,"%s\n",buf);
+            fprintf(stderr,"%s\n",buf);
+        }
+        if (npme > 0 && fabs(lossp) >= DD_PERF_LOSS)
+        {
+            sprintf(buf,
+                    "NOTE: %.1f %% performance was lost because the PME nodes\n"
+                    "      had %s work to do than the PP nodes.\n"
+                    "      You might want to %s the number of PME nodes\n"
+                    "      or %s the cut-off and the grid spacing.\n",
+                    fabs(lossp*100),
+                    (lossp < 0) ? "less"     : "more",
+                    (lossp < 0) ? "decrease" : "increase",
+                    (lossp < 0) ? "decrease" : "increase");
+            fprintf(fplog,"%s\n",buf);
+            fprintf(stderr,"%s\n",buf);
+        }
+    }
+}
+
+static float dd_vol_min(gmx_domdec_t *dd)
+{
+    return dd->comm->load[0].cvol_min*dd->nnodes;
+}
+
+static gmx_bool dd_load_flags(gmx_domdec_t *dd)
+{
+    return dd->comm->load[0].flags;
+}
+
+static float dd_f_imbal(gmx_domdec_t *dd)
+{
+    return dd->comm->load[0].max*dd->nnodes/dd->comm->load[0].sum - 1;
+}
+
+static float dd_pme_f_ratio(gmx_domdec_t *dd)
+{
+    return dd->comm->load[0].pme/dd->comm->load[0].mdf;
+}
+
+static void dd_print_load(FILE *fplog,gmx_domdec_t *dd,gmx_large_int_t step)
+{
+    int flags,d;
+    char buf[22];
+    
+    flags = dd_load_flags(dd);
+    if (flags)
+    {
+        fprintf(fplog,
+                "DD  load balancing is limited by minimum cell size in dimension");
+        for(d=0; d<dd->ndim; d++)
+        {
+            if (flags & (1<<d))
+            {
+                fprintf(fplog," %c",dim2char(dd->dim[d]));
+            }
+        }
+        fprintf(fplog,"\n");
+    }
+    fprintf(fplog,"DD  step %s",gmx_step_str(step,buf));
+    if (dd->comm->bDynLoadBal)
+    {
+        fprintf(fplog,"  vol min/aver %5.3f%c",
+                dd_vol_min(dd),flags ? '!' : ' ');
+    }
+    fprintf(fplog," load imb.: force %4.1f%%",dd_f_imbal(dd)*100);
+    if (dd->comm->cycl_n[ddCyclPME])
+    {
+        fprintf(fplog,"  pme mesh/force %5.3f",dd_pme_f_ratio(dd));
+    }
+    fprintf(fplog,"\n\n");
+}
+
+static void dd_print_load_verbose(gmx_domdec_t *dd)
+{
+    if (dd->comm->bDynLoadBal)
+    {
+        fprintf(stderr,"vol %4.2f%c ",
+                dd_vol_min(dd),dd_load_flags(dd) ? '!' : ' ');
+    }
+    fprintf(stderr,"imb F %2d%% ",(int)(dd_f_imbal(dd)*100+0.5));
+    if (dd->comm->cycl_n[ddCyclPME])
+    {
+        fprintf(stderr,"pme/F %4.2f ",dd_pme_f_ratio(dd));
+    }
+}
+
+#ifdef GMX_MPI
+static void make_load_communicator(gmx_domdec_t *dd,MPI_Group g_all,
+                                   int dim_ind,ivec loc)
+{
+    MPI_Group g_row;
+    MPI_Comm  c_row;
+    int  dim,i,*rank;
+    ivec loc_c;
+    gmx_domdec_root_t *root;
+    
+    dim = dd->dim[dim_ind];
+    copy_ivec(loc,loc_c);
+    snew(rank,dd->nc[dim]);
+    for(i=0; i<dd->nc[dim]; i++)
+    {
+        loc_c[dim] = i;
+        rank[i] = dd_index(dd->nc,loc_c);
+    }
+    /* Here we create a new group, that does not necessarily
+     * include our process. But MPI_Comm_create needs to be
+     * called by all the processes in the original communicator.
+     * Calling MPI_Group_free afterwards gives errors, so I assume
+     * also the group is needed by all processes. (B. Hess)
+     */
+    MPI_Group_incl(g_all,dd->nc[dim],rank,&g_row);
+    MPI_Comm_create(dd->mpi_comm_all,g_row,&c_row);
+    if (c_row != MPI_COMM_NULL)
+    {
+        /* This process is part of the group */
+        dd->comm->mpi_comm_load[dim_ind] = c_row;
+        if (dd->comm->eDLB != edlbNO)
+        {
+            if (dd->ci[dim] == dd->master_ci[dim])
+            {
+                /* This is the root process of this row */
+                snew(dd->comm->root[dim_ind],1);
+                root = dd->comm->root[dim_ind];
+                snew(root->cell_f,DD_CELL_F_SIZE(dd,dim_ind));
+                snew(root->old_cell_f,dd->nc[dim]+1);
+                snew(root->bCellMin,dd->nc[dim]);
+                if (dim_ind > 0)
+                {
+                    snew(root->cell_f_max0,dd->nc[dim]);
+                    snew(root->cell_f_min1,dd->nc[dim]);
+                    snew(root->bound_min,dd->nc[dim]);
+                    snew(root->bound_max,dd->nc[dim]);
+                }
+                snew(root->buf_ncd,dd->nc[dim]);
+            }
+            else
+            {
+                /* This is not a root process, we only need to receive cell_f */
+                snew(dd->comm->cell_f_row,DD_CELL_F_SIZE(dd,dim_ind));
+            }
+        }
+        if (dd->ci[dim] == dd->master_ci[dim])
+        {
+            snew(dd->comm->load[dim_ind].load,dd->nc[dim]*DD_NLOAD_MAX);
+        }
+    }
+    sfree(rank);
+}
+#endif
+
+static void make_load_communicators(gmx_domdec_t *dd)
+{
+#ifdef GMX_MPI
+  MPI_Group g_all;
+  int  dim0,dim1,i,j;
+  ivec loc;
+
+  if (debug)
+    fprintf(debug,"Making load communicators\n");
+
+  MPI_Comm_group(dd->mpi_comm_all,&g_all);
+  
+  snew(dd->comm->load,dd->ndim);
+  snew(dd->comm->mpi_comm_load,dd->ndim);
+  
+  clear_ivec(loc);
+  make_load_communicator(dd,g_all,0,loc);
+  if (dd->ndim > 1) {
+    dim0 = dd->dim[0];
+    for(i=0; i<dd->nc[dim0]; i++) {
+      loc[dim0] = i;
+      make_load_communicator(dd,g_all,1,loc);
+    }
+  }
+  if (dd->ndim > 2) {
+    dim0 = dd->dim[0];
+    for(i=0; i<dd->nc[dim0]; i++) {
+      loc[dim0] = i;
+      dim1 = dd->dim[1];
+      for(j=0; j<dd->nc[dim1]; j++) {
+         loc[dim1] = j;
+         make_load_communicator(dd,g_all,2,loc);
+      }
+    }
+  }
+
+  MPI_Group_free(&g_all);
+
+  if (debug)
+    fprintf(debug,"Finished making load communicators\n");
+#endif
+}
+
+void setup_dd_grid(FILE *fplog,gmx_domdec_t *dd)
+{
+    gmx_bool bZYX;
+    int  d,dim,i,j,m;
+    ivec tmp,s;
+    int  nzone,nzonep;
+    ivec dd_zp[DD_MAXIZONE];
+    gmx_domdec_zones_t *zones;
+    gmx_domdec_ns_ranges_t *izone;
+    
+    for(d=0; d<dd->ndim; d++)
+    {
+        dim = dd->dim[d];
+        copy_ivec(dd->ci,tmp);
+        tmp[dim] = (tmp[dim] + 1) % dd->nc[dim];
+        dd->neighbor[d][0] = ddcoord2ddnodeid(dd,tmp);
+        copy_ivec(dd->ci,tmp);
+        tmp[dim] = (tmp[dim] - 1 + dd->nc[dim]) % dd->nc[dim];
+        dd->neighbor[d][1] = ddcoord2ddnodeid(dd,tmp);
+        if (debug)
+        {
+            fprintf(debug,"DD rank %d neighbor ranks in dir %d are + %d - %d\n",
+                    dd->rank,dim,
+                    dd->neighbor[d][0],
+                    dd->neighbor[d][1]);
+        }
+    }
+    
+    if (DDMASTER(dd))
+    {
+        fprintf(stderr,"Making %dD domain decomposition %d x %d x %d\n",
+           dd->ndim,dd->nc[XX],dd->nc[YY],dd->nc[ZZ]);
+    }
+    if (fplog)
+    {
+        fprintf(fplog,"\nMaking %dD domain decomposition grid %d x %d x %d, home cell index %d %d %d\n\n",
+                dd->ndim,
+                dd->nc[XX],dd->nc[YY],dd->nc[ZZ],
+                dd->ci[XX],dd->ci[YY],dd->ci[ZZ]);
+    }
+    switch (dd->ndim)
+    {
+    case 3:
+        nzone  = dd_z3n;
+        nzonep = dd_zp3n;
+        for(i=0; i<nzonep; i++)
+        {
+            copy_ivec(dd_zp3[i],dd_zp[i]);
+        }
+        break;
+    case 2:
+        nzone  = dd_z2n;
+        nzonep = dd_zp2n;
+        for(i=0; i<nzonep; i++)
+        {
+            copy_ivec(dd_zp2[i],dd_zp[i]);
+        }
+        break;
+    case 1:
+        nzone  = dd_z1n;
+        nzonep = dd_zp1n;
+        for(i=0; i<nzonep; i++)
+        {
+            copy_ivec(dd_zp1[i],dd_zp[i]);
+        }
+        break;
+    default:
+        gmx_fatal(FARGS,"Can only do 1, 2 or 3D domain decomposition");
+        nzone = 0;
+        nzonep = 0;
+    }
+
+    zones = &dd->comm->zones;
+
+    for(i=0; i<nzone; i++)
+    {
+        m = 0;
+        clear_ivec(zones->shift[i]);
+        for(d=0; d<dd->ndim; d++)
+        {
+            zones->shift[i][dd->dim[d]] = dd_zo[i][m++];
+        }
+    }
+    
+    zones->n = nzone;
+    for(i=0; i<nzone; i++)
+    {
+        for(d=0; d<DIM; d++)
+        {
+            s[d] = dd->ci[d] - zones->shift[i][d];
+            if (s[d] < 0)
+            {
+                s[d] += dd->nc[d];
+            }
+            else if (s[d] >= dd->nc[d])
+            {
+                s[d] -= dd->nc[d];
+            }
+        }
+    }
+    zones->nizone = nzonep;
+    for(i=0; i<zones->nizone; i++)
+    {
+        if (dd_zp[i][0] != i)
+        {
+            gmx_fatal(FARGS,"Internal inconsistency in the dd grid setup");
+        }
+        izone = &zones->izone[i];
+        izone->j0 = dd_zp[i][1];
+        izone->j1 = dd_zp[i][2];
+        for(dim=0; dim<DIM; dim++)
+        {
+            if (dd->nc[dim] == 1)
+            {
+                /* All shifts should be allowed */
+                izone->shift0[dim] = -1;
+                izone->shift1[dim] = 1;
+            }
+            else
+            {
+                /*
+                  izone->shift0[d] = 0;
+                  izone->shift1[d] = 0;
+                  for(j=izone->j0; j<izone->j1; j++) {
+                  if (dd->shift[j][d] > dd->shift[i][d])
+                  izone->shift0[d] = -1;
+                  if (dd->shift[j][d] < dd->shift[i][d])
+                  izone->shift1[d] = 1;
+                  }
+                */
+                
+                int shift_diff;
+                
+                /* Assume the shift are not more than 1 cell */
+                izone->shift0[dim] = 1;
+                izone->shift1[dim] = -1;
+                for(j=izone->j0; j<izone->j1; j++)
+                {
+                    shift_diff = zones->shift[j][dim] - zones->shift[i][dim];
+                    if (shift_diff < izone->shift0[dim])
+                    {
+                        izone->shift0[dim] = shift_diff;
+                    }
+                    if (shift_diff > izone->shift1[dim])
+                    {
+                        izone->shift1[dim] = shift_diff;
+                    }
+                }
+            }
+        }
+    }
+    
+    if (dd->comm->eDLB != edlbNO)
+    {
+        snew(dd->comm->root,dd->ndim);
+    }
+    
+    if (dd->comm->bRecordLoad)
+    {
+        make_load_communicators(dd);
+    }
+}
+
+static void make_pp_communicator(FILE *fplog,t_commrec *cr,int reorder)
+{
+    gmx_domdec_t *dd;
+    gmx_domdec_comm_t *comm;
+    int  i,rank,*buf;
+    ivec periods;
+#ifdef GMX_MPI
+    MPI_Comm comm_cart;
+#endif
+    
+    dd = cr->dd;
+    comm = dd->comm;
+    
+#ifdef GMX_MPI
+    if (comm->bCartesianPP)
+    {
+        /* Set up cartesian communication for the particle-particle part */
+        if (fplog)
+        {
+            fprintf(fplog,"Will use a Cartesian communicator: %d x %d x %d\n",
+                    dd->nc[XX],dd->nc[YY],dd->nc[ZZ]);
+        }
+        
+        for(i=0; i<DIM; i++)
+        {
+            periods[i] = TRUE;
+        }
+        MPI_Cart_create(cr->mpi_comm_mygroup,DIM,dd->nc,periods,reorder,
+                        &comm_cart);
+        /* We overwrite the old communicator with the new cartesian one */
+        cr->mpi_comm_mygroup = comm_cart;
+    }
+    
+    dd->mpi_comm_all = cr->mpi_comm_mygroup;
+    MPI_Comm_rank(dd->mpi_comm_all,&dd->rank);
+    
+    if (comm->bCartesianPP_PME)
+    {
+        /* Since we want to use the original cartesian setup for sim,
+         * and not the one after split, we need to make an index.
+         */
+        snew(comm->ddindex2ddnodeid,dd->nnodes);
+        comm->ddindex2ddnodeid[dd_index(dd->nc,dd->ci)] = dd->rank;
+        gmx_sumi(dd->nnodes,comm->ddindex2ddnodeid,cr);
+        /* Get the rank of the DD master,
+         * above we made sure that the master node is a PP node.
+         */
+        if (MASTER(cr))
+        {
+            rank = dd->rank;
+        }
+        else
+        {
+            rank = 0;
+        }
+        MPI_Allreduce(&rank,&dd->masterrank,1,MPI_INT,MPI_SUM,dd->mpi_comm_all);
+    }
+    else if (comm->bCartesianPP)
+    {
+        if (cr->npmenodes == 0)
+        {
+            /* The PP communicator is also
+             * the communicator for this simulation
+             */
+            cr->mpi_comm_mysim = cr->mpi_comm_mygroup;
+        }
+        cr->nodeid = dd->rank;
+        
+        MPI_Cart_coords(dd->mpi_comm_all,dd->rank,DIM,dd->ci);
+        
+        /* We need to make an index to go from the coordinates
+         * to the nodeid of this simulation.
+         */
+        snew(comm->ddindex2simnodeid,dd->nnodes);
+        snew(buf,dd->nnodes);
+        if (cr->duty & DUTY_PP)
+        {
+            buf[dd_index(dd->nc,dd->ci)] = cr->sim_nodeid;
+        }
+        /* Communicate the ddindex to simulation nodeid index */
+        MPI_Allreduce(buf,comm->ddindex2simnodeid,dd->nnodes,MPI_INT,MPI_SUM,
+                      cr->mpi_comm_mysim);
+        sfree(buf);
+        
+        /* Determine the master coordinates and rank.
+         * The DD master should be the same node as the master of this sim.
+         */
+        for(i=0; i<dd->nnodes; i++)
+        {
+            if (comm->ddindex2simnodeid[i] == 0)
+            {
+                ddindex2xyz(dd->nc,i,dd->master_ci);
+                MPI_Cart_rank(dd->mpi_comm_all,dd->master_ci,&dd->masterrank);
+            }
+        }
+        if (debug)
+        {
+            fprintf(debug,"The master rank is %d\n",dd->masterrank);
+        }
+    }
+    else
+    {
+        /* No Cartesian communicators */
+        /* We use the rank in dd->comm->all as DD index */
+        ddindex2xyz(dd->nc,dd->rank,dd->ci);
+        /* The simulation master nodeid is 0, so the DD master rank is also 0 */
+        dd->masterrank = 0;
+        clear_ivec(dd->master_ci);
+    }
+#endif
+  
+    if (fplog)
+    {
+        fprintf(fplog,
+                "Domain decomposition nodeid %d, coordinates %d %d %d\n\n",
+                dd->rank,dd->ci[XX],dd->ci[YY],dd->ci[ZZ]);
+    }
+    if (debug)
+    {
+        fprintf(debug,
+                "Domain decomposition nodeid %d, coordinates %d %d %d\n\n",
+                dd->rank,dd->ci[XX],dd->ci[YY],dd->ci[ZZ]);
+    }
+}
+
+static void receive_ddindex2simnodeid(t_commrec *cr)
+{
+    gmx_domdec_t *dd;
+    
+    gmx_domdec_comm_t *comm;
+    int  *buf;
+    
+    dd = cr->dd;
+    comm = dd->comm;
+    
+#ifdef GMX_MPI
+    if (!comm->bCartesianPP_PME && comm->bCartesianPP)
+    {
+        snew(comm->ddindex2simnodeid,dd->nnodes);
+        snew(buf,dd->nnodes);
+        if (cr->duty & DUTY_PP)
+        {
+            buf[dd_index(dd->nc,dd->ci)] = cr->sim_nodeid;
+        }
+#ifdef GMX_MPI
+        /* Communicate the ddindex to simulation nodeid index */
+        MPI_Allreduce(buf,comm->ddindex2simnodeid,dd->nnodes,MPI_INT,MPI_SUM,
+                      cr->mpi_comm_mysim);
+#endif
+        sfree(buf);
+    }
+#endif
+}
+
+static gmx_domdec_master_t *init_gmx_domdec_master_t(gmx_domdec_t *dd,
+                                                     int ncg,int natoms)
+{
+    gmx_domdec_master_t *ma;
+    int i;
+
+    snew(ma,1);
+    
+    snew(ma->ncg,dd->nnodes);
+    snew(ma->index,dd->nnodes+1);
+    snew(ma->cg,ncg);
+    snew(ma->nat,dd->nnodes);
+    snew(ma->ibuf,dd->nnodes*2);
+    snew(ma->cell_x,DIM);
+    for(i=0; i<DIM; i++)
+    {
+        snew(ma->cell_x[i],dd->nc[i]+1);
+    }
+
+    if (dd->nnodes <= GMX_DD_NNODES_SENDRECV)
+    {
+        ma->vbuf = NULL;
+    }
+    else
+    {
+        snew(ma->vbuf,natoms);
+    }
+
+    return ma;
+}
+
+static void split_communicator(FILE *fplog,t_commrec *cr,int dd_node_order,
+                               int reorder)
+{
+    gmx_domdec_t *dd;
+    gmx_domdec_comm_t *comm;
+    int  i,rank;
+    gmx_bool bDiv[DIM];
+    ivec periods;
+#ifdef GMX_MPI
+    MPI_Comm comm_cart;
+#endif
+    
+    dd = cr->dd;
+    comm = dd->comm;
+    
+    if (comm->bCartesianPP)
+    {
+        for(i=1; i<DIM; i++)
+        {
+            bDiv[i] = ((cr->npmenodes*dd->nc[i]) % (dd->nnodes) == 0);
+        }
+        if (bDiv[YY] || bDiv[ZZ])
+        {
+            comm->bCartesianPP_PME = TRUE;
+            /* If we have 2D PME decomposition, which is always in x+y,
+             * we stack the PME only nodes in z.
+             * Otherwise we choose the direction that provides the thinnest slab
+             * of PME only nodes as this will have the least effect
+             * on the PP communication.
+             * But for the PME communication the opposite might be better.
+             */
+            if (bDiv[ZZ] && (comm->npmenodes_y > 1 ||
+                             !bDiv[YY] ||
+                             dd->nc[YY] > dd->nc[ZZ]))
+            {
+                comm->cartpmedim = ZZ;
+            }
+            else
+            {
+                comm->cartpmedim = YY;
+            }
+            comm->ntot[comm->cartpmedim]
+                += (cr->npmenodes*dd->nc[comm->cartpmedim])/dd->nnodes;
+        }
+        else if (fplog)
+        {
+            fprintf(fplog,"#pmenodes (%d) is not a multiple of nx*ny (%d*%d) or nx*nz (%d*%d)\n",cr->npmenodes,dd->nc[XX],dd->nc[YY],dd->nc[XX],dd->nc[ZZ]);
+            fprintf(fplog,
+                    "Will not use a Cartesian communicator for PP <-> PME\n\n");
+        }
+    }
+    
+#ifdef GMX_MPI
+    if (comm->bCartesianPP_PME)
+    {
+        if (fplog)
+        {
+            fprintf(fplog,"Will use a Cartesian communicator for PP <-> PME: %d x %d x %d\n",comm->ntot[XX],comm->ntot[YY],comm->ntot[ZZ]);
+        }
+        
+        for(i=0; i<DIM; i++)
+        {
+            periods[i] = TRUE;
+        }
+        MPI_Cart_create(cr->mpi_comm_mysim,DIM,comm->ntot,periods,reorder,
+                        &comm_cart);
+        
+        MPI_Comm_rank(comm_cart,&rank);
+        if (MASTERNODE(cr) && rank != 0)
+        {
+            gmx_fatal(FARGS,"MPI rank 0 was renumbered by MPI_Cart_create, we do not allow this");
+        }
+        
+        /* With this assigment we loose the link to the original communicator
+         * which will usually be MPI_COMM_WORLD, unless have multisim.
+         */
+        cr->mpi_comm_mysim = comm_cart;
+        cr->sim_nodeid = rank;
+        
+        MPI_Cart_coords(cr->mpi_comm_mysim,cr->sim_nodeid,DIM,dd->ci);
+        
+        if (fplog)
+        {
+            fprintf(fplog,"Cartesian nodeid %d, coordinates %d %d %d\n\n",
+                    cr->sim_nodeid,dd->ci[XX],dd->ci[YY],dd->ci[ZZ]);
+        }
+        
+        if (dd->ci[comm->cartpmedim] < dd->nc[comm->cartpmedim])
+        {
+            cr->duty = DUTY_PP;
+        }
+        if (cr->npmenodes == 0 ||
+            dd->ci[comm->cartpmedim] >= dd->nc[comm->cartpmedim])
+        {
+            cr->duty = DUTY_PME;
+        }
+        
+        /* Split the sim communicator into PP and PME only nodes */
+        MPI_Comm_split(cr->mpi_comm_mysim,
+                       cr->duty,
+                       dd_index(comm->ntot,dd->ci),
+                       &cr->mpi_comm_mygroup);
+    }
+    else
+    {
+        switch (dd_node_order)
+        {
+        case ddnoPP_PME:
+            if (fplog)
+            {
+                fprintf(fplog,"Order of the nodes: PP first, PME last\n");
+            }
+            break;
+        case ddnoINTERLEAVE:
+            /* Interleave the PP-only and PME-only nodes,
+             * as on clusters with dual-core machines this will double
+             * the communication bandwidth of the PME processes
+             * and thus speed up the PP <-> PME and inter PME communication.
+             */
+            if (fplog)
+            {
+                fprintf(fplog,"Interleaving PP and PME nodes\n");
+            }
+            comm->pmenodes = dd_pmenodes(cr);
+            break;
+        case ddnoCARTESIAN:
+            break;
+        default:
+            gmx_fatal(FARGS,"Unknown dd_node_order=%d",dd_node_order);
+        }
+    
+        if (dd_simnode2pmenode(cr,cr->sim_nodeid) == -1)
+        {
+            cr->duty = DUTY_PME;
+        }
+        else
+        {
+            cr->duty = DUTY_PP;
+        }
+        
+        /* Split the sim communicator into PP and PME only nodes */
+        MPI_Comm_split(cr->mpi_comm_mysim,
+                       cr->duty,
+                       cr->nodeid,
+                       &cr->mpi_comm_mygroup);
+        MPI_Comm_rank(cr->mpi_comm_mygroup,&cr->nodeid);
+    }
+#endif
+
+    if (fplog)
+    {
+        fprintf(fplog,"This is a %s only node\n\n",
+                (cr->duty & DUTY_PP) ? "particle-particle" : "PME-mesh");
+    }
+}
+
+void make_dd_communicators(FILE *fplog,t_commrec *cr,int dd_node_order)
+{
+    gmx_domdec_t *dd;
+    gmx_domdec_comm_t *comm;
+    int CartReorder;
+    
+    dd = cr->dd;
+    comm = dd->comm;
+    
+    copy_ivec(dd->nc,comm->ntot);
+    
+    comm->bCartesianPP = (dd_node_order == ddnoCARTESIAN);
+    comm->bCartesianPP_PME = FALSE;
+    
+    /* Reorder the nodes by default. This might change the MPI ranks.
+     * Real reordering is only supported on very few architectures,
+     * Blue Gene is one of them.
+     */
+    CartReorder = (getenv("GMX_NO_CART_REORDER") == NULL);
+    
+    if (cr->npmenodes > 0)
+    {
+        /* Split the communicator into a PP and PME part */
+        split_communicator(fplog,cr,dd_node_order,CartReorder);
+        if (comm->bCartesianPP_PME)
+        {
+            /* We (possibly) reordered the nodes in split_communicator,
+             * so it is no longer required in make_pp_communicator.
+             */
+            CartReorder = FALSE;
+        }
+    }
+    else
+    {
+        /* All nodes do PP and PME */
+#ifdef GMX_MPI    
+        /* We do not require separate communicators */
+        cr->mpi_comm_mygroup = cr->mpi_comm_mysim;
+#endif
+    }
+    
+    if (cr->duty & DUTY_PP)
+    {
+        /* Copy or make a new PP communicator */
+        make_pp_communicator(fplog,cr,CartReorder);
+    }
+    else
+    {
+        receive_ddindex2simnodeid(cr);
+    }
+    
+    if (!(cr->duty & DUTY_PME))
+    {
+        /* Set up the commnuication to our PME node */
+        dd->pme_nodeid = dd_simnode2pmenode(cr,cr->sim_nodeid);
+        dd->pme_receive_vir_ener = receive_vir_ener(cr);
+        if (debug)
+        {
+            fprintf(debug,"My pme_nodeid %d receive ener %d\n",
+                    dd->pme_nodeid,dd->pme_receive_vir_ener);
+        }
+    }
+    else
+    {
+        dd->pme_nodeid = -1;
+    }
+
+    if (DDMASTER(dd))
+    {
+        dd->ma = init_gmx_domdec_master_t(dd,
+                                          comm->cgs_gl.nr,
+                                          comm->cgs_gl.index[comm->cgs_gl.nr]);
+    }
+}
+
+static real *get_slb_frac(FILE *fplog,const char *dir,int nc,const char *size_string)
+{
+    real *slb_frac,tot;
+    int  i,n;
+    double dbl;
+    
+    slb_frac = NULL;
+    if (nc > 1 && size_string != NULL)
+    {
+        if (fplog)
+        {
+            fprintf(fplog,"Using static load balancing for the %s direction\n",
+                    dir);
+        }
+        snew(slb_frac,nc);
+        tot = 0;
+        for (i=0; i<nc; i++)
+        {
+            dbl = 0;
+            sscanf(size_string,"%lf%n",&dbl,&n);
+            if (dbl == 0)
+            {
+                gmx_fatal(FARGS,"Incorrect or not enough DD cell size entries for direction %s: '%s'",dir,size_string);
+            }
+            slb_frac[i] = dbl;
+            size_string += n;
+            tot += slb_frac[i];
+        }
+        /* Normalize */
+        if (fplog)
+        {
+            fprintf(fplog,"Relative cell sizes:");
+        }
+        for (i=0; i<nc; i++)
+        {
+            slb_frac[i] /= tot;
+            if (fplog)
+            {
+                fprintf(fplog," %5.3f",slb_frac[i]);
+            }
+        }
+        if (fplog)
+        {
+            fprintf(fplog,"\n");
+        }
+    }
+    
+    return slb_frac;
+}
+
+static int multi_body_bondeds_count(gmx_mtop_t *mtop)
+{
+    int n,nmol,ftype;
+    gmx_mtop_ilistloop_t iloop;
+    t_ilist *il;
+    
+    n = 0;
+    iloop = gmx_mtop_ilistloop_init(mtop);
+    while (gmx_mtop_ilistloop_next(iloop,&il,&nmol))
+    {
+        for(ftype=0; ftype<F_NRE; ftype++)
+        {
+            if ((interaction_function[ftype].flags & IF_BOND) &&
+                NRAL(ftype) >  2)
+            {
+                n += nmol*il[ftype].nr/(1 + NRAL(ftype));
+            }
+        }
+  }
+
+  return n;
+}
+
+static int dd_nst_env(FILE *fplog,const char *env_var,int def)
+{
+    char *val;
+    int  nst;
+    
+    nst = def;
+    val = getenv(env_var);
+    if (val)
+    {
+        if (sscanf(val,"%d",&nst) <= 0)
+        {
+            nst = 1;
+        }
+        if (fplog)
+        {
+            fprintf(fplog,"Found env.var. %s = %s, using value %d\n",
+                    env_var,val,nst);
+        }
+    }
+    
+    return nst;
+}
+
+static void dd_warning(t_commrec *cr,FILE *fplog,const char *warn_string)
+{
+    if (MASTER(cr))
+    {
+        fprintf(stderr,"\n%s\n",warn_string);
+    }
+    if (fplog)
+    {
+        fprintf(fplog,"\n%s\n",warn_string);
+    }
+}
+
+static void check_dd_restrictions(t_commrec *cr,gmx_domdec_t *dd,
+                                  t_inputrec *ir,FILE *fplog)
+{
+    if (ir->ePBC == epbcSCREW &&
+        (dd->nc[XX] == 1 || dd->nc[YY] > 1 || dd->nc[ZZ] > 1))
+    {
+        gmx_fatal(FARGS,"With pbc=%s can only do domain decomposition in the x-direction",epbc_names[ir->ePBC]);
+    }
+
+    if (ir->ns_type == ensSIMPLE)
+    {
+        gmx_fatal(FARGS,"Domain decomposition does not support simple neighbor searching, use grid searching or use particle decomposition");
+    }
+
+    if (ir->nstlist == 0)
+    {
+        gmx_fatal(FARGS,"Domain decomposition does not work with nstlist=0");
+    }
+
+    if (ir->comm_mode == ecmANGULAR && ir->ePBC != epbcNONE)
+    {
+        dd_warning(cr,fplog,"comm-mode angular will give incorrect results when the comm group partially crosses a periodic boundary");
+    }
+}
+
+static real average_cellsize_min(gmx_domdec_t *dd,gmx_ddbox_t *ddbox)
+{
+    int  di,d;
+    real r;
+
+    r = ddbox->box_size[XX];
+    for(di=0; di<dd->ndim; di++)
+    {
+        d = dd->dim[di];
+        /* Check using the initial average cell size */
+        r = min(r,ddbox->box_size[d]*ddbox->skew_fac[d]/dd->nc[d]);
+    }
+
+    return r;
+}
+
+static int check_dlb_support(FILE *fplog,t_commrec *cr,
+                             const char *dlb_opt,gmx_bool bRecordLoad,
+                             unsigned long Flags,t_inputrec *ir)
+{
+    gmx_domdec_t *dd;
+    int  eDLB=-1;
+    char buf[STRLEN];
+
+    switch (dlb_opt[0])
+    {
+    case 'a': eDLB = edlbAUTO; break;
+    case 'n': eDLB = edlbNO;   break;
+    case 'y': eDLB = edlbYES;  break;
+    default: gmx_incons("Unknown dlb_opt");
+    }
+
+    if (Flags & MD_RERUN)
+    {
+        return edlbNO;
+    }
+
+    if (!EI_DYNAMICS(ir->eI))
+    {
+        if (eDLB == edlbYES)
+        {
+            sprintf(buf,"NOTE: dynamic load balancing is only supported with dynamics, not with integrator '%s'\n",EI(ir->eI));
+            dd_warning(cr,fplog,buf);
+        }
+            
+        return edlbNO;
+    }
+
+    if (!bRecordLoad)
+    {
+        dd_warning(cr,fplog,"NOTE: Cycle counting is not supported on this architecture, will not use dynamic load balancing\n");
+
+        return edlbNO;
+    }
+
+    if (Flags & MD_REPRODUCIBLE)
+    {
+        switch (eDLB)
+        {
+                       case edlbNO: 
+                               break;
+                       case edlbAUTO:
+                               dd_warning(cr,fplog,"NOTE: reproducability requested, will not use dynamic load balancing\n");
+                               eDLB = edlbNO;
+                               break;
+                       case edlbYES:
+                               dd_warning(cr,fplog,"WARNING: reproducability requested with dynamic load balancing, the simulation will NOT be binary reproducable\n");
+                               break;
+                       default:
+                               gmx_fatal(FARGS,"Death horror: undefined case (%d) for load balancing choice",eDLB);
+                               break;
+        }
+    }
+
+    return eDLB;
+}
+
+static void set_dd_dim(FILE *fplog,gmx_domdec_t *dd)
+{
+    int dim;
+
+    dd->ndim = 0;
+    if (getenv("GMX_DD_ORDER_ZYX") != NULL)
+    {
+        /* Decomposition order z,y,x */
+        if (fplog)
+        {
+            fprintf(fplog,"Using domain decomposition order z, y, x\n");
+        }
+        for(dim=DIM-1; dim>=0; dim--)
+        {
+            if (dd->nc[dim] > 1)
+            {
+                dd->dim[dd->ndim++] = dim;
+            }
+        }
+    }
+    else
+    {
+        /* Decomposition order x,y,z */
+        for(dim=0; dim<DIM; dim++)
+        {
+            if (dd->nc[dim] > 1)
+            {
+                dd->dim[dd->ndim++] = dim;
+            }
+        }
+    }
+}
+
+static gmx_domdec_comm_t *init_dd_comm()
+{
+    gmx_domdec_comm_t *comm;
+    int  i;
+
+    snew(comm,1);
+    snew(comm->cggl_flag,DIM*2);
+    snew(comm->cgcm_state,DIM*2);
+    for(i=0; i<DIM*2; i++)
+    {
+        comm->cggl_flag_nalloc[i]  = 0;
+        comm->cgcm_state_nalloc[i] = 0;
+    }
+    
+    comm->nalloc_int = 0;
+    comm->buf_int    = NULL;
+
+    vec_rvec_init(&comm->vbuf);
+
+    comm->n_load_have    = 0;
+    comm->n_load_collect = 0;
+
+    for(i=0; i<ddnatNR-ddnatZONE; i++)
+    {
+        comm->sum_nat[i] = 0;
+    }
+    comm->ndecomp = 0;
+    comm->nload   = 0;
+    comm->load_step = 0;
+    comm->load_sum  = 0;
+    comm->load_max  = 0;
+    clear_ivec(comm->load_lim);
+    comm->load_mdf  = 0;
+    comm->load_pme  = 0;
+
+    return comm;
+}
+
+gmx_domdec_t *init_domain_decomposition(FILE *fplog,t_commrec *cr,
+                                        unsigned long Flags,
+                                        ivec nc,
+                                        real comm_distance_min,real rconstr,
+                                        const char *dlb_opt,real dlb_scale,
+                                        const char *sizex,const char *sizey,const char *sizez,
+                                        gmx_mtop_t *mtop,t_inputrec *ir,
+                                        matrix box,rvec *x,
+                                        gmx_ddbox_t *ddbox,
+                                        int *npme_x,int *npme_y)
+{
+    gmx_domdec_t *dd;
+    gmx_domdec_comm_t *comm;
+    int  recload;
+    int  d,i,j;
+    real r_2b,r_mb,r_bonded=-1,r_bonded_limit=-1,limit,acs;
+    gmx_bool bC;
+    char buf[STRLEN];
+    
+    if (fplog)
+    {
+        fprintf(fplog,
+                "\nInitializing Domain Decomposition on %d nodes\n",cr->nnodes);
+    }
+    
+    snew(dd,1);
+
+    dd->comm = init_dd_comm();
+    comm = dd->comm;
+    snew(comm->cggl_flag,DIM*2);
+    snew(comm->cgcm_state,DIM*2);
+
+    dd->npbcdim   = ePBC2npbcdim(ir->ePBC);
+    dd->bScrewPBC = (ir->ePBC == epbcSCREW);
+    
+    dd->bSendRecv2      = dd_nst_env(fplog,"GMX_DD_SENDRECV2",0);
+    comm->eFlop         = dd_nst_env(fplog,"GMX_DLB_FLOP",0);
+    recload             = dd_nst_env(fplog,"GMX_DD_LOAD",1);
+    comm->nstSortCG     = dd_nst_env(fplog,"GMX_DD_SORT",1);
+    comm->nstDDDump     = dd_nst_env(fplog,"GMX_DD_DUMP",0);
+    comm->nstDDDumpGrid = dd_nst_env(fplog,"GMX_DD_DUMP_GRID",0);
+    comm->DD_debug      = dd_nst_env(fplog,"GMX_DD_DEBUG",0);
+
+    dd->pme_recv_f_alloc = 0;
+    dd->pme_recv_f_buf = NULL;
+
+    if (dd->bSendRecv2 && fplog)
+    {
+        fprintf(fplog,"Will use two sequential MPI_Sendrecv calls instead of two simultaneous non-blocking MPI_Irecv and MPI_Isend pairs for constraint and vsite communication\n");
+    }
+    if (comm->eFlop)
+    {
+        if (fplog)
+        {
+            fprintf(fplog,"Will load balance based on FLOP count\n");
+        }
+        if (comm->eFlop > 1)
+        {
+            srand(1+cr->nodeid);
+        }
+        comm->bRecordLoad = TRUE;
+    }
+    else
+    {
+        comm->bRecordLoad = (wallcycle_have_counter() && recload > 0);
+                             
+    }
+    
+    comm->eDLB = check_dlb_support(fplog,cr,dlb_opt,comm->bRecordLoad,Flags,ir);
+    
+    comm->bDynLoadBal = (comm->eDLB == edlbYES);
+    if (fplog)
+    {
+        fprintf(fplog,"Dynamic load balancing: %s\n",edlb_names[comm->eDLB]);
+    }
+    dd->bGridJump = comm->bDynLoadBal;
+    
+    if (comm->nstSortCG)
+    {
+        if (fplog)
+        {
+            if (comm->nstSortCG == 1)
+            {
+                fprintf(fplog,"Will sort the charge groups at every domain (re)decomposition\n");
+            }
+            else
+            {
+                fprintf(fplog,"Will sort the charge groups every %d steps\n",
+                        comm->nstSortCG);
+            }
+        }
+        snew(comm->sort,1);
+    }
+    else
+    {
+        if (fplog)
+        {
+            fprintf(fplog,"Will not sort the charge groups\n");
+        }
+    }
+    
+    comm->bInterCGBondeds = (ncg_mtop(mtop) > mtop->mols.nr);
+    if (comm->bInterCGBondeds)
+    {
+        comm->bInterCGMultiBody = (multi_body_bondeds_count(mtop) > 0);
+    }
+    else
+    {
+        comm->bInterCGMultiBody = FALSE;
+    }
+    
+    dd->bInterCGcons = inter_charge_group_constraints(mtop);
+
+    if (ir->rlistlong == 0)
+    {
+        /* Set the cut-off to some very large value,
+         * so we don't need if statements everywhere in the code.
+         * We use sqrt, since the cut-off is squared in some places.
+         */
+        comm->cutoff   = GMX_CUTOFF_INF;
+    }
+    else
+    {
+        comm->cutoff   = ir->rlistlong;
+    }
+    comm->cutoff_mbody = 0;
+    
+    comm->cellsize_limit = 0;
+    comm->bBondComm = FALSE;
+
+    if (comm->bInterCGBondeds)
+    {
+        if (comm_distance_min > 0)
+        {
+            comm->cutoff_mbody = comm_distance_min;
+            if (Flags & MD_DDBONDCOMM)
+            {
+                comm->bBondComm = (comm->cutoff_mbody > comm->cutoff);
+            }
+            else
+            {
+                comm->cutoff = max(comm->cutoff,comm->cutoff_mbody);
+            }
+            r_bonded_limit = comm->cutoff_mbody;
+        }
+        else if (ir->bPeriodicMols)
+        {
+            /* Can not easily determine the required cut-off */
+            dd_warning(cr,fplog,"NOTE: Periodic molecules: can not easily determine the required minimum bonded cut-off, using half the non-bonded cut-off\n");
+            comm->cutoff_mbody = comm->cutoff/2;
+            r_bonded_limit = comm->cutoff_mbody;
+        }
+        else
+        {
+            if (MASTER(cr))
+            {
+                dd_bonded_cg_distance(fplog,dd,mtop,ir,x,box,
+                                      Flags & MD_DDBONDCHECK,&r_2b,&r_mb);
+            }
+            gmx_bcast(sizeof(r_2b),&r_2b,cr);
+            gmx_bcast(sizeof(r_mb),&r_mb,cr);
+
+            /* We use an initial margin of 10% for the minimum cell size,
+             * except when we are just below the non-bonded cut-off.
+             */
+            if (Flags & MD_DDBONDCOMM)
+            {
+                if (max(r_2b,r_mb) > comm->cutoff)
+                {
+                    r_bonded       = max(r_2b,r_mb);
+                    r_bonded_limit = 1.1*r_bonded;
+                    comm->bBondComm = TRUE;
+                }
+                else
+                {
+                    r_bonded       = r_mb;
+                    r_bonded_limit = min(1.1*r_bonded,comm->cutoff);
+                }
+                /* We determine cutoff_mbody later */
+            }
+            else
+            {
+                /* No special bonded communication,
+                 * simply increase the DD cut-off.
+                 */
+                r_bonded_limit     = 1.1*max(r_2b,r_mb);
+                comm->cutoff_mbody = r_bonded_limit;
+                comm->cutoff       = max(comm->cutoff,comm->cutoff_mbody);
+            }
+        }
+        comm->cellsize_limit = max(comm->cellsize_limit,r_bonded_limit);
+        if (fplog)
+        {
+            fprintf(fplog,
+                    "Minimum cell size due to bonded interactions: %.3f nm\n",
+                    comm->cellsize_limit);
+        }
+    }
+
+    if (dd->bInterCGcons && rconstr <= 0)
+    {
+        /* There is a cell size limit due to the constraints (P-LINCS) */
+        rconstr = constr_r_max(fplog,mtop,ir);
+        if (fplog)
+        {
+            fprintf(fplog,
+                    "Estimated maximum distance required for P-LINCS: %.3f nm\n",
+                    rconstr);
+            if (rconstr > comm->cellsize_limit)
+            {
+                fprintf(fplog,"This distance will limit the DD cell size, you can override this with -rcon\n");
+            }
+        }
+    }
+    else if (rconstr > 0 && fplog)
+    {
+        /* Here we do not check for dd->bInterCGcons,
+         * because one can also set a cell size limit for virtual sites only
+         * and at this point we don't know yet if there are intercg v-sites.
+         */
+        fprintf(fplog,
+                "User supplied maximum distance required for P-LINCS: %.3f nm\n",
+                rconstr);
+    }
+    comm->cellsize_limit = max(comm->cellsize_limit,rconstr);
+
+    comm->cgs_gl = gmx_mtop_global_cgs(mtop);
+
+    if (nc[XX] > 0)
+    {
+        copy_ivec(nc,dd->nc);
+        set_dd_dim(fplog,dd);
+        set_ddbox_cr(cr,&dd->nc,ir,box,&comm->cgs_gl,x,ddbox);
+
+        if (cr->npmenodes == -1)
+        {
+            cr->npmenodes = 0;
+        }
+        acs = average_cellsize_min(dd,ddbox);
+        if (acs < comm->cellsize_limit)
+        {
+            if (fplog)
+            {
+                fprintf(fplog,"ERROR: The initial cell size (%f) is smaller than the cell size limit (%f)\n",acs,comm->cellsize_limit);
+            }
+            gmx_fatal_collective(FARGS,cr,NULL,
+                                 "The initial cell size (%f) is smaller than the cell size limit (%f), change options -dd, -rdd or -rcon, see the log file for details",
+                                 acs,comm->cellsize_limit);
+        }
+    }
+    else
+    {
+        set_ddbox_cr(cr,NULL,ir,box,&comm->cgs_gl,x,ddbox);
+
+        /* We need to choose the optimal DD grid and possibly PME nodes */
+        limit = dd_choose_grid(fplog,cr,dd,ir,mtop,box,ddbox,
+                               comm->eDLB!=edlbNO,dlb_scale,
+                               comm->cellsize_limit,comm->cutoff,
+                               comm->bInterCGBondeds,comm->bInterCGMultiBody);
+        
+        if (dd->nc[XX] == 0)
+        {
+            bC = (dd->bInterCGcons && rconstr > r_bonded_limit);
+            sprintf(buf,"Change the number of nodes or mdrun option %s%s%s",
+                    !bC ? "-rdd" : "-rcon",
+                    comm->eDLB!=edlbNO ? " or -dds" : "",
+                    bC ? " or your LINCS settings" : "");
+
+            gmx_fatal_collective(FARGS,cr,NULL,
+                                 "There is no domain decomposition for %d nodes that is compatible with the given box and a minimum cell size of %g nm\n"
+                                 "%s\n"
+                                 "Look in the log file for details on the domain decomposition",
+                                 cr->nnodes-cr->npmenodes,limit,buf);
+        }
+        set_dd_dim(fplog,dd);
+    }
+
+    if (fplog)
+    {
+        fprintf(fplog,
+                "Domain decomposition grid %d x %d x %d, separate PME nodes %d\n",
+                dd->nc[XX],dd->nc[YY],dd->nc[ZZ],cr->npmenodes);
+    }
+    
+    dd->nnodes = dd->nc[XX]*dd->nc[YY]*dd->nc[ZZ];
+    if (cr->nnodes - dd->nnodes != cr->npmenodes)
+    {
+        gmx_fatal_collective(FARGS,cr,NULL,
+                             "The size of the domain decomposition grid (%d) does not match the number of nodes (%d). The total number of nodes is %d",
+                             dd->nnodes,cr->nnodes - cr->npmenodes,cr->nnodes);
+    }
+    if (cr->npmenodes > dd->nnodes)
+    {
+        gmx_fatal_collective(FARGS,cr,NULL,
+                             "The number of separate PME node (%d) is larger than the number of PP nodes (%d), this is not supported.",cr->npmenodes,dd->nnodes);
+    }
+    if (cr->npmenodes > 0)
+    {
+        comm->npmenodes = cr->npmenodes;
+    }
+    else
+    {
+        comm->npmenodes = dd->nnodes;
+    }
+
+    if (EEL_PME(ir->coulombtype))
+    {
+        /* The following choices should match those
+         * in comm_cost_est in domdec_setup.c.
+         * Note that here the checks have to take into account
+         * that the decomposition might occur in a different order than xyz
+         * (for instance through the env.var. GMX_DD_ORDER_ZYX),
+         * in which case they will not match those in comm_cost_est,
+         * but since that is mainly for testing purposes that's fine.
+         */
+        if (dd->ndim >= 2 && dd->dim[0] == XX && dd->dim[1] == YY &&
+            comm->npmenodes > dd->nc[XX] && comm->npmenodes % dd->nc[XX] == 0 &&
+            getenv("GMX_PMEONEDD") == NULL)
+        {
+            comm->npmedecompdim = 2;
+            comm->npmenodes_x   = dd->nc[XX];
+            comm->npmenodes_y   = comm->npmenodes/comm->npmenodes_x;
+        }
+        else
+        {
+            /* In case nc is 1 in both x and y we could still choose to
+             * decompose pme in y instead of x, but we use x for simplicity.
+             */
+            comm->npmedecompdim = 1;
+            if (dd->dim[0] == YY)
+            {
+                comm->npmenodes_x = 1;
+                comm->npmenodes_y = comm->npmenodes;
+            }
+            else
+            {
+                comm->npmenodes_x = comm->npmenodes;
+                comm->npmenodes_y = 1;
+            }
+        }    
+        if (fplog)
+        {
+            fprintf(fplog,"PME domain decomposition: %d x %d x %d\n",
+                    comm->npmenodes_x,comm->npmenodes_y,1);
+        }
+    }
+    else
+    {
+        comm->npmedecompdim = 0;
+        comm->npmenodes_x   = 0;
+        comm->npmenodes_y   = 0;
+    }
+    
+    /* Technically we don't need both of these,
+     * but it simplifies code not having to recalculate it.
+     */
+    *npme_x = comm->npmenodes_x;
+    *npme_y = comm->npmenodes_y;
+        
+    snew(comm->slb_frac,DIM);
+    if (comm->eDLB == edlbNO)
+    {
+        comm->slb_frac[XX] = get_slb_frac(fplog,"x",dd->nc[XX],sizex);
+        comm->slb_frac[YY] = get_slb_frac(fplog,"y",dd->nc[YY],sizey);
+        comm->slb_frac[ZZ] = get_slb_frac(fplog,"z",dd->nc[ZZ],sizez);
+    }
+
+    if (comm->bInterCGBondeds && comm->cutoff_mbody == 0)
+    {
+        if (comm->bBondComm || comm->eDLB != edlbNO)
+        {
+            /* Set the bonded communication distance to halfway
+             * the minimum and the maximum,
+             * since the extra communication cost is nearly zero.
+             */
+            acs = average_cellsize_min(dd,ddbox);
+            comm->cutoff_mbody = 0.5*(r_bonded + acs);
+            if (comm->eDLB != edlbNO)
+            {
+                /* Check if this does not limit the scaling */
+                comm->cutoff_mbody = min(comm->cutoff_mbody,dlb_scale*acs);
+            }
+            if (!comm->bBondComm)
+            {
+                /* Without bBondComm do not go beyond the n.b. cut-off */
+                comm->cutoff_mbody = min(comm->cutoff_mbody,comm->cutoff);
+                if (comm->cellsize_limit >= comm->cutoff)
+                {
+                    /* We don't loose a lot of efficieny
+                     * when increasing it to the n.b. cut-off.
+                     * It can even be slightly faster, because we need
+                     * less checks for the communication setup.
+                     */
+                    comm->cutoff_mbody = comm->cutoff;
+                }
+            }
+            /* Check if we did not end up below our original limit */
+            comm->cutoff_mbody = max(comm->cutoff_mbody,r_bonded_limit);
+
+            if (comm->cutoff_mbody > comm->cellsize_limit)
+            {
+                comm->cellsize_limit = comm->cutoff_mbody;
+            }
+        }
+        /* Without DLB and cutoff_mbody<cutoff, cutoff_mbody is dynamic */
+    }
+
+    if (debug)
+    {
+        fprintf(debug,"Bonded atom communication beyond the cut-off: %d\n"
+                "cellsize limit %f\n",
+                comm->bBondComm,comm->cellsize_limit);
+    }
+    
+    if (MASTER(cr))
+    {
+        check_dd_restrictions(cr,dd,ir,fplog);
+    }
+
+    comm->partition_step = INT_MIN;
+    dd->ddp_count = 0;
+
+    clear_dd_cycle_counts(dd);
+
+    return dd;
+}
+
+static void set_dlb_limits(gmx_domdec_t *dd)
+
+{
+    int d;
+
+    for(d=0; d<dd->ndim; d++)
+    {
+        dd->comm->cd[d].np = dd->comm->cd[d].np_dlb;
+        dd->comm->cellsize_min[dd->dim[d]] =
+            dd->comm->cellsize_min_dlb[dd->dim[d]];
+    }
+}
+
+
+static void turn_on_dlb(FILE *fplog,t_commrec *cr,gmx_large_int_t step)
+{
+    gmx_domdec_t *dd;
+    gmx_domdec_comm_t *comm;
+    real cellsize_min;
+    int  d,nc,i;
+    char buf[STRLEN];
+    
+    dd = cr->dd;
+    comm = dd->comm;
+    
+    if (fplog)
+    {
+        fprintf(fplog,"At step %s the performance loss due to force load imbalance is %.1f %%\n",gmx_step_str(step,buf),dd_force_imb_perf_loss(dd)*100);
+    }
+
+    cellsize_min = comm->cellsize_min[dd->dim[0]];
+    for(d=1; d<dd->ndim; d++)
+    {
+        cellsize_min = min(cellsize_min,comm->cellsize_min[dd->dim[d]]);
+    }
+
+    if (cellsize_min < comm->cellsize_limit*1.05)
+    {
+        dd_warning(cr,fplog,"NOTE: the minimum cell size is smaller than 1.05 times the cell size limit, will not turn on dynamic load balancing\n");
+
+        /* Change DLB from "auto" to "no". */
+        comm->eDLB = edlbNO;
+
+        return;
+    }
+
+    dd_warning(cr,fplog,"NOTE: Turning on dynamic load balancing\n");
+    comm->bDynLoadBal = TRUE;
+    dd->bGridJump = TRUE;
+    
+    set_dlb_limits(dd);
+
+    /* We can set the required cell size info here,
+     * so we do not need to communicate this.
+     * The grid is completely uniform.
+     */
+    for(d=0; d<dd->ndim; d++)
+    {
+        if (comm->root[d])
+        {
+            comm->load[d].sum_m = comm->load[d].sum;
+
+            nc = dd->nc[dd->dim[d]];
+            for(i=0; i<nc; i++)
+            {
+                comm->root[d]->cell_f[i]    = i/(real)nc;
+                if (d > 0)
+                {
+                    comm->root[d]->cell_f_max0[i] =  i   /(real)nc;
+                    comm->root[d]->cell_f_min1[i] = (i+1)/(real)nc;
+                }
+            }
+            comm->root[d]->cell_f[nc] = 1.0;
+        }
+    }
+}
+
+static char *init_bLocalCG(gmx_mtop_t *mtop)
+{
+    int  ncg,cg;
+    char *bLocalCG;
+    
+    ncg = ncg_mtop(mtop);
+    snew(bLocalCG,ncg);
+    for(cg=0; cg<ncg; cg++)
+    {
+        bLocalCG[cg] = FALSE;
+    }
+
+    return bLocalCG;
+}
+
+void dd_init_bondeds(FILE *fplog,
+                     gmx_domdec_t *dd,gmx_mtop_t *mtop,
+                     gmx_vsite_t *vsite,gmx_constr_t constr,
+                     t_inputrec *ir,gmx_bool bBCheck,cginfo_mb_t *cginfo_mb)
+{
+    gmx_domdec_comm_t *comm;
+    gmx_bool bBondComm;
+    int  d;
+
+    dd_make_reverse_top(fplog,dd,mtop,vsite,constr,ir,bBCheck);
+
+    comm = dd->comm;
+
+    if (comm->bBondComm)
+    {
+        /* Communicate atoms beyond the cut-off for bonded interactions */
+        comm = dd->comm;
+
+        comm->cglink = make_charge_group_links(mtop,dd,cginfo_mb);
+
+        comm->bLocalCG = init_bLocalCG(mtop);
+    }
+    else
+    {
+        /* Only communicate atoms based on cut-off */
+        comm->cglink   = NULL;
+        comm->bLocalCG = NULL;
+    }
+}
+
+static void print_dd_settings(FILE *fplog,gmx_domdec_t *dd,
+                              t_inputrec *ir,
+                              gmx_bool bDynLoadBal,real dlb_scale,
+                              gmx_ddbox_t *ddbox)
+{
+    gmx_domdec_comm_t *comm;
+    int  d;
+    ivec np;
+    real limit,shrink;
+    char buf[64];
+
+    if (fplog == NULL)
+    {
+        return;
+    }
+
+    comm = dd->comm;
+
+    if (bDynLoadBal)
+    {
+        fprintf(fplog,"The maximum number of communication pulses is:");
+        for(d=0; d<dd->ndim; d++)
+        {
+            fprintf(fplog," %c %d",dim2char(dd->dim[d]),comm->cd[d].np_dlb);
+        }
+        fprintf(fplog,"\n");
+        fprintf(fplog,"The minimum size for domain decomposition cells is %.3f nm\n",comm->cellsize_limit);
+        fprintf(fplog,"The requested allowed shrink of DD cells (option -dds) is: %.2f\n",dlb_scale);
+        fprintf(fplog,"The allowed shrink of domain decomposition cells is:");
+        for(d=0; d<DIM; d++)
+        {
+            if (dd->nc[d] > 1)
+            {
+                if (d >= ddbox->npbcdim && dd->nc[d] == 2)
+                {
+                    shrink = 0;
+                }
+                else
+                {
+                    shrink =
+                        comm->cellsize_min_dlb[d]/
+                        (ddbox->box_size[d]*ddbox->skew_fac[d]/dd->nc[d]);
+                }
+                fprintf(fplog," %c %.2f",dim2char(d),shrink);
+            }
+        }
+        fprintf(fplog,"\n");
+    }
+    else
+    {
+        set_dd_cell_sizes_slb(dd,ddbox,FALSE,np);
+        fprintf(fplog,"The initial number of communication pulses is:");
+        for(d=0; d<dd->ndim; d++)
+        {
+            fprintf(fplog," %c %d",dim2char(dd->dim[d]),np[dd->dim[d]]);
+        }
+        fprintf(fplog,"\n");
+        fprintf(fplog,"The initial domain decomposition cell size is:");
+        for(d=0; d<DIM; d++) {
+            if (dd->nc[d] > 1)
+            {
+                fprintf(fplog," %c %.2f nm",
+                        dim2char(d),dd->comm->cellsize_min[d]);
+            }
+        }
+        fprintf(fplog,"\n\n");
+    }
+    
+    if (comm->bInterCGBondeds || dd->vsite_comm || dd->constraint_comm)
+    {
+        fprintf(fplog,"The maximum allowed distance for charge groups involved in interactions is:\n");
+        fprintf(fplog,"%40s  %-7s %6.3f nm\n",
+                "non-bonded interactions","",comm->cutoff);
+
+        if (bDynLoadBal)
+        {
+            limit = dd->comm->cellsize_limit;
+        }
+        else
+        {
+            if (dynamic_dd_box(ddbox,ir))
+            {
+                fprintf(fplog,"(the following are initial values, they could change due to box deformation)\n");
+            }
+            limit = dd->comm->cellsize_min[XX];
+            for(d=1; d<DIM; d++)
+            {
+                limit = min(limit,dd->comm->cellsize_min[d]);
+            }
+        }
+
+        if (comm->bInterCGBondeds)
+        {
+            fprintf(fplog,"%40s  %-7s %6.3f nm\n",
+                    "two-body bonded interactions","(-rdd)",
+                    max(comm->cutoff,comm->cutoff_mbody));
+            fprintf(fplog,"%40s  %-7s %6.3f nm\n",
+                    "multi-body bonded interactions","(-rdd)",
+                    (comm->bBondComm || dd->bGridJump) ? comm->cutoff_mbody : min(comm->cutoff,limit));
+        }
+        if (dd->vsite_comm)
+        {
+            fprintf(fplog,"%40s  %-7s %6.3f nm\n",
+                    "virtual site constructions","(-rcon)",limit);
+        }
+        if (dd->constraint_comm)
+        {
+            sprintf(buf,"atoms separated by up to %d constraints",
+                    1+ir->nProjOrder);
+            fprintf(fplog,"%40s  %-7s %6.3f nm\n",
+                    buf,"(-rcon)",limit);
+        }
+        fprintf(fplog,"\n");
+    }
+    
+    fflush(fplog);
+}
+
+void set_dd_parameters(FILE *fplog,gmx_domdec_t *dd,real dlb_scale,
+                       t_inputrec *ir,t_forcerec *fr,
+                       gmx_ddbox_t *ddbox)
+{
+    gmx_domdec_comm_t *comm;
+    int  d,dim,npulse,npulse_d_max,npulse_d;
+    gmx_bool bNoCutOff;
+    int  natoms_tot;
+    real vol_frac;
+
+    comm = dd->comm;
+
+    bNoCutOff = (ir->rvdw == 0 || ir->rcoulomb == 0);
+
+    if (EEL_PME(ir->coulombtype))
+    {
+        init_ddpme(dd,&comm->ddpme[0],0);
+        if (comm->npmedecompdim >= 2)
+        {
+            init_ddpme(dd,&comm->ddpme[1],1);
+        }
+    }
+    else
+    {
+        comm->npmenodes = 0;
+        if (dd->pme_nodeid >= 0)
+        {
+            gmx_fatal_collective(FARGS,NULL,dd,
+                                 "Can not have separate PME nodes without PME electrostatics");
+        }
+    }
+    
+    /* If each molecule is a single charge group
+     * or we use domain decomposition for each periodic dimension,
+     * we do not need to take pbc into account for the bonded interactions.
+     */
+    if (fr->ePBC == epbcNONE || !comm->bInterCGBondeds ||
+        (dd->nc[XX]>1 && dd->nc[YY]>1 && (dd->nc[ZZ]>1 || fr->ePBC==epbcXY)))
+    {
+        fr->bMolPBC = FALSE;
+    }
+    else
+    {
+        fr->bMolPBC = TRUE;
+    }
+        
+    if (debug)
+    {
+        fprintf(debug,"The DD cut-off is %f\n",comm->cutoff);
+    }
+    if (comm->eDLB != edlbNO)
+    {
+        /* Determine the maximum number of comm. pulses in one dimension */
+        
+        comm->cellsize_limit = max(comm->cellsize_limit,comm->cutoff_mbody);
+        
+        /* Determine the maximum required number of grid pulses */
+        if (comm->cellsize_limit >= comm->cutoff)
+        {
+            /* Only a single pulse is required */
+            npulse = 1;
+        }
+        else if (!bNoCutOff && comm->cellsize_limit > 0)
+        {
+            /* We round down slightly here to avoid overhead due to the latency
+             * of extra communication calls when the cut-off
+             * would be only slightly longer than the cell size.
+             * Later cellsize_limit is redetermined,
+             * so we can not miss interactions due to this rounding.
+             */
+            npulse = (int)(0.96 + comm->cutoff/comm->cellsize_limit);
+        }
+        else
+        {
+            /* There is no cell size limit */
+            npulse = max(dd->nc[XX]-1,max(dd->nc[YY]-1,dd->nc[ZZ]-1));
+        }
+
+        if (!bNoCutOff && npulse > 1)
+        {
+            /* See if we can do with less pulses, based on dlb_scale */
+            npulse_d_max = 0;
+            for(d=0; d<dd->ndim; d++)
+            {
+                dim = dd->dim[d];
+                npulse_d = (int)(1 + dd->nc[dim]*comm->cutoff
+                                 /(ddbox->box_size[dim]*ddbox->skew_fac[dim]*dlb_scale));
+                npulse_d_max = max(npulse_d_max,npulse_d);
+            }
+            npulse = min(npulse,npulse_d_max);
+        }
+        
+        /* This env var can override npulse */
+        d = dd_nst_env(fplog,"GMX_DD_NPULSE",0);
+        if (d > 0)
+        {
+            npulse = d;
+        }
+
+        comm->maxpulse = 1;
+        comm->bVacDLBNoLimit = (ir->ePBC == epbcNONE);
+        for(d=0; d<dd->ndim; d++)
+        {
+            comm->cd[d].np_dlb = min(npulse,dd->nc[dd->dim[d]]-1);
+            comm->cd[d].np_nalloc = comm->cd[d].np_dlb;
+            snew(comm->cd[d].ind,comm->cd[d].np_nalloc);
+            comm->maxpulse = max(comm->maxpulse,comm->cd[d].np_dlb);
+            if (comm->cd[d].np_dlb < dd->nc[dd->dim[d]]-1)
+            {
+                comm->bVacDLBNoLimit = FALSE;
+            }
+        }
+        
+        /* cellsize_limit is set for LINCS in init_domain_decomposition */
+        if (!comm->bVacDLBNoLimit)
+        {
+            comm->cellsize_limit = max(comm->cellsize_limit,
+                                       comm->cutoff/comm->maxpulse);
+        }
+        comm->cellsize_limit = max(comm->cellsize_limit,comm->cutoff_mbody);
+        /* Set the minimum cell size for each DD dimension */
+        for(d=0; d<dd->ndim; d++)
+        {
+            if (comm->bVacDLBNoLimit ||
+                comm->cd[d].np_dlb*comm->cellsize_limit >= comm->cutoff)
+            {
+                comm->cellsize_min_dlb[dd->dim[d]] = comm->cellsize_limit;
+            }
+            else
+            {
+                comm->cellsize_min_dlb[dd->dim[d]] =
+                    comm->cutoff/comm->cd[d].np_dlb;
+            }
+        }
+        if (comm->cutoff_mbody <= 0)
+        {
+            comm->cutoff_mbody = min(comm->cutoff,comm->cellsize_limit);
+        }
+        if (comm->bDynLoadBal)
+        {
+            set_dlb_limits(dd);
+        }
+    }
+    
+    print_dd_settings(fplog,dd,ir,comm->bDynLoadBal,dlb_scale,ddbox);
+    if (comm->eDLB == edlbAUTO)
+    {
+        if (fplog)
+        {
+            fprintf(fplog,"When dynamic load balancing gets turned on, these settings will change to:\n");
+        }
+        print_dd_settings(fplog,dd,ir,TRUE,dlb_scale,ddbox);
+    }
+
+    if (ir->ePBC == epbcNONE)
+    {
+        vol_frac = 1 - 1/(double)dd->nnodes;
+    }
+    else
+    {
+        vol_frac =
+            (1 + comm_box_frac(dd->nc,comm->cutoff,ddbox))/(double)dd->nnodes;
+    }
+    if (debug)
+    {
+        fprintf(debug,"Volume fraction for all DD zones: %f\n",vol_frac);
+    }
+    natoms_tot = comm->cgs_gl.index[comm->cgs_gl.nr];
+   
+    dd->ga2la = ga2la_init(natoms_tot,vol_frac*natoms_tot);
+}
+
+static void merge_cg_buffers(int ncell,
+                             gmx_domdec_comm_dim_t *cd, int pulse,
+                             int  *ncg_cell,
+                             int  *index_gl, int  *recv_i,
+                             rvec *cg_cm,    rvec *recv_vr,
+                             int *cgindex,
+                             cginfo_mb_t *cginfo_mb,int *cginfo)
+{
+    gmx_domdec_ind_t *ind,*ind_p;
+    int p,cell,c,cg,cg0,cg1,cg_gl,nat;
+    int shift,shift_at;
+    
+    ind = &cd->ind[pulse];
+    
+    /* First correct the already stored data */
+    shift = ind->nrecv[ncell];
+    for(cell=ncell-1; cell>=0; cell--)
+    {
+        shift -= ind->nrecv[cell];
+        if (shift > 0)
+        {
+            /* Move the cg's present from previous grid pulses */
+            cg0 = ncg_cell[ncell+cell];
+            cg1 = ncg_cell[ncell+cell+1];
+            cgindex[cg1+shift] = cgindex[cg1];
+            for(cg=cg1-1; cg>=cg0; cg--)
+            {
+                index_gl[cg+shift] = index_gl[cg];
+                copy_rvec(cg_cm[cg],cg_cm[cg+shift]);
+                cgindex[cg+shift] = cgindex[cg];
+                cginfo[cg+shift] = cginfo[cg];
+            }
+            /* Correct the already stored send indices for the shift */
+            for(p=1; p<=pulse; p++)
+            {
+                ind_p = &cd->ind[p];
+                cg0 = 0;
+                for(c=0; c<cell; c++)
+                {
+                    cg0 += ind_p->nsend[c];
+                }
+                cg1 = cg0 + ind_p->nsend[cell];
+                for(cg=cg0; cg<cg1; cg++)
+                {
+                    ind_p->index[cg] += shift;
+                }
+            }
+        }
+    }
+
+    /* Merge in the communicated buffers */
+    shift = 0;
+    shift_at = 0;
+    cg0 = 0;
+    for(cell=0; cell<ncell; cell++)
+    {
+        cg1 = ncg_cell[ncell+cell+1] + shift;
+        if (shift_at > 0)
+        {
+            /* Correct the old cg indices */
+            for(cg=ncg_cell[ncell+cell]; cg<cg1; cg++)
+            {
+                cgindex[cg+1] += shift_at;
+            }
+        }
+        for(cg=0; cg<ind->nrecv[cell]; cg++)
+        {
+            /* Copy this charge group from the buffer */
+            index_gl[cg1] = recv_i[cg0];
+            copy_rvec(recv_vr[cg0],cg_cm[cg1]);
+            /* Add it to the cgindex */
+            cg_gl = index_gl[cg1];
+            cginfo[cg1] = ddcginfo(cginfo_mb,cg_gl);
+            nat = GET_CGINFO_NATOMS(cginfo[cg1]);
+            cgindex[cg1+1] = cgindex[cg1] + nat;
+            cg0++;
+            cg1++;
+            shift_at += nat;
+        }
+        shift += ind->nrecv[cell];
+        ncg_cell[ncell+cell+1] = cg1;
+    }
+}
+
+static void make_cell2at_index(gmx_domdec_comm_dim_t *cd,
+                               int nzone,int cg0,const int *cgindex)
+{
+    int cg,zone,p;
+    
+    /* Store the atom block boundaries for easy copying of communication buffers
+     */
+    cg = cg0;
+    for(zone=0; zone<nzone; zone++)
+    {
+        for(p=0; p<cd->np; p++) {
+            cd->ind[p].cell2at0[zone] = cgindex[cg];
+            cg += cd->ind[p].nrecv[zone];
+            cd->ind[p].cell2at1[zone] = cgindex[cg];
+        }
+    }
+}
+
+static gmx_bool missing_link(t_blocka *link,int cg_gl,char *bLocalCG)
+{
+    int  i;
+    gmx_bool bMiss;
+
+    bMiss = FALSE;
+    for(i=link->index[cg_gl]; i<link->index[cg_gl+1]; i++)
+    {
+        if (!bLocalCG[link->a[i]])
+        {
+            bMiss = TRUE;
+        }
+    }
+
+    return bMiss;
+}
+
+static void setup_dd_communication(gmx_domdec_t *dd,
+                                   matrix box,gmx_ddbox_t *ddbox,t_forcerec *fr)
+{
+    int dim_ind,dim,dim0,dim1=-1,dim2=-1,dimd,p,nat_tot;
+    int nzone,nzone_send,zone,zonei,cg0,cg1;
+    int c,i,j,cg,cg_gl,nrcg;
+    int *zone_cg_range,pos_cg,*index_gl,*cgindex,*recv_i;
+    gmx_domdec_comm_t *comm;
+    gmx_domdec_zones_t *zones;
+    gmx_domdec_comm_dim_t *cd;
+    gmx_domdec_ind_t *ind;
+    cginfo_mb_t *cginfo_mb;
+    gmx_bool bBondComm,bDist2B,bDistMB,bDistMB_pulse,bDistBonded,bScrew;
+    real r_mb,r_comm2,r_scomm2,r_bcomm2,r,r_0,r_1,r2,rb2,r2inc,inv_ncg,tric_sh;
+    rvec rb,rn;
+    real corner[DIM][4],corner_round_0=0,corner_round_1[4];
+    real bcorner[DIM],bcorner_round_1=0;
+    ivec tric_dist;
+    rvec *cg_cm,*normal,*v_d,*v_0=NULL,*v_1=NULL,*recv_vr;
+    real skew_fac2_d,skew_fac_01;
+    rvec sf2_round;
+    int  nsend,nat;
+    
+    if (debug)
+    {
+        fprintf(debug,"Setting up DD communication\n");
+    }
+    
+    comm  = dd->comm;
+    cg_cm = fr->cg_cm;
+
+    for(dim_ind=0; dim_ind<dd->ndim; dim_ind++)
+    {
+        dim = dd->dim[dim_ind];
+
+        /* Check if we need to use triclinic distances */
+        tric_dist[dim_ind] = 0;
+        for(i=0; i<=dim_ind; i++)
+        {
+            if (ddbox->tric_dir[dd->dim[i]])
+            {
+                tric_dist[dim_ind] = 1;
+            }
+        }
+    }
+
+    bBondComm = comm->bBondComm;
+
+    /* Do we need to determine extra distances for multi-body bondeds? */
+    bDistMB = (comm->bInterCGMultiBody && dd->bGridJump && dd->ndim > 1);
+    
+    /* Do we need to determine extra distances for only two-body bondeds? */
+    bDist2B = (bBondComm && !bDistMB);
+
+    r_comm2  = sqr(comm->cutoff);
+    r_bcomm2 = sqr(comm->cutoff_mbody);
+
+    if (debug)
+    {
+        fprintf(debug,"bBondComm %d, r_bc %f\n",bBondComm,sqrt(r_bcomm2));
+    }
+
+    zones = &comm->zones;
+    
+    dim0 = dd->dim[0];
+    /* The first dimension is equal for all cells */
+    corner[0][0] = comm->cell_x0[dim0];
+    if (bDistMB)
+    {
+        bcorner[0] = corner[0][0];
+    }
+    if (dd->ndim >= 2)
+    {
+        dim1 = dd->dim[1];
+        /* This cell row is only seen from the first row */
+        corner[1][0] = comm->cell_x0[dim1];
+        /* All rows can see this row */
+        corner[1][1] = comm->cell_x0[dim1];
+        if (dd->bGridJump)
+        {
+            corner[1][1] = max(comm->cell_x0[dim1],comm->zone_d1[1].mch0);
+            if (bDistMB)
+            {
+                /* For the multi-body distance we need the maximum */
+                bcorner[1] = max(comm->cell_x0[dim1],comm->zone_d1[1].p1_0);
+            }
+        }
+        /* Set the upper-right corner for rounding */
+        corner_round_0 = comm->cell_x1[dim0];
+        
+        if (dd->ndim >= 3)
+        {
+            dim2 = dd->dim[2];
+            for(j=0; j<4; j++)
+            {
+                corner[2][j] = comm->cell_x0[dim2];
+            }
+            if (dd->bGridJump)
+            {
+                /* Use the maximum of the i-cells that see a j-cell */
+                for(i=0; i<zones->nizone; i++)
+                {
+                    for(j=zones->izone[i].j0; j<zones->izone[i].j1; j++)
+                    {
+                        if (j >= 4)
+                        {
+                            corner[2][j-4] =
+                                max(corner[2][j-4],
+                                    comm->zone_d2[zones->shift[i][dim0]][zones->shift[i][dim1]].mch0);
+                        }
+                    }
+                }
+                if (bDistMB)
+                {
+                    /* For the multi-body distance we need the maximum */
+                    bcorner[2] = comm->cell_x0[dim2];
+                    for(i=0; i<2; i++)
+                    {
+                        for(j=0; j<2; j++)
+                        {
+                            bcorner[2] = max(bcorner[2],
+                                             comm->zone_d2[i][j].p1_0);
+                        }
+                    }
+                }
+            }
+            
+            /* Set the upper-right corner for rounding */
+            /* Cell (0,0,0) and cell (1,0,0) can see cell 4 (0,1,1)
+             * Only cell (0,0,0) can see cell 7 (1,1,1)
+             */
+            corner_round_1[0] = comm->cell_x1[dim1];
+            corner_round_1[3] = comm->cell_x1[dim1];
+            if (dd->bGridJump)
+            {
+                corner_round_1[0] = max(comm->cell_x1[dim1],
+                                        comm->zone_d1[1].mch1);
+                if (bDistMB)
+                {
+                    /* For the multi-body distance we need the maximum */
+                    bcorner_round_1 = max(comm->cell_x1[dim1],
+                                          comm->zone_d1[1].p1_1);
+                }
+            }
+        }
+    }
+    
+    /* Triclinic stuff */
+    normal = ddbox->normal;
+    skew_fac_01 = 0;
+    if (dd->ndim >= 2)
+    {
+        v_0 = ddbox->v[dim0];
+        if (ddbox->tric_dir[dim0] && ddbox->tric_dir[dim1])
+        {
+            /* Determine the coupling coefficient for the distances
+             * to the cell planes along dim0 and dim1 through dim2.
+             * This is required for correct rounding.
+             */
+            skew_fac_01 =
+                ddbox->v[dim0][dim1+1][dim0]*ddbox->v[dim1][dim1+1][dim1];
+            if (debug)
+            {
+                fprintf(debug,"\nskew_fac_01 %f\n",skew_fac_01);
+            }
+        }
+    }
+    if (dd->ndim >= 3)
+    {
+        v_1 = ddbox->v[dim1];
+    }
+    
+    zone_cg_range = zones->cg_range;
+    index_gl = dd->index_gl;
+    cgindex  = dd->cgindex;
+    cginfo_mb = fr->cginfo_mb;
+    
+    zone_cg_range[0]   = 0;
+    zone_cg_range[1]   = dd->ncg_home;
+    comm->zone_ncg1[0] = dd->ncg_home;
+    pos_cg             = dd->ncg_home;
+    
+    nat_tot = dd->nat_home;
+    nzone = 1;
+    for(dim_ind=0; dim_ind<dd->ndim; dim_ind++)
+    {
+        dim = dd->dim[dim_ind];
+        cd = &comm->cd[dim_ind];
+        
+        if (dim >= ddbox->npbcdim && dd->ci[dim] == 0)
+        {
+            /* No pbc in this dimension, the first node should not comm. */
+            nzone_send = 0;
+        }
+        else
+        {
+            nzone_send = nzone;
+        }
+
+        bScrew = (dd->bScrewPBC && dim == XX);
+        
+        v_d = ddbox->v[dim];
+        skew_fac2_d = sqr(ddbox->skew_fac[dim]);
+
+        cd->bInPlace = TRUE;
+        for(p=0; p<cd->np; p++)
+        {
+            /* Only atoms communicated in the first pulse are used
+             * for multi-body bonded interactions or for bBondComm.
+             */
+            bDistBonded   = ((bDistMB || bDist2B) && p == 0);
+            bDistMB_pulse = (bDistMB && bDistBonded);
+
+            ind = &cd->ind[p];
+            nsend = 0;
+            nat = 0;
+            for(zone=0; zone<nzone_send; zone++)
+            {
+                if (tric_dist[dim_ind] && dim_ind > 0)
+                {
+                    /* Determine slightly more optimized skew_fac's
+                     * for rounding.
+                     * This reduces the number of communicated atoms
+                     * by about 10% for 3D DD of rhombic dodecahedra.
+                     */
+                    for(dimd=0; dimd<dim; dimd++)
+                    {
+                        sf2_round[dimd] = 1;
+                        if (ddbox->tric_dir[dimd])
+                        {
+                            for(i=dd->dim[dimd]+1; i<DIM; i++)
+                            {
+                                /* If we are shifted in dimension i
+                                 * and the cell plane is tilted forward
+                                 * in dimension i, skip this coupling.
+                                 */
+                                if (!(zones->shift[nzone+zone][i] &&
+                                      ddbox->v[dimd][i][dimd] >= 0))
+                                {
+                                    sf2_round[dimd] +=
+                                        sqr(ddbox->v[dimd][i][dimd]);
+                                }
+                            }
+                            sf2_round[dimd] = 1/sf2_round[dimd];
+                        }
+                    }
+                }
+
+                zonei = zone_perm[dim_ind][zone];
+                if (p == 0)
+                {
+                    /* Here we permutate the zones to obtain a convenient order
+                     * for neighbor searching
+                     */
+                    cg0 = zone_cg_range[zonei];
+                    cg1 = zone_cg_range[zonei+1];
+                }
+                else
+                {
+                    /* Look only at the cg's received in the previous grid pulse
+                     */
+                    cg1 = zone_cg_range[nzone+zone+1];
+                    cg0 = cg1 - cd->ind[p-1].nrecv[zone];
+                }
+                ind->nsend[zone] = 0;
+                for(cg=cg0; cg<cg1; cg++)
+                {
+                    r2  = 0;
+                    rb2 = 0;
+                    if (tric_dist[dim_ind] == 0)
+                    {
+                        /* Rectangular direction, easy */
+                        r = cg_cm[cg][dim] - corner[dim_ind][zone];
+                        if (r > 0)
+                        {
+                            r2 += r*r;
+                        }
+                        if (bDistMB_pulse)
+                        {
+                            r = cg_cm[cg][dim] - bcorner[dim_ind];
+                            if (r > 0)
+                            {
+                                rb2 += r*r;
+                            }
+                        }
+                        /* Rounding gives at most a 16% reduction
+                         * in communicated atoms
+                         */
+                        if (dim_ind >= 1 && (zonei == 1 || zonei == 2))
+                        {
+                            r = cg_cm[cg][dim0] - corner_round_0;
+                            /* This is the first dimension, so always r >= 0 */
+                            r2 += r*r;
+                            if (bDistMB_pulse)
+                            {
+                                rb2 += r*r;
+                            }
+                        }
+                        if (dim_ind == 2 && (zonei == 2 || zonei == 3))
+                        {
+                            r = cg_cm[cg][dim1] - corner_round_1[zone];
+                            if (r > 0)
+                            {
+                                r2 += r*r;
+                            }
+                            if (bDistMB_pulse)
+                            {
+                                r = cg_cm[cg][dim1] - bcorner_round_1;
+                                if (r > 0)
+                                {
+                                    rb2 += r*r;
+                                }
+                            }
+                        }
+                    }
+                    else
+                    {
+                        /* Triclinic direction, more complicated */
+                        clear_rvec(rn);
+                        clear_rvec(rb);
+                        /* Rounding, conservative as the skew_fac multiplication
+                         * will slightly underestimate the distance.
+                         */
+                        if (dim_ind >= 1 && (zonei == 1 || zonei == 2))
+                        {
+                            rn[dim0] = cg_cm[cg][dim0] - corner_round_0;
+                            for(i=dim0+1; i<DIM; i++)
+                            {
+                                rn[dim0] -= cg_cm[cg][i]*v_0[i][dim0];
+                            }
+                            r2 = rn[dim0]*rn[dim0]*sf2_round[dim0];
+                            if (bDistMB_pulse)
+                            {
+                                rb[dim0] = rn[dim0];
+                                rb2 = r2;
+                            }
+                            /* Take care that the cell planes along dim0 might not
+                             * be orthogonal to those along dim1 and dim2.
+                             */
+                            for(i=1; i<=dim_ind; i++)
+                            {
+                                dimd = dd->dim[i];
+                                if (normal[dim0][dimd] > 0)
+                                {
+                                    rn[dimd] -= rn[dim0]*normal[dim0][dimd];
+                                    if (bDistMB_pulse)
+                                    {
+                                        rb[dimd] -= rb[dim0]*normal[dim0][dimd];
+                                    }
+                                }
+                            }
+                        }
+                        if (dim_ind == 2 && (zonei == 2 || zonei == 3))
+                        {
+                            rn[dim1] += cg_cm[cg][dim1] - corner_round_1[zone];
+                            tric_sh = 0;
+                            for(i=dim1+1; i<DIM; i++)
+                            {
+                                tric_sh -= cg_cm[cg][i]*v_1[i][dim1];
+                            }
+                            rn[dim1] += tric_sh;
+                            if (rn[dim1] > 0)
+                            {
+                                r2 += rn[dim1]*rn[dim1]*sf2_round[dim1];
+                                /* Take care of coupling of the distances
+                                 * to the planes along dim0 and dim1 through dim2.
+                                 */
+                                r2 -= rn[dim0]*rn[dim1]*skew_fac_01;
+                                /* Take care that the cell planes along dim1
+                                 * might not be orthogonal to that along dim2.
+                                 */
+                                if (normal[dim1][dim2] > 0)
+                                {
+                                    rn[dim2] -= rn[dim1]*normal[dim1][dim2];
+                                }
+                            }
+                            if (bDistMB_pulse)
+                            {
+                                rb[dim1] +=
+                                    cg_cm[cg][dim1] - bcorner_round_1 + tric_sh;
+                                if (rb[dim1] > 0)
+                                {
+                                    rb2 += rb[dim1]*rb[dim1]*sf2_round[dim1];
+                                    /* Take care of coupling of the distances
+                                     * to the planes along dim0 and dim1 through dim2.
+                                     */
+                                    rb2 -= rb[dim0]*rb[dim1]*skew_fac_01;
+                                    /* Take care that the cell planes along dim1
+                                     * might not be orthogonal to that along dim2.
+                                     */
+                                    if (normal[dim1][dim2] > 0)
+                                    {
+                                        rb[dim2] -= rb[dim1]*normal[dim1][dim2];
+                                    }
+                                }
+                            }
+                        }
+                        /* The distance along the communication direction */
+                        rn[dim] += cg_cm[cg][dim] - corner[dim_ind][zone];
+                        tric_sh = 0;
+                        for(i=dim+1; i<DIM; i++)
+                        {
+                            tric_sh -= cg_cm[cg][i]*v_d[i][dim];
+                        }
+                        rn[dim] += tric_sh;
+                        if (rn[dim] > 0)
+                        {
+                            r2 += rn[dim]*rn[dim]*skew_fac2_d;
+                            /* Take care of coupling of the distances
+                             * to the planes along dim0 and dim1 through dim2.
+                             */
+                            if (dim_ind == 1 && zonei == 1)
+                            {
+                                r2 -= rn[dim0]*rn[dim]*skew_fac_01;
+                            }
+                        }
+                        if (bDistMB_pulse)
+                        {
+                            clear_rvec(rb);
+                            rb[dim] += cg_cm[cg][dim] - bcorner[dim_ind] + tric_sh;
+                            if (rb[dim] > 0)
+                            {
+                                rb2 += rb[dim]*rb[dim]*skew_fac2_d;
+                                /* Take care of coupling of the distances
+                                 * to the planes along dim0 and dim1 through dim2.
+                                 */
+                                if (dim_ind == 1 && zonei == 1)
+                                {
+                                    rb2 -= rb[dim0]*rb[dim]*skew_fac_01;
+                                }
+                            }
+                        }
+                    }
+                    
+                    if (r2 < r_comm2 ||
+                        (bDistBonded &&
+                         ((bDistMB && rb2 < r_bcomm2) ||
+                          (bDist2B && r2  < r_bcomm2)) &&
+                         (!bBondComm ||
+                          (GET_CGINFO_BOND_INTER(fr->cginfo[cg]) &&
+                           missing_link(comm->cglink,index_gl[cg],
+                                        comm->bLocalCG)))))
+                    {
+                        /* Make an index to the local charge groups */
+                        if (nsend+1 > ind->nalloc)
+                        {
+                            ind->nalloc = over_alloc_large(nsend+1);
+                            srenew(ind->index,ind->nalloc);
+                        }
+                        if (nsend+1 > comm->nalloc_int)
+                        {
+                            comm->nalloc_int = over_alloc_large(nsend+1);
+                            srenew(comm->buf_int,comm->nalloc_int);
+                        }
+                        ind->index[nsend] = cg;
+                        comm->buf_int[nsend] = index_gl[cg];
+                        ind->nsend[zone]++;
+                        vec_rvec_check_alloc(&comm->vbuf,nsend+1);
+
+                        if (dd->ci[dim] == 0)
+                        {
+                            /* Correct cg_cm for pbc */
+                            rvec_add(cg_cm[cg],box[dim],comm->vbuf.v[nsend]);
+                            if (bScrew)
+                            {
+                                comm->vbuf.v[nsend][YY] =
+                                    box[YY][YY]-comm->vbuf.v[nsend][YY];
+                                comm->vbuf.v[nsend][ZZ] =
+                                    box[ZZ][ZZ]-comm->vbuf.v[nsend][ZZ];
+                            }
+                        }
+                        else
+                        {
+                            copy_rvec(cg_cm[cg],comm->vbuf.v[nsend]);
+                        }
+                        nsend++;
+                        nat += cgindex[cg+1] - cgindex[cg];
+                    }
+                }
+            }
+            /* Clear the counts in case we do not have pbc */
+            for(zone=nzone_send; zone<nzone; zone++)
+            {
+                ind->nsend[zone] = 0;
+            }
+            ind->nsend[nzone]   = nsend;
+            ind->nsend[nzone+1] = nat;
+            /* Communicate the number of cg's and atoms to receive */
+            dd_sendrecv_int(dd, dim_ind, dddirBackward,
+                            ind->nsend, nzone+2,
+                            ind->nrecv, nzone+2);
+            
+            /* The rvec buffer is also required for atom buffers of size nsend
+             * in dd_move_x and dd_move_f.
+             */
+            vec_rvec_check_alloc(&comm->vbuf,ind->nsend[nzone+1]);
+
+            if (p > 0)
+            {
+                /* We can receive in place if only the last zone is not empty */
+                for(zone=0; zone<nzone-1; zone++)
+                {
+                    if (ind->nrecv[zone] > 0)
+                    {
+                        cd->bInPlace = FALSE;
+                    }
+                }
+                if (!cd->bInPlace)
+                {
+                    /* The int buffer is only required here for the cg indices */
+                    if (ind->nrecv[nzone] > comm->nalloc_int2)
+                    {
+                        comm->nalloc_int2 = over_alloc_dd(ind->nrecv[nzone]);
+                        srenew(comm->buf_int2,comm->nalloc_int2);
+                    }
+                    /* The rvec buffer is also required for atom buffers
+                     * of size nrecv in dd_move_x and dd_move_f.
+                     */
+                    i = max(cd->ind[0].nrecv[nzone+1],ind->nrecv[nzone+1]);
+                    vec_rvec_check_alloc(&comm->vbuf2,i);
+                }
+            }
+            
+            /* Make space for the global cg indices */
+            if (pos_cg + ind->nrecv[nzone] > dd->cg_nalloc
+                || dd->cg_nalloc == 0)
+            {
+                dd->cg_nalloc = over_alloc_dd(pos_cg + ind->nrecv[nzone]);
+                srenew(index_gl,dd->cg_nalloc);
+                srenew(cgindex,dd->cg_nalloc+1);
+            }
+            /* Communicate the global cg indices */
+            if (cd->bInPlace)
+            {
+                recv_i = index_gl + pos_cg;
+            }
+            else
+            {
+                recv_i = comm->buf_int2;
+            }
+            dd_sendrecv_int(dd, dim_ind, dddirBackward,
+                            comm->buf_int, nsend,
+                            recv_i,        ind->nrecv[nzone]);
+
+            /* Make space for cg_cm */
+            if (pos_cg + ind->nrecv[nzone] > fr->cg_nalloc)
+            {
+                dd_realloc_fr_cg(fr,pos_cg + ind->nrecv[nzone]);
+                cg_cm = fr->cg_cm;
+            }
+            /* Communicate cg_cm */
+            if (cd->bInPlace)
+            {
+                recv_vr = cg_cm + pos_cg;
+            }
+            else
+            {
+                recv_vr = comm->vbuf2.v;
+            }
+            dd_sendrecv_rvec(dd, dim_ind, dddirBackward,
+                             comm->vbuf.v, nsend,
+                             recv_vr,      ind->nrecv[nzone]);
+            
+            /* Make the charge group index */
+            if (cd->bInPlace)
+            {
+                zone = (p == 0 ? 0 : nzone - 1);
+                while (zone < nzone)
+                {
+                    for(cg=0; cg<ind->nrecv[zone]; cg++)
+                    {
+                        cg_gl = index_gl[pos_cg];
+                        fr->cginfo[pos_cg] = ddcginfo(cginfo_mb,cg_gl);
+                        nrcg = GET_CGINFO_NATOMS(fr->cginfo[pos_cg]);
+                        cgindex[pos_cg+1] = cgindex[pos_cg] + nrcg;
+                        if (bBondComm)
+                        {
+                            /* Update the charge group presence,
+                             * so we can use it in the next pass of the loop.
+                             */
+                            comm->bLocalCG[cg_gl] = TRUE;
+                        }
+                        pos_cg++;
+                    }
+                    if (p == 0)
+                    {
+                        comm->zone_ncg1[nzone+zone] = ind->nrecv[zone];
+                    }
+                    zone++;
+                    zone_cg_range[nzone+zone] = pos_cg;
+                }
+            }
+            else
+            {
+                /* This part of the code is never executed with bBondComm. */
+                merge_cg_buffers(nzone,cd,p,zone_cg_range,
+                                 index_gl,recv_i,cg_cm,recv_vr,
+                                 cgindex,fr->cginfo_mb,fr->cginfo);
+                pos_cg += ind->nrecv[nzone];
+            }
+            nat_tot += ind->nrecv[nzone+1];
+        }
+        if (!cd->bInPlace)
+        {
+            /* Store the atom block for easy copying of communication buffers */
+            make_cell2at_index(cd,nzone,zone_cg_range[nzone],cgindex);
+        }
+        nzone += nzone;
+    }
+    dd->index_gl = index_gl;
+    dd->cgindex  = cgindex;
+    
+    dd->ncg_tot = zone_cg_range[zones->n];
+    dd->nat_tot = nat_tot;
+    comm->nat[ddnatHOME] = dd->nat_home;
+    for(i=ddnatZONE; i<ddnatNR; i++)
+    {
+        comm->nat[i] = dd->nat_tot;
+    }
+
+    if (!bBondComm)
+    {
+        /* We don't need to update cginfo, since that was alrady done above.
+         * So we pass NULL for the forcerec.
+         */
+        dd_set_cginfo(dd->index_gl,dd->ncg_home,dd->ncg_tot,
+                      NULL,comm->bLocalCG);
+    }
+
+    if (debug)
+    {
+        fprintf(debug,"Finished setting up DD communication, zones:");
+        for(c=0; c<zones->n; c++)
+        {
+            fprintf(debug," %d",zones->cg_range[c+1]-zones->cg_range[c]);
+        }
+        fprintf(debug,"\n");
+    }
+}
+
+static void set_cg_boundaries(gmx_domdec_zones_t *zones)
+{
+    int c;
+    
+    for(c=0; c<zones->nizone; c++)
+    {
+        zones->izone[c].cg1  = zones->cg_range[c+1];
+        zones->izone[c].jcg0 = zones->cg_range[zones->izone[c].j0];
+        zones->izone[c].jcg1 = zones->cg_range[zones->izone[c].j1];
+    }
+}
+
+static int comp_cgsort(const void *a,const void *b)
+{
+    int comp;
+    
+    gmx_cgsort_t *cga,*cgb;
+    cga = (gmx_cgsort_t *)a;
+    cgb = (gmx_cgsort_t *)b;
+    
+    comp = cga->nsc - cgb->nsc;
+    if (comp == 0)
+    {
+        comp = cga->ind_gl - cgb->ind_gl;
+    }
+    
+    return comp;
+}
+
+static void order_int_cg(int n,gmx_cgsort_t *sort,
+                         int *a,int *buf)
+{
+    int i;
+    
+    /* Order the data */
+    for(i=0; i<n; i++)
+    {
+        buf[i] = a[sort[i].ind];
+    }
+    
+    /* Copy back to the original array */
+    for(i=0; i<n; i++)
+    {
+        a[i] = buf[i];
+    }
+}
+
+static void order_vec_cg(int n,gmx_cgsort_t *sort,
+                         rvec *v,rvec *buf)
+{
+    int i;
+    
+    /* Order the data */
+    for(i=0; i<n; i++)
+    {
+        copy_rvec(v[sort[i].ind],buf[i]);
+    }
+    
+    /* Copy back to the original array */
+    for(i=0; i<n; i++)
+    {
+        copy_rvec(buf[i],v[i]);
+    }
+}
+
+static void order_vec_atom(int ncg,int *cgindex,gmx_cgsort_t *sort,
+                           rvec *v,rvec *buf)
+{
+    int a,atot,cg,cg0,cg1,i;
+    
+    /* Order the data */
+    a = 0;
+    for(cg=0; cg<ncg; cg++)
+    {
+        cg0 = cgindex[sort[cg].ind];
+        cg1 = cgindex[sort[cg].ind+1];
+        for(i=cg0; i<cg1; i++)
+        {
+            copy_rvec(v[i],buf[a]);
+            a++;
+        }
+    }
+    atot = a;
+    
+    /* Copy back to the original array */
+    for(a=0; a<atot; a++)
+    {
+        copy_rvec(buf[a],v[a]);
+    }
+}
+
+static void ordered_sort(int nsort2,gmx_cgsort_t *sort2,
+                         int nsort_new,gmx_cgsort_t *sort_new,
+                         gmx_cgsort_t *sort1)
+{
+    int i1,i2,i_new;
+    
+    /* The new indices are not very ordered, so we qsort them */
+    qsort_threadsafe(sort_new,nsort_new,sizeof(sort_new[0]),comp_cgsort);
+    
+    /* sort2 is already ordered, so now we can merge the two arrays */
+    i1 = 0;
+    i2 = 0;
+    i_new = 0;
+    while(i2 < nsort2 || i_new < nsort_new)
+    {
+        if (i2 == nsort2)
+        {
+            sort1[i1++] = sort_new[i_new++];
+        }
+        else if (i_new == nsort_new)
+        {
+            sort1[i1++] = sort2[i2++];
+        }
+        else if (sort2[i2].nsc < sort_new[i_new].nsc ||
+                 (sort2[i2].nsc == sort_new[i_new].nsc &&
+                  sort2[i2].ind_gl < sort_new[i_new].ind_gl))
+        {
+            sort1[i1++] = sort2[i2++];
+        }
+        else
+        {
+            sort1[i1++] = sort_new[i_new++];
+        }
+    }
+}
+
+static void dd_sort_state(gmx_domdec_t *dd,int ePBC,
+                          rvec *cgcm,t_forcerec *fr,t_state *state,
+                          int ncg_home_old)
+{
+    gmx_domdec_sort_t *sort;
+    gmx_cgsort_t *cgsort,*sort_i;
+    int  ncg_new,nsort2,nsort_new,i,cell_index,*ibuf,cgsize;
+    rvec *vbuf;
+    
+    sort = dd->comm->sort;
+    
+    if (dd->ncg_home > sort->sort_nalloc)
+    {
+        sort->sort_nalloc = over_alloc_dd(dd->ncg_home);
+        srenew(sort->sort1,sort->sort_nalloc);
+        srenew(sort->sort2,sort->sort_nalloc);
+    }
+    
+    if (ncg_home_old >= 0)
+    {
+        /* The charge groups that remained in the same ns grid cell
+         * are completely ordered. So we can sort efficiently by sorting
+         * the charge groups that did move into the stationary list.
+         */
+        ncg_new = 0;
+        nsort2 = 0;
+        nsort_new = 0;
+        for(i=0; i<dd->ncg_home; i++)
+        {
+            /* Check if this cg did not move to another node */
+            cell_index = fr->ns.grid->cell_index[i];
+            if (cell_index !=  4*fr->ns.grid->ncells)
+            {
+                if (i >= ncg_home_old || cell_index != sort->sort1[i].nsc)
+                {
+                    /* This cg is new on this node or moved ns grid cell */
+                    if (nsort_new >= sort->sort_new_nalloc)
+                    {
+                        sort->sort_new_nalloc = over_alloc_dd(nsort_new+1);
+                        srenew(sort->sort_new,sort->sort_new_nalloc);
+                    }
+                    sort_i = &(sort->sort_new[nsort_new++]);
+                }
+                else
+                {
+                    /* This cg did not move */
+                    sort_i = &(sort->sort2[nsort2++]);
+                }
+                /* Sort on the ns grid cell indices
+                 * and the global topology index
+                 */
+                sort_i->nsc    = cell_index;
+                sort_i->ind_gl = dd->index_gl[i];
+                sort_i->ind    = i;
+                ncg_new++;
+            }
+        }
+        if (debug)
+        {
+            fprintf(debug,"ordered sort cgs: stationary %d moved %d\n",
+                    nsort2,nsort_new);
+        }
+        /* Sort efficiently */
+        ordered_sort(nsort2,sort->sort2,nsort_new,sort->sort_new,sort->sort1);
+    }
+    else
+    {
+        cgsort = sort->sort1;
+        ncg_new = 0;
+        for(i=0; i<dd->ncg_home; i++)
+        {
+            /* Sort on the ns grid cell indices
+             * and the global topology index
+             */
+            cgsort[i].nsc    = fr->ns.grid->cell_index[i];
+            cgsort[i].ind_gl = dd->index_gl[i];
+            cgsort[i].ind    = i;
+            if (cgsort[i].nsc != 4*fr->ns.grid->ncells)
+            {
+                ncg_new++;
+            }
+        }
+        if (debug)
+        {
+            fprintf(debug,"qsort cgs: %d new home %d\n",dd->ncg_home,ncg_new);
+        }
+        /* Determine the order of the charge groups using qsort */
+        qsort_threadsafe(cgsort,dd->ncg_home,sizeof(cgsort[0]),comp_cgsort);
+    }
+    cgsort = sort->sort1;
+    
+    /* We alloc with the old size, since cgindex is still old */
+    vec_rvec_check_alloc(&dd->comm->vbuf,dd->cgindex[dd->ncg_home]);
+    vbuf = dd->comm->vbuf.v;
+    
+    /* Remove the charge groups which are no longer at home here */
+    dd->ncg_home = ncg_new;
+    
+    /* Reorder the state */
+    for(i=0; i<estNR; i++)
+    {
+        if (EST_DISTR(i) && state->flags & (1<<i))
+        {
+            switch (i)
+            {
+            case estX:
+                order_vec_atom(dd->ncg_home,dd->cgindex,cgsort,state->x,vbuf);
+                break;
+            case estV:
+                order_vec_atom(dd->ncg_home,dd->cgindex,cgsort,state->v,vbuf);
+                break;
+            case estSDX:
+                order_vec_atom(dd->ncg_home,dd->cgindex,cgsort,state->sd_X,vbuf);
+                break;
+            case estCGP:
+                order_vec_atom(dd->ncg_home,dd->cgindex,cgsort,state->cg_p,vbuf);
+                break;
+            case estLD_RNG:
+            case estLD_RNGI:
+            case estDISRE_INITF:
+            case estDISRE_RM3TAV:
+            case estORIRE_INITF:
+            case estORIRE_DTAV:
+                /* No ordering required */
+                break;
+            default:
+                gmx_incons("Unknown state entry encountered in dd_sort_state");
+                break;
+            }
+        }
+    }
+    /* Reorder cgcm */
+    order_vec_cg(dd->ncg_home,cgsort,cgcm,vbuf);
+    
+    if (dd->ncg_home+1 > sort->ibuf_nalloc)
+    {
+        sort->ibuf_nalloc = over_alloc_dd(dd->ncg_home+1);
+        srenew(sort->ibuf,sort->ibuf_nalloc);
+    }
+    ibuf = sort->ibuf;
+    /* Reorder the global cg index */
+    order_int_cg(dd->ncg_home,cgsort,dd->index_gl,ibuf);
+    /* Reorder the cginfo */
+    order_int_cg(dd->ncg_home,cgsort,fr->cginfo,ibuf);
+    /* Rebuild the local cg index */
+    ibuf[0] = 0;
+    for(i=0; i<dd->ncg_home; i++)
+    {
+        cgsize = dd->cgindex[cgsort[i].ind+1] - dd->cgindex[cgsort[i].ind];
+        ibuf[i+1] = ibuf[i] + cgsize;
+    }
+    for(i=0; i<dd->ncg_home+1; i++)
+    {
+        dd->cgindex[i] = ibuf[i];
+    }
+    /* Set the home atom number */
+    dd->nat_home = dd->cgindex[dd->ncg_home];
+    
+    /* Copy the sorted ns cell indices back to the ns grid struct */
+    for(i=0; i<dd->ncg_home; i++)
+    {
+        fr->ns.grid->cell_index[i] = cgsort[i].nsc;
+    }
+    fr->ns.grid->nr = dd->ncg_home;
+}
+
+static void add_dd_statistics(gmx_domdec_t *dd)
+{
+    gmx_domdec_comm_t *comm;
+    int ddnat;
+    
+    comm = dd->comm;
+    
+    for(ddnat=ddnatZONE; ddnat<ddnatNR; ddnat++)
+    {
+        comm->sum_nat[ddnat-ddnatZONE] +=
+            comm->nat[ddnat] - comm->nat[ddnat-1];
+    }
+    comm->ndecomp++;
+}
+
+void reset_dd_statistics_counters(gmx_domdec_t *dd)
+{
+    gmx_domdec_comm_t *comm;
+    int ddnat;
+    
+    comm = dd->comm;
+
+    /* Reset all the statistics and counters for total run counting */
+    for(ddnat=ddnatZONE; ddnat<ddnatNR; ddnat++)
+    {
+        comm->sum_nat[ddnat-ddnatZONE] = 0;
+    }
+    comm->ndecomp = 0;
+    comm->nload = 0;
+    comm->load_step = 0;
+    comm->load_sum = 0;
+    comm->load_max = 0;
+    clear_ivec(comm->load_lim);
+    comm->load_mdf = 0;
+    comm->load_pme = 0;
+}
+
+void print_dd_statistics(t_commrec *cr,t_inputrec *ir,FILE *fplog)
+{
+    gmx_domdec_comm_t *comm;
+    int ddnat;
+    double av;
+   
+    comm = cr->dd->comm;
+    
+    gmx_sumd(ddnatNR-ddnatZONE,comm->sum_nat,cr);
+    
+    if (fplog == NULL)
+    {
+        return;
+    }
+    
+    fprintf(fplog,"\n    D O M A I N   D E C O M P O S I T I O N   S T A T I S T I C S\n\n");
+            
+    for(ddnat=ddnatZONE; ddnat<ddnatNR; ddnat++)
+    {
+        av = comm->sum_nat[ddnat-ddnatZONE]/comm->ndecomp;
+        switch(ddnat)
+        {
+        case ddnatZONE:
+            fprintf(fplog,
+                    " av. #atoms communicated per step for force:  %d x %.1f\n",
+                    2,av);
+            break;
+        case ddnatVSITE:
+            if (cr->dd->vsite_comm)
+            {
+                fprintf(fplog,
+                        " av. #atoms communicated per step for vsites: %d x %.1f\n",
+                        (EEL_PME(ir->coulombtype) || ir->coulombtype==eelEWALD) ? 3 : 2,
+                        av);
+            }
+            break;
+        case ddnatCON:
+            if (cr->dd->constraint_comm)
+            {
+                fprintf(fplog,
+                        " av. #atoms communicated per step for LINCS:  %d x %.1f\n",
+                        1 + ir->nLincsIter,av);
+            }
+            break;
+        default:
+            gmx_incons(" Unknown type for DD statistics");
+        }
+    }
+    fprintf(fplog,"\n");
+    
+    if (comm->bRecordLoad && EI_DYNAMICS(ir->eI))
+    {
+        print_dd_load_av(fplog,cr->dd);
+    }
+}
+
+void dd_partition_system(FILE            *fplog,
+                         gmx_large_int_t      step,
+                         t_commrec       *cr,
+                         gmx_bool            bMasterState,
+                         int             nstglobalcomm,
+                         t_state         *state_global,
+                         gmx_mtop_t      *top_global,
+                         t_inputrec      *ir,
+                         t_state         *state_local,
+                         rvec            **f,
+                         t_mdatoms       *mdatoms,
+                         gmx_localtop_t  *top_local,
+                         t_forcerec      *fr,
+                         gmx_vsite_t     *vsite,
+                         gmx_shellfc_t   shellfc,
+                         gmx_constr_t    constr,
+                         t_nrnb          *nrnb,
+                         gmx_wallcycle_t wcycle,
+                         gmx_bool            bVerbose)
+{
+    gmx_domdec_t *dd;
+    gmx_domdec_comm_t *comm;
+    gmx_ddbox_t ddbox={0};
+    t_block *cgs_gl;
+    gmx_large_int_t step_pcoupl;
+    rvec cell_ns_x0,cell_ns_x1;
+    int  i,j,n,cg0=0,ncg_home_old=-1,nat_f_novirsum;
+    gmx_bool bBoxChanged,bNStGlobalComm,bDoDLB,bCheckDLB,bTurnOnDLB,bLogLoad;
+    gmx_bool bRedist,bSortCG,bResortAll;
+    ivec ncells_old,np;
+    real grid_density;
+    char sbuf[22];
+       
+    dd = cr->dd;
+    comm = dd->comm;
+
+    bBoxChanged = (bMasterState || DEFORM(*ir));
+    if (ir->epc != epcNO)
+    {
+        /* With nstcalcenery > 1 pressure coupling happens.
+         * one step after calculating the energies.
+         * Box scaling happens at the end of the MD step,
+         * after the DD partitioning.
+         * We therefore have to do DLB in the first partitioning
+         * after an MD step where P-coupling occured.
+         * We need to determine the last step in which p-coupling occurred.
+         * MRS -- need to validate this for vv?
+         */
+        n = ir->nstcalcenergy;
+        if (n == 1)
+        {
+            step_pcoupl = step - 1;
+        }
+        else
+        {
+            step_pcoupl = ((step - 1)/n)*n + 1;
+        }
+        if (step_pcoupl >= comm->partition_step)
+        {
+            bBoxChanged = TRUE;
+        }
+    }
+
+    bNStGlobalComm = (step >= comm->partition_step + nstglobalcomm);
+
+    if (!comm->bDynLoadBal)
+    {
+        bDoDLB = FALSE;
+    }
+    else
+    {
+        /* Should we do dynamic load balacing this step?
+         * Since it requires (possibly expensive) global communication,
+         * we might want to do DLB less frequently.
+         */
+        if (bBoxChanged || ir->epc != epcNO)
+        {
+            bDoDLB = bBoxChanged;
+        }
+        else
+        {
+            bDoDLB = bNStGlobalComm;
+        }
+    }
+
+    /* Check if we have recorded loads on the nodes */
+    if (comm->bRecordLoad && dd_load_count(comm))
+    {
+        if (comm->eDLB == edlbAUTO && !comm->bDynLoadBal)
+        {
+            /* Check if we should use DLB at the second partitioning
+             * and every 100 partitionings,
+             * so the extra communication cost is negligible.
+             */
+            n = max(100,nstglobalcomm);
+            bCheckDLB = (comm->n_load_collect == 0 ||
+                         comm->n_load_have % n == n-1);
+        }
+        else
+        {
+            bCheckDLB = FALSE;
+        }
+        
+        /* Print load every nstlog, first and last step to the log file */
+        bLogLoad = ((ir->nstlog > 0 && step % ir->nstlog == 0) ||
+                    comm->n_load_collect == 0 ||
+                    (step + ir->nstlist > ir->init_step + ir->nsteps));
+
+        /* Avoid extra communication due to verbose screen output
+         * when nstglobalcomm is set.
+         */
+        if (bDoDLB || bLogLoad || bCheckDLB ||
+            (bVerbose && (ir->nstlist == 0 || nstglobalcomm <= ir->nstlist)))
+        {
+            get_load_distribution(dd,wcycle);
+            if (DDMASTER(dd))
+            {
+                if (bLogLoad)
+                {
+                    dd_print_load(fplog,dd,step-1);
+                }
+                if (bVerbose)
+                {
+                    dd_print_load_verbose(dd);
+                }
+            }
+            comm->n_load_collect++;
+
+            if (bCheckDLB) {
+                /* Since the timings are node dependent, the master decides */
+                if (DDMASTER(dd))
+                {
+                    bTurnOnDLB =
+                        (dd_force_imb_perf_loss(dd) >= DD_PERF_LOSS);
+                    if (debug)
+                    {
+                        fprintf(debug,"step %s, imb loss %f\n",
+                                gmx_step_str(step,sbuf),
+                                dd_force_imb_perf_loss(dd));
+                    }
+                }
+                dd_bcast(dd,sizeof(bTurnOnDLB),&bTurnOnDLB);
+                if (bTurnOnDLB)
+                {
+                    turn_on_dlb(fplog,cr,step);
+                    bDoDLB = TRUE;
+                }
+            }
+        }
+        comm->n_load_have++;
+    }
+
+    cgs_gl = &comm->cgs_gl;
+
+    bRedist = FALSE;
+    if (bMasterState)
+    {
+        /* Clear the old state */
+        clear_dd_indices(dd,0,0);
+
+        set_ddbox(dd,bMasterState,cr,ir,state_global->box,
+                  TRUE,cgs_gl,state_global->x,&ddbox);
+    
+        get_cg_distribution(fplog,step,dd,cgs_gl,
+                            state_global->box,&ddbox,state_global->x);
+        
+        dd_distribute_state(dd,cgs_gl,
+                            state_global,state_local,f);
+        
+        dd_make_local_cgs(dd,&top_local->cgs);
+        
+        if (dd->ncg_home > fr->cg_nalloc)
+        {
+            dd_realloc_fr_cg(fr,dd->ncg_home);
+        }
+        calc_cgcm(fplog,0,dd->ncg_home,
+                  &top_local->cgs,state_local->x,fr->cg_cm);
+        
+        inc_nrnb(nrnb,eNR_CGCM,dd->nat_home);
+        
+        dd_set_cginfo(dd->index_gl,0,dd->ncg_home,fr,comm->bLocalCG);
+
+        cg0 = 0;
+    }
+    else if (state_local->ddp_count != dd->ddp_count)
+    {
+        if (state_local->ddp_count > dd->ddp_count)
+        {
+            gmx_fatal(FARGS,"Internal inconsistency state_local->ddp_count (%d) > dd->ddp_count (%d)",state_local->ddp_count,dd->ddp_count);
+        }
+        
+        if (state_local->ddp_count_cg_gl != state_local->ddp_count)
+        {
+            gmx_fatal(FARGS,"Internal inconsistency state_local->ddp_count_cg_gl (%d) != state_local->ddp_count (%d)",state_local->ddp_count_cg_gl,state_local->ddp_count);
+        }
+        
+        /* Clear the old state */
+        clear_dd_indices(dd,0,0);
+        
+        /* Build the new indices */
+        rebuild_cgindex(dd,cgs_gl->index,state_local);
+        make_dd_indices(dd,cgs_gl->index,0);
+        
+        /* Redetermine the cg COMs */
+        calc_cgcm(fplog,0,dd->ncg_home,
+                  &top_local->cgs,state_local->x,fr->cg_cm);
+        
+        inc_nrnb(nrnb,eNR_CGCM,dd->nat_home);
+
+        dd_set_cginfo(dd->index_gl,0,dd->ncg_home,fr,comm->bLocalCG);
+
+        set_ddbox(dd,bMasterState,cr,ir,state_local->box,
+                  TRUE,&top_local->cgs,state_local->x,&ddbox);
+
+        bRedist = comm->bDynLoadBal;
+    }
+    else
+    {
+        /* We have the full state, only redistribute the cgs */
+
+        /* Clear the non-home indices */
+        clear_dd_indices(dd,dd->ncg_home,dd->nat_home);
+
+        /* Avoid global communication for dim's without pbc and -gcom */
+        if (!bNStGlobalComm)
+        {
+            copy_rvec(comm->box0    ,ddbox.box0    );
+            copy_rvec(comm->box_size,ddbox.box_size);
+        }
+        set_ddbox(dd,bMasterState,cr,ir,state_local->box,
+                  bNStGlobalComm,&top_local->cgs,state_local->x,&ddbox);
+
+        bBoxChanged = TRUE;
+        bRedist = TRUE;
+    }
+    /* For dim's without pbc and -gcom */
+    copy_rvec(ddbox.box0    ,comm->box0    );
+    copy_rvec(ddbox.box_size,comm->box_size);
+    
+    set_dd_cell_sizes(dd,&ddbox,dynamic_dd_box(&ddbox,ir),bMasterState,bDoDLB,
+                      step,wcycle);
+    
+    if (comm->nstDDDumpGrid > 0 && step % comm->nstDDDumpGrid == 0)
+    {
+        write_dd_grid_pdb("dd_grid",step,dd,state_local->box,&ddbox);
+    }
+    
+    /* Check if we should sort the charge groups */
+    if (comm->nstSortCG > 0)
+    {
+        bSortCG = (bMasterState ||
+                   (bRedist && (step % comm->nstSortCG == 0)));
+    }
+    else
+    {
+        bSortCG = FALSE;
+    }
+
+    ncg_home_old = dd->ncg_home;
+
+    if (bRedist)
+    {
+        cg0 = dd_redistribute_cg(fplog,step,dd,ddbox.tric_dir,
+                                 state_local,f,fr,mdatoms,
+                                 !bSortCG,nrnb);
+    }
+    
+    get_nsgrid_boundaries(fr->ns.grid,dd,
+                          state_local->box,&ddbox,&comm->cell_x0,&comm->cell_x1,
+                          dd->ncg_home,fr->cg_cm,
+                          cell_ns_x0,cell_ns_x1,&grid_density);
+
+    if (bBoxChanged)
+    {
+        comm_dd_ns_cell_sizes(dd,&ddbox,cell_ns_x0,cell_ns_x1,step);
+    }
+
+    copy_ivec(fr->ns.grid->n,ncells_old);
+    grid_first(fplog,fr->ns.grid,dd,&ddbox,fr->ePBC,
+               state_local->box,cell_ns_x0,cell_ns_x1,
+               fr->rlistlong,grid_density);
+    /* We need to store tric_dir for dd_get_ns_ranges called from ns.c */
+    copy_ivec(ddbox.tric_dir,comm->tric_dir);
+
+    if (bSortCG)
+    {
+        /* Sort the state on charge group position.
+         * This enables exact restarts from this step.
+         * It also improves performance by about 15% with larger numbers
+         * of atoms per node.
+         */
+        
+        /* Fill the ns grid with the home cell,
+         * so we can sort with the indices.
+         */
+        set_zones_ncg_home(dd);
+        fill_grid(fplog,&comm->zones,fr->ns.grid,dd->ncg_home,
+                  0,dd->ncg_home,fr->cg_cm);
+        
+        /* Check if we can user the old order and ns grid cell indices
+         * of the charge groups to sort the charge groups efficiently.
+         */
+        bResortAll = (bMasterState ||
+                      fr->ns.grid->n[XX] != ncells_old[XX] ||
+                      fr->ns.grid->n[YY] != ncells_old[YY] ||
+                      fr->ns.grid->n[ZZ] != ncells_old[ZZ]);
+
+        if (debug)
+        {
+            fprintf(debug,"Step %s, sorting the %d home charge groups\n",
+                    gmx_step_str(step,sbuf),dd->ncg_home);
+        }
+        dd_sort_state(dd,ir->ePBC,fr->cg_cm,fr,state_local,
+                      bResortAll ? -1 : ncg_home_old);
+        /* Rebuild all the indices */
+        cg0 = 0;
+        ga2la_clear(dd->ga2la);
+    }
+    
+    /* Setup up the communication and communicate the coordinates */
+    setup_dd_communication(dd,state_local->box,&ddbox,fr);
+    
+    /* Set the indices */
+    make_dd_indices(dd,cgs_gl->index,cg0);
+
+    /* Set the charge group boundaries for neighbor searching */
+    set_cg_boundaries(&comm->zones);
+    
+    /*
+    write_dd_pdb("dd_home",step,"dump",top_global,cr,
+                 -1,state_local->x,state_local->box);
+    */
+    
+    /* Extract a local topology from the global topology */
+    for(i=0; i<dd->ndim; i++)
+    {
+        np[dd->dim[i]] = comm->cd[i].np;
+    }
+    dd_make_local_top(fplog,dd,&comm->zones,dd->npbcdim,state_local->box,
+                      comm->cellsize_min,np,
+                      fr,vsite,top_global,top_local);
+    
+    /* Set up the special atom communication */
+    n = comm->nat[ddnatZONE];
+    for(i=ddnatZONE+1; i<ddnatNR; i++)
+    {
+        switch(i)
+        {
+        case ddnatVSITE:
+            if (vsite && vsite->n_intercg_vsite)
+            {
+                n = dd_make_local_vsites(dd,n,top_local->idef.il);
+            }
+            break;
+        case ddnatCON:
+            if (dd->bInterCGcons)
+            {
+                /* Only for inter-cg constraints we need special code */
+                n = dd_make_local_constraints(dd,n,top_global,
+                                              constr,ir->nProjOrder,
+                                              &top_local->idef.il[F_CONSTR]);
+            }
+            break;
+        default:
+            gmx_incons("Unknown special atom type setup");
+        }
+        comm->nat[i] = n;
+    }
+    
+    /* Make space for the extra coordinates for virtual site
+     * or constraint communication.
+     */
+    state_local->natoms = comm->nat[ddnatNR-1];
+    if (state_local->natoms > state_local->nalloc)
+    {
+        dd_realloc_state(state_local,f,state_local->natoms);
+    }
+
+    if (fr->bF_NoVirSum)
+    {
+        if (vsite && vsite->n_intercg_vsite)
+        {
+            nat_f_novirsum = comm->nat[ddnatVSITE];
+        }
+        else
+        {
+            if (EEL_FULL(ir->coulombtype) && dd->n_intercg_excl > 0)
+            {
+                nat_f_novirsum = dd->nat_tot;
+            }
+            else
+            {
+                nat_f_novirsum = dd->nat_home;
+            }
+        }
+    }
+    else
+    {
+        nat_f_novirsum = 0;
+    }
+
+    /* Set the number of atoms required for the force calculation.
+     * Forces need to be constrained when using a twin-range setup
+     * or with energy minimization. For simple simulations we could
+     * avoid some allocation, zeroing and copying, but this is
+     * probably not worth the complications ande checking.
+     */
+    forcerec_set_ranges(fr,dd->ncg_home,dd->ncg_tot,
+                        dd->nat_tot,comm->nat[ddnatCON],nat_f_novirsum);
+
+    /* We make the all mdatoms up to nat_tot_con.
+     * We could save some work by only setting invmass
+     * between nat_tot and nat_tot_con.
+     */
+    /* This call also sets the new number of home particles to dd->nat_home */
+    atoms2md(top_global,ir,
+             comm->nat[ddnatCON],dd->gatindex,0,dd->nat_home,mdatoms);
+
+    /* Now we have the charges we can sort the FE interactions */
+    dd_sort_local_top(dd,mdatoms,top_local);
+
+    if (shellfc)
+    {
+        /* Make the local shell stuff, currently no communication is done */
+        make_local_shells(cr,mdatoms,shellfc);
+    }
+    
+       if (ir->implicit_solvent)
+    {
+        make_local_gb(cr,fr->born,ir->gb_algorithm);
+    }
+       
+    if (!(cr->duty & DUTY_PME))
+    {
+        /* Send the charges to our PME only node */
+        gmx_pme_send_q(cr,mdatoms->nChargePerturbed,
+                       mdatoms->chargeA,mdatoms->chargeB,
+                       dd_pme_maxshift_x(dd),dd_pme_maxshift_y(dd));
+    }
+    
+    if (constr)
+    {
+        set_constraints(constr,top_local,ir,mdatoms,cr);
+    }
+    
+    if (ir->ePull != epullNO)
+    {
+        /* Update the local pull groups */
+        dd_make_local_pull_groups(dd,ir->pull,mdatoms);
+    }
+    
+    if (ir->bRot)
+    {
+        /* Update the local rotation groups */
+        dd_make_local_rotation_groups(dd,ir->rot);
+    }
+
+
+    add_dd_statistics(dd);
+    
+    /* Make sure we only count the cycles for this DD partitioning */
+    clear_dd_cycle_counts(dd);
+    
+    /* Because the order of the atoms might have changed since
+     * the last vsite construction, we need to communicate the constructing
+     * atom coordinates again (for spreading the forces this MD step).
+     */
+    dd_move_x_vsites(dd,state_local->box,state_local->x);
+    
+    if (comm->nstDDDump > 0 && step % comm->nstDDDump == 0)
+    {
+        dd_move_x(dd,state_local->box,state_local->x);
+        write_dd_pdb("dd_dump",step,"dump",top_global,cr,
+                     -1,state_local->x,state_local->box);
+    }
+
+    /* Store the partitioning step */
+    comm->partition_step = step;
+    
+    /* Increase the DD partitioning counter */
+    dd->ddp_count++;
+    /* The state currently matches this DD partitioning count, store it */
+    state_local->ddp_count = dd->ddp_count;
+    if (bMasterState)
+    {
+        /* The DD master node knows the complete cg distribution,
+         * store the count so we can possibly skip the cg info communication.
+         */
+        comm->master_cg_ddp_count = (bSortCG ? 0 : dd->ddp_count);
+    }
+
+    if (comm->DD_debug > 0)
+    {
+        /* Set the env var GMX_DD_DEBUG if you suspect corrupted indices */
+        check_index_consistency(dd,top_global->natoms,ncg_mtop(top_global),
+                                "after partitioning");
+    }
+}
similarity index 100%
rename from src/mdlib/ebin.c
rename to src/gromacs/mdlib/ebin.c
similarity index 100%
rename from src/mdlib/edsam.c
rename to src/gromacs/mdlib/edsam.c
similarity index 100%
rename from src/mdlib/ewald.c
rename to src/gromacs/mdlib/ewald.c
similarity index 100%
rename from src/mdlib/fft5d.c
rename to src/gromacs/mdlib/fft5d.c
similarity index 100%
rename from src/mdlib/fft5d.h
rename to src/gromacs/mdlib/fft5d.h
similarity index 100%
rename from src/mdlib/force.c
rename to src/gromacs/mdlib/force.c
similarity index 100%
rename from src/mdlib/ghat.c
rename to src/gromacs/mdlib/ghat.c
diff --git a/src/gromacs/mdlib/gmx_wallcycle.c b/src/gromacs/mdlib/gmx_wallcycle.c
new file mode 100644 (file)
index 0000000..47fbcdc
--- /dev/null
@@ -0,0 +1,474 @@
+/*  -*- 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-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
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include "gmx_wallcycle.h"
+#include "gmx_cyclecounter.h"
+#include "smalloc.h"
+#include "gmx_fatal.h"
+
+#ifdef GMX_LIB_MPI
+#include <mpi.h>
+#endif
+#ifdef GMX_THREADS
+#include "tmpi.h"
+#endif
+
+typedef struct
+{
+    int          n;
+    gmx_cycles_t c;
+    gmx_cycles_t start;
+    gmx_cycles_t last;
+} wallcc_t;
+
+typedef struct gmx_wallcycle
+{
+    wallcc_t     *wcc;
+    /* variables for testing/debugging */
+    gmx_bool         wc_barrier;
+    wallcc_t     *wcc_all;
+    int          wc_depth;
+    int          ewc_prev;
+    gmx_cycles_t cycle_prev;
+    gmx_large_int_t   reset_counters;
+#ifdef GMX_MPI
+    MPI_Comm     mpi_comm_mygroup;
+#endif
+} gmx_wallcycle_t_t;
+
+/* Each name should not exceed 19 characters */
+static const char *wcn[ewcNR] =
+{ "Run", "Step", "PP during PME", "Domain decomp.", "DD comm. load", "DD comm. bounds", "Vsite constr.", "Send X to PME", "Comm. coord.", "Neighbor search", "Born radii", "Force", "Wait + Comm. F", "PME mesh", "PME redist. X/F", "PME spread/gather", "PME 3D-FFT", "PME solve", "Wait + Comm. X/F", "Wait + Recv. PME F", "Vsite spread", "Write traj.", "Update", "Constraints", "Comm. energies", "Enforced rotation", "Test" };
+
+gmx_bool wallcycle_have_counter(void)
+{
+  return gmx_cycles_have_counter();
+}
+
+gmx_wallcycle_t wallcycle_init(FILE *fplog,int resetstep,t_commrec *cr)
+{
+    gmx_wallcycle_t wc;
+    
+    
+    if (!wallcycle_have_counter())
+    {
+        return NULL;
+    }
+
+    snew(wc,1);
+
+    wc->wc_barrier = FALSE;
+    wc->wcc_all    = NULL;
+    wc->wc_depth   = 0;
+    wc->ewc_prev   = -1;
+    wc->reset_counters = resetstep;
+
+#ifdef GMX_MPI
+    if (PAR(cr) && getenv("GMX_CYCLE_BARRIER") != NULL)
+    {
+        if (fplog) 
+        {
+            fprintf(fplog,"\nWill call MPI_Barrier before each cycle start/stop call\n\n");
+        }
+        wc->wc_barrier = TRUE;
+        wc->mpi_comm_mygroup = cr->mpi_comm_mygroup;
+    }
+#endif
+
+    snew(wc->wcc,ewcNR);
+    if (getenv("GMX_CYCLE_ALL") != NULL)
+    {
+/*#ifndef GMX_THREADS*/
+        if (fplog) 
+        {
+            fprintf(fplog,"\nWill time all the code during the run\n\n");
+        }
+        snew(wc->wcc_all,ewcNR*ewcNR);
+/*#else*/
+        gmx_fatal(FARGS, "GMX_CYCLE_ALL is incompatible with threaded code");
+/*#endif*/
+    }
+    
+    return wc;
+}
+
+void wallcycle_destroy(gmx_wallcycle_t wc)
+{
+    if (wc == NULL)
+    {
+        return;
+    }
+    
+    if (wc->wcc != NULL)
+    {
+        sfree(wc->wcc);
+    }
+    if (wc->wcc_all != NULL)
+    {
+        sfree(wc->wcc_all);
+    }
+    sfree(wc);
+}
+
+static void wallcycle_all_start(gmx_wallcycle_t wc,int ewc,gmx_cycles_t cycle)
+{
+    wc->ewc_prev = ewc;
+    wc->cycle_prev = cycle;
+}
+
+static void wallcycle_all_stop(gmx_wallcycle_t wc,int ewc,gmx_cycles_t cycle)
+{
+    wc->wcc_all[wc->ewc_prev*ewcNR+ewc].n += 1;
+    wc->wcc_all[wc->ewc_prev*ewcNR+ewc].c += cycle - wc->cycle_prev;
+}
+
+void wallcycle_start(gmx_wallcycle_t wc, int ewc)
+{
+    gmx_cycles_t cycle;
+
+    if (wc == NULL)
+    {
+        return;
+    }
+
+#ifdef GMX_MPI
+    if (wc->wc_barrier)
+    {
+        MPI_Barrier(wc->mpi_comm_mygroup);
+    }
+#endif
+
+    cycle = gmx_cycles_read();
+    wc->wcc[ewc].start = cycle;
+    if (wc->wcc_all != NULL)
+    {
+        wc->wc_depth++;
+        if (ewc == ewcRUN)
+        {
+            wallcycle_all_start(wc,ewc,cycle);
+        }
+        else if (wc->wc_depth == 3)
+        {
+            wallcycle_all_stop(wc,ewc,cycle);
+        }
+    }
+}
+
+double wallcycle_stop(gmx_wallcycle_t wc, int ewc)
+{
+    gmx_cycles_t cycle,last;
+    
+    if (wc == NULL)
+    {
+        return 0;
+    }
+    
+#ifdef GMX_MPI
+    if (wc->wc_barrier)
+    {
+        MPI_Barrier(wc->mpi_comm_mygroup);
+    }
+#endif
+    
+    cycle = gmx_cycles_read();
+    last = cycle - wc->wcc[ewc].start;
+    wc->wcc[ewc].c += last;
+    wc->wcc[ewc].n++;
+    if (wc->wcc_all)
+    {
+        wc->wc_depth--;
+        if (ewc == ewcRUN)
+        {
+            wallcycle_all_stop(wc,ewc,cycle);
+        }
+        else if (wc->wc_depth == 2)
+        {
+            wallcycle_all_start(wc,ewc,cycle);
+        }
+    }
+
+    return last;
+}
+
+void wallcycle_reset_all(gmx_wallcycle_t wc)
+{
+    int i;
+
+    if (wc == NULL)
+    {
+        return;
+    }
+
+    for(i=0; i<ewcNR; i++)
+    {
+        wc->wcc[i].n = 0;
+        wc->wcc[i].c = 0;
+        wc->wcc[i].start = 0;
+        wc->wcc[i].last = 0;
+    }
+}
+
+void wallcycle_sum(t_commrec *cr, gmx_wallcycle_t wc,double cycles[])
+{
+    wallcc_t *wcc;
+    double cycles_n[ewcNR],buf[ewcNR],*cyc_all,*buf_all;
+    int    i;
+
+    if (wc == NULL)
+    {
+        return;
+    }
+
+    wcc = wc->wcc;
+
+    if (wcc[ewcDDCOMMLOAD].n > 0)
+    {
+        wcc[ewcDOMDEC].c -= wcc[ewcDDCOMMLOAD].c;
+    }
+    if (wcc[ewcDDCOMMBOUND].n > 0)
+    {
+        wcc[ewcDOMDEC].c -= wcc[ewcDDCOMMBOUND].c;
+    }
+    if (cr->npmenodes == 0)
+    {
+        /* All nodes do PME (or no PME at all) */
+        if (wcc[ewcPMEMESH].n > 0)
+        {
+            wcc[ewcFORCE].c -= wcc[ewcPMEMESH].c;
+        }
+    }
+    else
+    {
+        /* The are PME-only nodes */
+        if (wcc[ewcPMEMESH].n > 0)
+        {
+            /* This must be a PME only node, calculate the Wait + Comm. time */
+            wcc[ewcPMEWAITCOMM].c = wcc[ewcRUN].c - wcc[ewcPMEMESH].c;
+        }
+    }
+    
+    /* Store the cycles in a double buffer for summing */
+    for(i=0; i<ewcNR; i++)
+    {
+        cycles_n[i] = (double)wcc[i].n;
+        cycles[i]   = (double)wcc[i].c;
+    }
+    
+#ifdef GMX_MPI
+    if (cr->nnodes > 1)
+    {
+        MPI_Allreduce(cycles_n,buf,ewcNR,MPI_DOUBLE,MPI_MAX,
+                      cr->mpi_comm_mysim);
+        for(i=0; i<ewcNR; i++)
+        {
+            wcc[i].n = (int)(buf[i] + 0.5);
+        }
+        MPI_Allreduce(cycles,buf,ewcNR,MPI_DOUBLE,MPI_SUM,
+                      cr->mpi_comm_mysim);
+        for(i=0; i<ewcNR; i++)
+        {
+            cycles[i] = buf[i];
+        }
+
+        if (wc->wcc_all != NULL)
+        {
+            snew(cyc_all,ewcNR*ewcNR);
+            snew(buf_all,ewcNR*ewcNR);
+            for(i=0; i<ewcNR*ewcNR; i++)
+            {
+                cyc_all[i] = wc->wcc_all[i].c;
+            }
+            MPI_Allreduce(cyc_all,buf_all,ewcNR*ewcNR,MPI_DOUBLE,MPI_SUM,
+                          cr->mpi_comm_mysim);
+            for(i=0; i<ewcNR*ewcNR; i++)
+            {
+                wc->wcc_all[i].c = buf_all[i];
+            }
+            sfree(buf_all);
+            sfree(cyc_all);
+        }
+    }
+#endif
+}
+
+static void print_cycles(FILE *fplog, double c2t, const char *name, int nnodes,
+                         int n, double c, double tot)
+{
+    char num[11];
+  
+    if (c > 0)
+    {
+        if (n > 0)
+        {
+            sprintf(num,"%10d",n);
+        }
+        else
+        {
+            sprintf(num,"          ");
+        }
+        fprintf(fplog," %-19s %4d %10s %12.3f %10.1f   %5.1f\n",
+                name,nnodes,num,c*1e-9,c*c2t,100*c/tot);
+    }
+}
+
+static gmx_bool subdivision(int ewc)
+{
+    return (ewc >= ewcPME_REDISTXF && ewc <= ewcPME_SOLVE);
+}
+
+void wallcycle_print(FILE *fplog, int nnodes, int npme, double realtime,
+                     gmx_wallcycle_t wc, double cycles[])
+{
+    double c2t,tot,sum;
+    int    i,j,npp;
+    char   buf[STRLEN];
+    const char *myline = "-----------------------------------------------------------------------";
+    
+    if (wc == NULL)
+    {
+        return;
+    }
+
+    if (npme > 0)
+    {
+        npp = nnodes - npme;
+    }
+    else
+    {
+        npp  = nnodes;
+        npme = nnodes;
+    }
+    tot = cycles[ewcRUN];
+    /* Conversion factor from cycles to seconds */
+    if (tot > 0)
+    {
+      c2t = nnodes*realtime/tot;
+    }
+    else
+    {
+      c2t = 0;
+    }
+
+    fprintf(fplog,"\n     R E A L   C Y C L E   A N D   T I M E   A C C O U N T I N G\n\n");
+
+    fprintf(fplog," Computing:         Nodes     Number     G-Cycles    Seconds     %c\n",'%');
+    fprintf(fplog,"%s\n",myline);
+    sum = 0;
+    for(i=ewcPPDURINGPME+1; i<ewcNR; i++)
+    {
+        if (!subdivision(i))
+        {
+            print_cycles(fplog,c2t,wcn[i],
+                         (i==ewcPMEMESH || i==ewcPMEWAITCOMM) ? npme : npp,
+                         wc->wcc[i].n,cycles[i],tot);
+            sum += cycles[i];
+        }
+    }
+    if (wc->wcc_all != NULL)
+    {
+        for(i=0; i<ewcNR; i++)
+        {
+            for(j=0; j<ewcNR; j++)
+            {
+                sprintf(buf,"%-9s",wcn[i]);
+                buf[9] = ' ';
+                sprintf(buf+10,"%-9s",wcn[j]);
+                buf[19] = '\0';
+                print_cycles(fplog,c2t,buf,
+                             (i==ewcPMEMESH || i==ewcPMEWAITCOMM) ? npme : npp,
+                             wc->wcc_all[i*ewcNR+j].n,
+                             wc->wcc_all[i*ewcNR+j].c,
+                             tot);
+            }
+        }
+    }
+    print_cycles(fplog,c2t,"Rest",npp,0,tot-sum,tot);
+    fprintf(fplog,"%s\n",myline);
+    print_cycles(fplog,c2t,"Total",nnodes,0,tot,tot);
+    fprintf(fplog,"%s\n",myline);
+    
+    if (wc->wcc[ewcPMEMESH].n > 0)
+    {
+        fprintf(fplog,"%s\n",myline);
+        for(i=ewcPPDURINGPME+1; i<ewcNR; i++)
+        {
+            if (subdivision(i))
+            {
+                print_cycles(fplog,c2t,wcn[i],
+                             (i>=ewcPMEMESH || i<=ewcPME_SOLVE) ? npme : npp,
+                             wc->wcc[i].n,cycles[i],tot);
+            }
+        }
+        fprintf(fplog,"%s\n",myline);
+    }
+
+    if (cycles[ewcMoveE] > tot*0.05)
+    {
+        sprintf(buf,
+                "NOTE: %d %% of the run time was spent communicating energies,\n"
+                "      you might want to use the -gcom option of mdrun\n",
+                (int)(100*cycles[ewcMoveE]/tot+0.5));
+        if (fplog)
+        {
+            fprintf(fplog,"\n%s\n",buf);
+        }
+        /* Only the sim master calls this function, so always print to stderr */
+        fprintf(stderr,"\n%s\n",buf);
+    }
+}
+
+extern gmx_large_int_t wcycle_get_reset_counters(gmx_wallcycle_t wc)
+{
+    if (wc == NULL)
+    {
+        return -1;
+    }
+    
+    return wc->reset_counters;
+}
+
+extern void wcycle_set_reset_counters(gmx_wallcycle_t wc, gmx_large_int_t reset_counters)
+{
+    if (wc == NULL)
+        return;
+
+    wc->reset_counters = reset_counters;
+}
similarity index 100%
rename from src/mdlib/init.c
rename to src/gromacs/mdlib/init.c
diff --git a/src/gromacs/mdlib/mdebin.c b/src/gromacs/mdlib/mdebin.c
new file mode 100644 (file)
index 0000000..394ca89
--- /dev/null
@@ -0,0 +1,1254 @@
+/* -*- 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
+ * 
+ *                        VERSION 3.2.0
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * 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.
+
+ * 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:
+ * GROwing Monsters And Cloning Shrimps
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <float.h>
+#include "typedefs.h"
+#include "string2.h"
+#include "mdebin.h"
+#include "smalloc.h"
+#include "physics.h"
+#include "enxio.h"
+#include "vec.h"
+#include "disre.h"
+#include "main.h"
+#include "network.h"
+#include "names.h"
+#include "orires.h"
+#include "constr.h"
+#include "mtop_util.h"
+#include "xvgr.h"
+#include "gmxfio.h"
+
+#include "mdebin_bar.h"
+
+
+static const char *conrmsd_nm[] = { "Constr. rmsd", "Constr.2 rmsd" };
+
+static const char *boxs_nm[] = { "Box-X", "Box-Y", "Box-Z" };
+
+static const char *tricl_boxs_nm[] = { 
+    "Box-XX", "Box-YY", "Box-ZZ",
+    "Box-YX", "Box-ZX", "Box-ZY" 
+};
+
+static const char *vol_nm[] = { "Volume" };
+
+static const char *dens_nm[] = {"Density" };
+
+static const char *pv_nm[] = {"pV" };
+
+static const char *enthalpy_nm[] = {"Enthalpy" };
+
+static const char *boxvel_nm[] = {
+    "Box-Vel-XX", "Box-Vel-YY", "Box-Vel-ZZ",
+    "Box-Vel-YX", "Box-Vel-ZX", "Box-Vel-ZY"
+};
+
+#define NBOXS asize(boxs_nm)
+#define NTRICLBOXS asize(tricl_boxs_nm)
+
+static gmx_bool bTricl,bDynBox;
+static int  f_nre=0,epc,etc,nCrmsd;
+
+
+
+
+
+t_mdebin *init_mdebin(ener_file_t fp_ene,
+                      const gmx_mtop_t *mtop,
+                      const t_inputrec *ir,
+                      FILE *fp_dhdl)
+{
+    const char *ener_nm[F_NRE];
+    static const char *vir_nm[] = {
+        "Vir-XX", "Vir-XY", "Vir-XZ",
+        "Vir-YX", "Vir-YY", "Vir-YZ",
+        "Vir-ZX", "Vir-ZY", "Vir-ZZ"
+    };
+    static const char *sv_nm[] = {
+        "ShakeVir-XX", "ShakeVir-XY", "ShakeVir-XZ",
+        "ShakeVir-YX", "ShakeVir-YY", "ShakeVir-YZ",
+        "ShakeVir-ZX", "ShakeVir-ZY", "ShakeVir-ZZ"
+    };
+    static const char *fv_nm[] = {
+        "ForceVir-XX", "ForceVir-XY", "ForceVir-XZ",
+        "ForceVir-YX", "ForceVir-YY", "ForceVir-YZ",
+        "ForceVir-ZX", "ForceVir-ZY", "ForceVir-ZZ"
+    };
+    static const char *pres_nm[] = {
+        "Pres-XX","Pres-XY","Pres-XZ",
+        "Pres-YX","Pres-YY","Pres-YZ",
+        "Pres-ZX","Pres-ZY","Pres-ZZ"
+    };
+    static const char *surft_nm[] = {
+        "#Surf*SurfTen"
+    };
+    static const char *mu_nm[] = {
+        "Mu-X", "Mu-Y", "Mu-Z"
+    };
+    static const char *vcos_nm[] = {
+        "2CosZ*Vel-X"
+    };
+    static const char *visc_nm[] = {
+        "1/Viscosity"
+    };
+    static const char *baro_nm[] = {
+        "Barostat"
+    };
+
+    char     **grpnms;
+    const gmx_groups_t *groups;
+    char     **gnm;
+    char     buf[256];
+    const char     *bufi;
+    t_mdebin *md;
+    int      i,j,ni,nj,n,nh,k,kk,ncon,nset;
+    gmx_bool     bBHAM,bNoseHoover,b14;
+
+    snew(md,1);
+
+    if (EI_DYNAMICS(ir->eI))
+    {
+        md->delta_t = ir->delta_t;
+    }
+    else
+    {
+        md->delta_t = 0;
+    }
+
+    groups = &mtop->groups;
+
+    bBHAM = (mtop->ffparams.functype[0] == F_BHAM);
+    b14   = (gmx_mtop_ftype_count(mtop,F_LJ14) > 0 ||
+             gmx_mtop_ftype_count(mtop,F_LJC14_Q) > 0);
+
+    ncon = gmx_mtop_ftype_count(mtop,F_CONSTR);
+    nset = gmx_mtop_ftype_count(mtop,F_SETTLE);
+    md->bConstr    = (ncon > 0 || nset > 0);
+    md->bConstrVir = FALSE;
+    if (md->bConstr) {
+        if (ncon > 0 && ir->eConstrAlg == econtLINCS) {
+            if (ir->eI == eiSD2)
+                md->nCrmsd = 2;
+            else
+                md->nCrmsd = 1;
+        }
+        md->bConstrVir = (getenv("GMX_CONSTRAINTVIR") != NULL);
+    } else {
+        md->nCrmsd = 0;
+    }
+
+    /* Energy monitoring */
+    for(i=0;i<egNR;i++)
+    {
+        md->bEInd[i]=FALSE;
+    }
+
+#ifndef GMX_OPENMM
+    for(i=0; i<F_NRE; i++)
+    {
+        md->bEner[i] = FALSE;
+        if (i == F_LJ)
+            md->bEner[i] = !bBHAM;
+        else if (i == F_BHAM)
+            md->bEner[i] = bBHAM;
+        else if (i == F_EQM)
+            md->bEner[i] = ir->bQMMM;
+        else if (i == F_COUL_LR)
+            md->bEner[i] = (ir->rcoulomb > ir->rlist);
+        else if (i == F_LJ_LR)
+            md->bEner[i] = (!bBHAM && ir->rvdw > ir->rlist);
+        else if (i == F_BHAM_LR)
+            md->bEner[i] = (bBHAM && ir->rvdw > ir->rlist);
+        else if (i == F_RF_EXCL)
+            md->bEner[i] = (EEL_RF(ir->coulombtype) && ir->coulombtype != eelRF_NEC);
+        else if (i == F_COUL_RECIP)
+            md->bEner[i] = EEL_FULL(ir->coulombtype);
+        else if (i == F_LJ14)
+            md->bEner[i] = b14;
+        else if (i == F_COUL14)
+            md->bEner[i] = b14;
+        else if (i == F_LJC14_Q || i == F_LJC_PAIRS_NB)
+            md->bEner[i] = FALSE;
+        else if ((i == F_DVDL) || (i == F_DKDL))
+            md->bEner[i] = (ir->efep != efepNO);
+        else if (i == F_DHDL_CON)
+            md->bEner[i] = (ir->efep != efepNO && md->bConstr);
+        else if ((interaction_function[i].flags & IF_VSITE) ||
+                 (i == F_CONSTR) || (i == F_CONSTRNC) || (i == F_SETTLE))
+            md->bEner[i] = FALSE;
+        else if ((i == F_COUL_SR) || (i == F_EPOT) || (i == F_PRES)  || (i==F_EQM))
+            md->bEner[i] = TRUE;
+        else if ((i == F_GBPOL) && ir->implicit_solvent==eisGBSA)
+            md->bEner[i] = TRUE;
+        else if ((i == F_NPSOLVATION) && ir->implicit_solvent==eisGBSA && (ir->sa_algorithm != esaNO))
+            md->bEner[i] = TRUE;
+        else if ((i == F_GB12) || (i == F_GB13) || (i == F_GB14))
+            md->bEner[i] = FALSE;
+        else if ((i == F_ETOT) || (i == F_EKIN) || (i == F_TEMP))
+            md->bEner[i] = EI_DYNAMICS(ir->eI);
+        else if (i==F_VTEMP) 
+            md->bEner[i] =  (EI_DYNAMICS(ir->eI) && getenv("GMX_VIRIAL_TEMPERATURE"));
+        else if (i == F_DISPCORR || i == F_PDISPCORR)
+            md->bEner[i] = (ir->eDispCorr != edispcNO);
+        else if (i == F_DISRESVIOL)
+            md->bEner[i] = (gmx_mtop_ftype_count(mtop,F_DISRES) > 0);
+        else if (i == F_ORIRESDEV)
+            md->bEner[i] = (gmx_mtop_ftype_count(mtop,F_ORIRES) > 0);
+        else if (i == F_CONNBONDS)
+            md->bEner[i] = FALSE;
+        else if (i == F_COM_PULL)
+            md->bEner[i] = (ir->ePull == epullUMBRELLA || ir->ePull == epullCONST_F || ir->bRot);
+        else if (i == F_ECONSERVED)
+            md->bEner[i] = ((ir->etc == etcNOSEHOOVER || ir->etc == etcVRESCALE) &&
+                            (ir->epc == epcNO || ir->epc==epcMTTK));
+        else
+            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
+
+    md->f_nre=0;
+    for(i=0; i<F_NRE; i++)
+    {
+        if (md->bEner[i])
+        {
+            /* FIXME: The constness should not be cast away */
+            /*ener_nm[f_nre]=(char *)interaction_function[i].longname;*/
+            ener_nm[md->f_nre]=interaction_function[i].longname;
+            md->f_nre++;
+        }
+    }
+
+    md->epc = ir->epc;
+    for (i=0;i<DIM;i++) 
+    {
+        for (j=0;j<DIM;j++) 
+        {
+            md->ref_p[i][j] = ir->ref_p[i][j];
+        }
+    }
+    md->bTricl = TRICLINIC(ir->compress) || TRICLINIC(ir->deform);
+    md->bDynBox = DYNAMIC_BOX(*ir);
+    md->etc = ir->etc;
+    md->bNHC_trotter = IR_NVT_TROTTER(ir);
+    md->bMTTK = IR_NPT_TROTTER(ir);
+
+    md->ebin  = mk_ebin();
+    /* Pass NULL for unit to let get_ebin_space determine the units
+     * for interaction_function[i].longname
+     */
+    md->ie    = get_ebin_space(md->ebin,md->f_nre,ener_nm,NULL);
+    if (md->nCrmsd)
+    {
+        /* This should be called directly after the call for md->ie,
+         * such that md->iconrmsd follows directly in the list.
+         */
+        md->iconrmsd = get_ebin_space(md->ebin,md->nCrmsd,conrmsd_nm,"");
+    }
+    if (md->bDynBox)
+    {
+        md->ib    = get_ebin_space(md->ebin, 
+                                   md->bTricl ? NTRICLBOXS : NBOXS, 
+                                   md->bTricl ? tricl_boxs_nm : boxs_nm,
+                                   unit_length);
+        md->ivol  = get_ebin_space(md->ebin, 1, vol_nm,  unit_volume);
+        md->idens = get_ebin_space(md->ebin, 1, dens_nm, unit_density_SI);
+        md->ipv   = get_ebin_space(md->ebin, 1, pv_nm,   unit_energy);
+        md->ienthalpy = get_ebin_space(md->ebin, 1, enthalpy_nm,   unit_energy);
+    }
+    if (md->bConstrVir)
+    {
+        md->isvir = get_ebin_space(md->ebin,asize(sv_nm),sv_nm,unit_energy);
+        md->ifvir = get_ebin_space(md->ebin,asize(fv_nm),fv_nm,unit_energy);
+    }
+    md->ivir   = get_ebin_space(md->ebin,asize(vir_nm),vir_nm,unit_energy);
+    md->ipres  = get_ebin_space(md->ebin,asize(pres_nm),pres_nm,unit_pres_bar);
+    md->isurft = get_ebin_space(md->ebin,asize(surft_nm),surft_nm,
+                                unit_surft_bar);
+    if (md->epc == epcPARRINELLORAHMAN || md->epc == epcMTTK)
+    {
+        md->ipc = get_ebin_space(md->ebin,md->bTricl ? 6 : 3,
+                                 boxvel_nm,unit_vel);
+    }
+    md->imu    = get_ebin_space(md->ebin,asize(mu_nm),mu_nm,unit_dipole_D);
+    if (ir->cos_accel != 0)
+    {
+        md->ivcos = get_ebin_space(md->ebin,asize(vcos_nm),vcos_nm,unit_vel);
+        md->ivisc = get_ebin_space(md->ebin,asize(visc_nm),visc_nm,
+                                   unit_invvisc_SI);
+    }
+
+    /* Energy monitoring */
+    for(i=0;i<egNR;i++)
+    {
+        md->bEInd[i] = FALSE;
+    }
+    md->bEInd[egCOULSR] = TRUE;
+    md->bEInd[egLJSR  ] = TRUE;
+
+    if (ir->rcoulomb > ir->rlist)
+    {
+        md->bEInd[egCOULLR] = TRUE;
+    }
+    if (!bBHAM)
+    {
+        if (ir->rvdw > ir->rlist)
+        {
+            md->bEInd[egLJLR]   = TRUE;
+        }
+    }
+    else
+    {
+        md->bEInd[egLJSR]   = FALSE;
+        md->bEInd[egBHAMSR] = TRUE;
+        if (ir->rvdw > ir->rlist)
+        {
+            md->bEInd[egBHAMLR]   = TRUE;
+        }
+    }
+    if (b14)
+    {
+        md->bEInd[egLJ14] = TRUE;
+        md->bEInd[egCOUL14] = TRUE;
+    }
+    md->nEc=0;
+    for(i=0; (i<egNR); i++)
+    {
+        if (md->bEInd[i])
+        {
+            md->nEc++;
+        }
+    }
+
+    n=groups->grps[egcENER].nr;
+    md->nEg=n;
+    md->nE=(n*(n+1))/2;
+    snew(md->igrp,md->nE);
+    if (md->nE > 1)
+    {
+        n=0;
+        snew(gnm,md->nEc);
+        for(k=0; (k<md->nEc); k++)
+        {
+            snew(gnm[k],STRLEN);
+        }
+        for(i=0; (i<groups->grps[egcENER].nr); i++)
+        {
+            ni=groups->grps[egcENER].nm_ind[i];
+            for(j=i; (j<groups->grps[egcENER].nr); j++)
+            {
+                nj=groups->grps[egcENER].nm_ind[j];
+                for(k=kk=0; (k<egNR); k++)
+                {
+                    if (md->bEInd[k])
+                    {
+                        sprintf(gnm[kk],"%s:%s-%s",egrp_nm[k],
+                                *(groups->grpname[ni]),*(groups->grpname[nj]));
+                        kk++;
+                    }
+                }
+                md->igrp[n]=get_ebin_space(md->ebin,md->nEc,
+                                           (const char **)gnm,unit_energy);
+                n++;
+            }
+        }
+        for(k=0; (k<md->nEc); k++)
+        {
+            sfree(gnm[k]);
+        }
+        sfree(gnm);
+
+        if (n != md->nE)
+        {
+            gmx_incons("Number of energy terms wrong");
+        }
+    }
+
+    md->nTC=groups->grps[egcTC].nr;
+    md->nNHC = ir->opts.nhchainlength; /* shorthand for number of NH chains */ 
+    if (md->bMTTK)
+    {
+        md->nTCP = 1;  /* assume only one possible coupling system for barostat 
+                          for now */
+    } 
+    else 
+    {
+        md->nTCP = 0;
+    }
+
+    if (md->etc == etcNOSEHOOVER) {
+        if (md->bNHC_trotter) { 
+            md->mde_n = 2*md->nNHC*md->nTC;
+        }
+        else 
+        {
+            md->mde_n = 2*md->nTC;
+        }
+        if (md->epc == epcMTTK)
+        {
+            md->mdeb_n = 2*md->nNHC*md->nTCP;
+        }
+    } else { 
+        md->mde_n = md->nTC;
+        md->mdeb_n = 0;
+    }
+
+    snew(md->tmp_r,md->mde_n);
+    snew(md->tmp_v,md->mde_n);
+    snew(md->grpnms,md->mde_n);
+    grpnms = md->grpnms;
+
+    for(i=0; (i<md->nTC); i++)
+    {
+        ni=groups->grps[egcTC].nm_ind[i];
+        sprintf(buf,"T-%s",*(groups->grpname[ni]));
+        grpnms[i]=strdup(buf);
+    }
+    md->itemp=get_ebin_space(md->ebin,md->nTC,(const char **)grpnms,
+                             unit_temp_K);
+
+    bNoseHoover = (getenv("GMX_NOSEHOOVER_CHAINS") != NULL); /* whether to print Nose-Hoover chains */
+
+    if (md->etc == etcNOSEHOOVER)
+    {
+        if (bNoseHoover) 
+        {
+            if (md->bNHC_trotter) 
+            {
+                for(i=0; (i<md->nTC); i++) 
+                {
+                    ni=groups->grps[egcTC].nm_ind[i];
+                    bufi = *(groups->grpname[ni]);
+                    for(j=0; (j<md->nNHC); j++) 
+                    {
+                        sprintf(buf,"Xi-%d-%s",j,bufi);
+                        grpnms[2*(i*md->nNHC+j)]=strdup(buf);
+                        sprintf(buf,"vXi-%d-%s",j,bufi);
+                        grpnms[2*(i*md->nNHC+j)+1]=strdup(buf);
+                    }
+                }
+                md->itc=get_ebin_space(md->ebin,md->mde_n,
+                                       (const char **)grpnms,unit_invtime);
+                if (md->bMTTK) 
+                {
+                    for(i=0; (i<md->nTCP); i++) 
+                    {
+                        bufi = baro_nm[0];  /* All barostat DOF's together for now. */
+                        for(j=0; (j<md->nNHC); j++) 
+                        {
+                            sprintf(buf,"Xi-%d-%s",j,bufi);
+                            grpnms[2*(i*md->nNHC+j)]=strdup(buf);
+                            sprintf(buf,"vXi-%d-%s",j,bufi);
+                            grpnms[2*(i*md->nNHC+j)+1]=strdup(buf);
+                        }
+                    }
+                    md->itcb=get_ebin_space(md->ebin,md->mdeb_n,
+                                            (const char **)grpnms,unit_invtime);
+                }
+            } 
+            else
+            {
+                for(i=0; (i<md->nTC); i++) 
+                {
+                    ni=groups->grps[egcTC].nm_ind[i];
+                    bufi = *(groups->grpname[ni]);
+                    sprintf(buf,"Xi-%s",bufi);
+                    grpnms[2*i]=strdup(buf);
+                    sprintf(buf,"vXi-%s",bufi);
+                    grpnms[2*i+1]=strdup(buf);
+                }
+                md->itc=get_ebin_space(md->ebin,md->mde_n,
+                                       (const char **)grpnms,unit_invtime);
+            }
+        }
+    }
+    else if (md->etc == etcBERENDSEN || md->etc == etcYES || 
+             md->etc == etcVRESCALE)
+    {
+        for(i=0; (i<md->nTC); i++)
+        {
+            ni=groups->grps[egcTC].nm_ind[i];
+            sprintf(buf,"Lamb-%s",*(groups->grpname[ni]));
+            grpnms[i]=strdup(buf);
+        }
+        md->itc=get_ebin_space(md->ebin,md->mde_n,(const char **)grpnms,"");
+    }
+
+    sfree(grpnms);
+
+
+    md->nU=groups->grps[egcACC].nr;
+    if (md->nU > 1)
+    {
+        snew(grpnms,3*md->nU);
+        for(i=0; (i<md->nU); i++)
+        {
+            ni=groups->grps[egcACC].nm_ind[i];
+            sprintf(buf,"Ux-%s",*(groups->grpname[ni]));
+            grpnms[3*i+XX]=strdup(buf);
+            sprintf(buf,"Uy-%s",*(groups->grpname[ni]));
+            grpnms[3*i+YY]=strdup(buf);
+            sprintf(buf,"Uz-%s",*(groups->grpname[ni]));
+            grpnms[3*i+ZZ]=strdup(buf);
+        }
+        md->iu=get_ebin_space(md->ebin,3*md->nU,(const char **)grpnms,unit_vel);
+        sfree(grpnms);
+    }
+
+    if ( fp_ene )
+    {
+        do_enxnms(fp_ene,&md->ebin->nener,&md->ebin->enm);
+    }
+
+    md->print_grpnms=NULL;
+
+    /* check whether we're going to write dh histograms */
+    md->dhc=NULL; 
+    if (ir->separate_dhdl_file == sepdhdlfileNO )
+    {
+        int i;
+        snew(md->dhc, 1);
+
+        mde_delta_h_coll_init(md->dhc, ir);
+        md->fp_dhdl = NULL;
+    }
+    else
+    {
+        md->fp_dhdl = fp_dhdl;
+    }
+    md->dhdl_derivatives = (ir->dhdl_derivatives==dhdlderivativesYES);
+    return md;
+}
+
+FILE *open_dhdl(const char *filename,const t_inputrec *ir,
+                const output_env_t oenv)
+{
+    FILE *fp;
+    const char *dhdl="dH/d\\lambda",*deltag="\\DeltaH",*lambda="\\lambda";
+    char title[STRLEN],label_x[STRLEN],label_y[STRLEN];
+    char **setname;
+    char buf[STRLEN];
+
+    sprintf(label_x,"%s (%s)","Time",unit_time);
+    if (ir->n_flambda == 0)
+    {
+        sprintf(title,"%s",dhdl);
+        sprintf(label_y,"%s (%s %s)",
+                dhdl,unit_energy,"[\\lambda]\\S-1\\N");
+    }
+    else
+    {
+        sprintf(title,"%s, %s",dhdl,deltag);
+        sprintf(label_y,"(%s)",unit_energy);
+    }
+    fp = gmx_fio_fopen(filename,"w+");
+    xvgr_header(fp,title,label_x,label_y,exvggtXNY,oenv);
+
+    if (ir->delta_lambda == 0)
+    {
+        sprintf(buf,"T = %g (K), %s = %g",
+                ir->opts.ref_t[0],lambda,ir->init_lambda);
+    }
+    else
+    {
+        sprintf(buf,"T = %g (K)",
+                ir->opts.ref_t[0]);
+    }
+    xvgr_subtitle(fp,buf,oenv);
+
+    if (ir->n_flambda > 0)
+    {
+        int nsets,s,nsi=0;
+        /* g_bar has to determine the lambda values used in this simulation
+         * from this xvg legend.  */
+        nsets = ( (ir->dhdl_derivatives==dhdlderivativesYES) ? 1 : 0) + 
+                  ir->n_flambda;
+        snew(setname,nsets);
+        if (ir->dhdl_derivatives == dhdlderivativesYES)
+        {
+            sprintf(buf,"%s %s %g",dhdl,lambda,ir->init_lambda);
+            setname[nsi++] = strdup(buf);
+        }
+        for(s=0; s<ir->n_flambda; s++)
+        {
+            sprintf(buf,"%s %s %g",deltag,lambda,ir->flambda[s]);
+            setname[nsi++] = strdup(buf);
+        }
+        xvgr_legend(fp,nsets,(const char**)setname,oenv);
+
+        for(s=0; s<nsets; s++)
+        {
+            sfree(setname[s]);
+        }
+        sfree(setname);
+    }
+
+    return fp;
+}
+
+static void copy_energy(t_mdebin *md, real e[],real ecpy[])
+{
+    int i,j;
+
+    for(i=j=0; (i<F_NRE); i++)
+        if (md->bEner[i])
+            ecpy[j++] = e[i];
+    if (j != md->f_nre) 
+        gmx_incons("Number of energy terms wrong");
+}
+
+void upd_mdebin(t_mdebin *md, gmx_bool write_dhdl,
+                gmx_bool bSum,
+                double time,
+                real tmass,
+                gmx_enerdata_t *enerd,
+                t_state *state,
+                matrix  box,
+                tensor svir,
+                tensor fvir,
+                tensor vir,
+                tensor pres,
+                gmx_ekindata_t *ekind,
+                rvec mu_tot,
+                gmx_constr_t constr)
+{
+    int    i,j,k,kk,m,n,gid;
+    real   crmsd[2],tmp6[6];
+    real   bs[NTRICLBOXS],vol,dens,pv,enthalpy;
+    real   eee[egNR];
+    real   ecopy[F_NRE];
+    real   tmp;
+    gmx_bool   bNoseHoover;
+
+    /* Do NOT use the box in the state variable, but the separate box provided
+     * as an argument. This is because we sometimes need to write the box from
+     * the last timestep to match the trajectory frames.
+     */
+    copy_energy(md, enerd->term,ecopy);
+    add_ebin(md->ebin,md->ie,md->f_nre,ecopy,bSum);
+    if (md->nCrmsd)
+    {
+        crmsd[0] = constr_rmsd(constr,FALSE);
+        if (md->nCrmsd > 1)
+        {
+            crmsd[1] = constr_rmsd(constr,TRUE);
+        }
+        add_ebin(md->ebin,md->iconrmsd,md->nCrmsd,crmsd,FALSE);
+    }
+    if (md->bDynBox)
+    {
+        int nboxs;
+        if(md->bTricl)
+        {
+            bs[0] = box[XX][XX];
+            bs[1] = box[YY][YY];
+            bs[2] = box[ZZ][ZZ];
+            bs[3] = box[YY][XX];
+            bs[4] = box[ZZ][XX];
+            bs[5] = box[ZZ][YY];
+            nboxs=NTRICLBOXS;
+        }
+        else
+        {
+            bs[0] = box[XX][XX];
+            bs[1] = box[YY][YY];
+            bs[2] = box[ZZ][ZZ];
+            nboxs=NBOXS;
+        }
+        vol  = box[XX][XX]*box[YY][YY]*box[ZZ][ZZ];
+        dens = (tmass*AMU)/(vol*NANO*NANO*NANO);
+
+        /* This is pV (in kJ/mol).  The pressure is the reference pressure,
+           not the instantaneous pressure */  
+        pv = 0;
+        for (i=0;i<DIM;i++) 
+        {
+            for (j=0;j<DIM;j++) 
+            {
+                if (i>j) 
+                {
+                    pv += box[i][j]*md->ref_p[i][j]/PRESFAC;
+                } 
+                else 
+                {
+                    pv += box[j][i]*md->ref_p[j][i]/PRESFAC;
+                }
+            }
+        }
+
+        add_ebin(md->ebin,md->ib   ,nboxs,bs   ,bSum);
+        add_ebin(md->ebin,md->ivol ,1    ,&vol ,bSum);
+        add_ebin(md->ebin,md->idens,1    ,&dens,bSum);
+        add_ebin(md->ebin,md->ipv  ,1    ,&pv  ,bSum);
+        enthalpy = pv + enerd->term[F_ETOT];
+        add_ebin(md->ebin,md->ienthalpy  ,1    ,&enthalpy  ,bSum);
+    }
+    if (md->bConstrVir)
+    {
+        add_ebin(md->ebin,md->isvir,9,svir[0],bSum);
+        add_ebin(md->ebin,md->ifvir,9,fvir[0],bSum);
+    }
+    add_ebin(md->ebin,md->ivir,9,vir[0],bSum);
+    add_ebin(md->ebin,md->ipres,9,pres[0],bSum);
+    tmp = (pres[ZZ][ZZ]-(pres[XX][XX]+pres[YY][YY])*0.5)*box[ZZ][ZZ];
+    add_ebin(md->ebin,md->isurft,1,&tmp,bSum);
+    if (md->epc == epcPARRINELLORAHMAN || md->epc == epcMTTK)
+    {
+        tmp6[0] = state->boxv[XX][XX];
+        tmp6[1] = state->boxv[YY][YY];
+        tmp6[2] = state->boxv[ZZ][ZZ];
+        tmp6[3] = state->boxv[YY][XX];
+        tmp6[4] = state->boxv[ZZ][XX];
+        tmp6[5] = state->boxv[ZZ][YY];
+        add_ebin(md->ebin,md->ipc,md->bTricl ? 6 : 3,tmp6,bSum);
+    }
+    add_ebin(md->ebin,md->imu,3,mu_tot,bSum);
+    if (ekind && ekind->cosacc.cos_accel != 0)
+    {
+        vol  = box[XX][XX]*box[YY][YY]*box[ZZ][ZZ];
+        dens = (tmass*AMU)/(vol*NANO*NANO*NANO);
+        add_ebin(md->ebin,md->ivcos,1,&(ekind->cosacc.vcos),bSum);
+        /* 1/viscosity, unit 1/(kg m^-1 s^-1) */
+        tmp = 1/(ekind->cosacc.cos_accel/(ekind->cosacc.vcos*PICO)
+                 *vol*sqr(box[ZZ][ZZ]*NANO/(2*M_PI)));
+        add_ebin(md->ebin,md->ivisc,1,&tmp,bSum);    
+    }
+    if (md->nE > 1)
+    {
+        n=0;
+        for(i=0; (i<md->nEg); i++)
+        {
+            for(j=i; (j<md->nEg); j++)
+            {
+                gid=GID(i,j,md->nEg);
+                for(k=kk=0; (k<egNR); k++)
+                {
+                    if (md->bEInd[k])
+                    {
+                        eee[kk++] = enerd->grpp.ener[k][gid];
+                    }
+                }
+                add_ebin(md->ebin,md->igrp[n],md->nEc,eee,bSum);
+                n++;
+            }
+        }
+    }
+
+    if (ekind)
+    {
+        for(i=0; (i<md->nTC); i++)
+        {
+            md->tmp_r[i] = ekind->tcstat[i].T;
+        }
+        add_ebin(md->ebin,md->itemp,md->nTC,md->tmp_r,bSum);
+
+        /* whether to print Nose-Hoover chains: */
+        bNoseHoover = (getenv("GMX_NOSEHOOVER_CHAINS") != NULL); 
+
+        if (md->etc == etcNOSEHOOVER)
+        {
+            if (bNoseHoover) 
+            {
+                if (md->bNHC_trotter)
+                {
+                    for(i=0; (i<md->nTC); i++) 
+                    {
+                        for (j=0;j<md->nNHC;j++) 
+                        {
+                            k = i*md->nNHC+j;
+                            md->tmp_r[2*k] = state->nosehoover_xi[k];
+                            md->tmp_r[2*k+1] = state->nosehoover_vxi[k];
+                        }
+                    }
+                    add_ebin(md->ebin,md->itc,md->mde_n,md->tmp_r,bSum);      
+
+                    if (md->bMTTK) {
+                        for(i=0; (i<md->nTCP); i++) 
+                        {
+                            for (j=0;j<md->nNHC;j++) 
+                            {
+                                k = i*md->nNHC+j;
+                                md->tmp_r[2*k] = state->nhpres_xi[k];
+                                md->tmp_r[2*k+1] = state->nhpres_vxi[k];
+                            }
+                        }
+                        add_ebin(md->ebin,md->itcb,md->mdeb_n,md->tmp_r,bSum);      
+                    }
+
+                } 
+                else 
+                {
+                    for(i=0; (i<md->nTC); i++)
+                    {
+                        md->tmp_r[2*i] = state->nosehoover_xi[i];
+                        md->tmp_r[2*i+1] = state->nosehoover_vxi[i];
+                    }
+                    add_ebin(md->ebin,md->itc,md->mde_n,md->tmp_r,bSum);
+                }
+            }
+        }
+        else if (md->etc == etcBERENDSEN || md->etc == etcYES || 
+                 md->etc == etcVRESCALE)
+        {
+            for(i=0; (i<md->nTC); i++)
+            {
+                md->tmp_r[i] = ekind->tcstat[i].lambda;
+            }
+            add_ebin(md->ebin,md->itc,md->nTC,md->tmp_r,bSum);
+        }
+    }
+
+    if (ekind && md->nU > 1)
+    {
+        for(i=0; (i<md->nU); i++)
+        {
+            copy_rvec(ekind->grpstat[i].u,md->tmp_v[i]);
+        }
+        add_ebin(md->ebin,md->iu,3*md->nU,md->tmp_v[0],bSum);
+    }
+
+    ebin_increase_count(md->ebin,bSum);
+
+    /* BAR + thermodynamic integration values */
+    if (write_dhdl)
+    {
+        if (md->fp_dhdl)
+        {
+            fprintf(md->fp_dhdl,"%.4f", time);
+
+            if (md->dhdl_derivatives)
+            {
+                fprintf(md->fp_dhdl," %g", enerd->term[F_DVDL]+ 
+                                           enerd->term[F_DKDL]+
+                                           enerd->term[F_DHDL_CON]);
+            }
+            for(i=1; i<enerd->n_lambda; i++)
+            {
+                fprintf(md->fp_dhdl," %g",
+                        enerd->enerpart_lambda[i]-enerd->enerpart_lambda[0]);
+            }
+            fprintf(md->fp_dhdl,"\n");
+        }
+        /* and the binary BAR output */
+        if (md->dhc)
+        {
+            mde_delta_h_coll_add_dh(md->dhc, 
+                                    enerd->term[F_DVDL]+ enerd->term[F_DKDL]+
+                                    enerd->term[F_DHDL_CON],
+                                    enerd->enerpart_lambda, time, 
+                                    state->lambda);
+        }
+    }
+}
+
+void upd_mdebin_step(t_mdebin *md)
+{
+    ebin_increase_count(md->ebin,FALSE); 
+}
+
+static void npr(FILE *log,int n,char c)
+{
+    for(; (n>0); n--) fprintf(log,"%c",c);
+}
+
+static void pprint(FILE *log,const char *s,t_mdebin *md)
+{
+    char CHAR='#';
+    int  slen;
+    char buf1[22],buf2[22];
+
+    slen = strlen(s);
+    fprintf(log,"\t<======  ");
+    npr(log,slen,CHAR);
+    fprintf(log,"  ==>\n");
+    fprintf(log,"\t<====  %s  ====>\n",s);
+    fprintf(log,"\t<==  ");
+    npr(log,slen,CHAR);
+    fprintf(log,"  ======>\n\n");
+
+    fprintf(log,"\tStatistics over %s steps using %s frames\n",
+            gmx_step_str(md->ebin->nsteps_sim,buf1),
+            gmx_step_str(md->ebin->nsum_sim,buf2));
+    fprintf(log,"\n");
+}
+
+void print_ebin_header(FILE *log,gmx_large_int_t steps,double time,real lamb)
+{
+    char buf[22];
+
+    fprintf(log,"   %12s   %12s   %12s\n"
+            "   %12s   %12.5f   %12.5f\n\n",
+            "Step","Time","Lambda",gmx_step_str(steps,buf),time,lamb);
+}
+
+void print_ebin(ener_file_t fp_ene,gmx_bool bEne,gmx_bool bDR,gmx_bool bOR,
+                FILE *log,
+                gmx_large_int_t step,double time,
+                int mode,gmx_bool bCompact,
+                t_mdebin *md,t_fcdata *fcd,
+                gmx_groups_t *groups,t_grpopts *opts)
+{
+    /*static char **grpnms=NULL;*/
+    char        buf[246];
+    int         i,j,n,ni,nj,ndr,nor,b;
+    int         ndisre=0;
+    real        *disre_rm3tav, *disre_rt;
+
+    /* these are for the old-style blocks (1 subblock, only reals), because
+       there can be only one per ID for these */
+    int         nr[enxNR];
+    int         id[enxNR];
+    real        *block[enxNR];
+
+    /* temporary arrays for the lambda values to write out */
+    double      enxlambda_data[2]; 
+
+    t_enxframe  fr;
+
+    switch (mode)
+    {
+        case eprNORMAL:
+            init_enxframe(&fr);
+            fr.t            = time;
+            fr.step         = step;
+            fr.nsteps       = md->ebin->nsteps;
+            fr.dt           = md->delta_t;
+            fr.nsum         = md->ebin->nsum;
+            fr.nre          = (bEne) ? md->ebin->nener : 0;
+            fr.ener         = md->ebin->e;
+            ndisre          = bDR ? fcd->disres.npair : 0;
+            disre_rm3tav    = fcd->disres.rm3tav;
+            disre_rt        = fcd->disres.rt;
+            /* Optional additional old-style (real-only) blocks. */
+            for(i=0; i<enxNR; i++)
+            {
+                nr[i] = 0;
+            }
+            if (fcd->orires.nr > 0 && bOR)
+            {
+                diagonalize_orires_tensors(&(fcd->orires));
+                nr[enxOR]     = fcd->orires.nr;
+                block[enxOR]  = fcd->orires.otav;
+                id[enxOR]     = enxOR;
+                nr[enxORI]    = (fcd->orires.oinsl != fcd->orires.otav) ? 
+                          fcd->orires.nr : 0;
+                block[enxORI] = fcd->orires.oinsl;
+                id[enxORI]    = enxORI;
+                nr[enxORT]    = fcd->orires.nex*12;
+                block[enxORT] = fcd->orires.eig;
+                id[enxORT]    = enxORT;
+            }        
+
+            /* whether we are going to wrte anything out: */
+            if (fr.nre || ndisre || nr[enxOR] || nr[enxORI])
+            {
+
+                /* the old-style blocks go first */
+                fr.nblock = 0;
+                for(i=0; i<enxNR; i++)
+                {
+                    if (nr[i] > 0)
+                    {
+                        fr.nblock = i + 1;
+                    }
+                }
+                add_blocks_enxframe(&fr, fr.nblock);
+                for(b=0;b<fr.nblock;b++)
+                {
+                    add_subblocks_enxblock(&(fr.block[b]), 1);
+                    fr.block[b].id=id[b]; 
+                    fr.block[b].sub[0].nr = nr[b];
+#ifndef GMX_DOUBLE
+                    fr.block[b].sub[0].type = xdr_datatype_float;
+                    fr.block[b].sub[0].fval = block[b];
+#else
+                    fr.block[b].sub[0].type = xdr_datatype_double;
+                    fr.block[b].sub[0].dval = block[b];
+#endif
+                }
+
+                /* check for disre block & fill it. */
+                if (ndisre>0)
+                {
+                    int db = fr.nblock;
+                    fr.nblock+=1;
+                    add_blocks_enxframe(&fr, fr.nblock);
+
+                    add_subblocks_enxblock(&(fr.block[db]), 2);
+                    fr.block[db].id=enxDISRE;
+                    fr.block[db].sub[0].nr=ndisre;
+                    fr.block[db].sub[1].nr=ndisre;
+#ifndef GMX_DOUBLE
+                    fr.block[db].sub[0].type=xdr_datatype_float;
+                    fr.block[db].sub[1].type=xdr_datatype_float;
+                    fr.block[db].sub[0].fval=disre_rt;
+                    fr.block[db].sub[1].fval=disre_rm3tav;
+#else
+                    fr.block[db].sub[0].type=xdr_datatype_double;
+                    fr.block[db].sub[1].type=xdr_datatype_double;
+                    fr.block[db].sub[0].dval=disre_rt;
+                    fr.block[db].sub[1].dval=disre_rm3tav;
+#endif
+                }
+                /* here we can put new-style blocks */
+
+                /* Free energy perturbation blocks */
+                if (md->dhc)
+                {
+                    mde_delta_h_coll_handle_block(md->dhc, &fr, fr.nblock);
+                }
+
+                /* do the actual I/O */
+                do_enx(fp_ene,&fr);
+                gmx_fio_check_file_position(enx_file_pointer(fp_ene));
+                if (fr.nre)
+                {
+                    /* We have stored the sums, so reset the sum history */
+                    reset_ebin_sums(md->ebin);
+                }
+
+                /* we can now free & reset the data in the blocks */
+                if (md->dhc)
+                    mde_delta_h_coll_reset(md->dhc);
+            }
+            free_enxframe(&fr);
+            break;
+        case eprAVER:
+            if (log)
+            {
+                pprint(log,"A V E R A G E S",md);
+            }
+            break;
+        case eprRMS:
+            if (log)
+            {
+                pprint(log,"R M S - F L U C T U A T I O N S",md);
+            }
+            break;
+        default:
+            gmx_fatal(FARGS,"Invalid print mode (%d)",mode);
+    }
+
+    if (log)
+    {
+        for(i=0;i<opts->ngtc;i++)
+        {
+            if(opts->annealing[i]!=eannNO)
+            {
+                fprintf(log,"Current ref_t for group %s: %8.1f\n",
+                        *(groups->grpname[groups->grps[egcTC].nm_ind[i]]),
+                        opts->ref_t[i]);
+            }
+        }
+        if (mode==eprNORMAL && fcd->orires.nr>0)
+        {
+            print_orires_log(log,&(fcd->orires));
+        }
+        fprintf(log,"   Energies (%s)\n",unit_energy);
+        pr_ebin(log,md->ebin,md->ie,md->f_nre+md->nCrmsd,5,mode,TRUE);  
+        fprintf(log,"\n");
+
+        if (!bCompact)
+        {
+            if (md->bDynBox)
+            {
+                pr_ebin(log,md->ebin,md->ib, md->bTricl ? NTRICLBOXS : NBOXS,5,
+                        mode,TRUE);      
+                fprintf(log,"\n");
+            }
+            if (md->bConstrVir)
+            {
+                fprintf(log,"   Constraint Virial (%s)\n",unit_energy);
+                pr_ebin(log,md->ebin,md->isvir,9,3,mode,FALSE);  
+                fprintf(log,"\n");
+                fprintf(log,"   Force Virial (%s)\n",unit_energy);
+                pr_ebin(log,md->ebin,md->ifvir,9,3,mode,FALSE);  
+                fprintf(log,"\n");
+            }
+            fprintf(log,"   Total Virial (%s)\n",unit_energy);
+            pr_ebin(log,md->ebin,md->ivir,9,3,mode,FALSE);   
+            fprintf(log,"\n");
+            fprintf(log,"   Pressure (%s)\n",unit_pres_bar);
+            pr_ebin(log,md->ebin,md->ipres,9,3,mode,FALSE);  
+            fprintf(log,"\n");
+            fprintf(log,"   Total Dipole (%s)\n",unit_dipole_D);
+            pr_ebin(log,md->ebin,md->imu,3,3,mode,FALSE);    
+            fprintf(log,"\n");
+
+            if (md->nE > 1)
+            {
+                if (md->print_grpnms==NULL)
+                {
+                    snew(md->print_grpnms,md->nE);
+                    n=0;
+                    for(i=0; (i<md->nEg); i++)
+                    {
+                        ni=groups->grps[egcENER].nm_ind[i];
+                        for(j=i; (j<md->nEg); j++)
+                        {
+                            nj=groups->grps[egcENER].nm_ind[j];
+                            sprintf(buf,"%s-%s",*(groups->grpname[ni]),
+                                    *(groups->grpname[nj]));
+                            md->print_grpnms[n++]=strdup(buf);
+                        }
+                    }
+                }
+                sprintf(buf,"Epot (%s)",unit_energy);
+                fprintf(log,"%15s   ",buf);
+                for(i=0; (i<egNR); i++)
+                {
+                    if (md->bEInd[i])
+                    {
+                        fprintf(log,"%12s   ",egrp_nm[i]);
+                    }
+                }
+                fprintf(log,"\n");
+                for(i=0; (i<md->nE); i++)
+                {
+                    fprintf(log,"%15s",md->print_grpnms[i]);
+                    pr_ebin(log,md->ebin,md->igrp[i],md->nEc,md->nEc,mode,
+                            FALSE);
+                }
+                fprintf(log,"\n");
+            }
+            if (md->nTC > 1)
+            {
+                pr_ebin(log,md->ebin,md->itemp,md->nTC,4,mode,TRUE);
+                fprintf(log,"\n");
+            }
+            if (md->nU > 1)
+            {
+                fprintf(log,"%15s   %12s   %12s   %12s\n",
+                        "Group","Ux","Uy","Uz");
+                for(i=0; (i<md->nU); i++)
+                {
+                    ni=groups->grps[egcACC].nm_ind[i];
+                    fprintf(log,"%15s",*groups->grpname[ni]);
+                    pr_ebin(log,md->ebin,md->iu+3*i,3,3,mode,FALSE);
+                }
+                fprintf(log,"\n");
+            }
+        }
+    }
+
+}
+
+void update_energyhistory(energyhistory_t * enerhist,t_mdebin * mdebin)
+{
+    int i;
+
+    enerhist->nsteps     = mdebin->ebin->nsteps;
+    enerhist->nsum       = mdebin->ebin->nsum;
+    enerhist->nsteps_sim = mdebin->ebin->nsteps_sim;
+    enerhist->nsum_sim   = mdebin->ebin->nsum_sim;
+    enerhist->nener      = mdebin->ebin->nener;
+
+    if (mdebin->ebin->nsum > 0)
+    {
+        /* Check if we need to allocate first */
+        if(enerhist->ener_ave == NULL)
+        {
+            snew(enerhist->ener_ave,enerhist->nener);
+            snew(enerhist->ener_sum,enerhist->nener);
+        }
+
+        for(i=0;i<enerhist->nener;i++)
+        {
+            enerhist->ener_ave[i] = mdebin->ebin->e[i].eav;
+            enerhist->ener_sum[i] = mdebin->ebin->e[i].esum;
+        }
+    }
+
+    if (mdebin->ebin->nsum_sim > 0)
+    {
+        /* Check if we need to allocate first */
+        if(enerhist->ener_sum_sim == NULL)
+        {
+            snew(enerhist->ener_sum_sim,enerhist->nener);
+        }
+
+        for(i=0;i<enerhist->nener;i++)
+        {
+            enerhist->ener_sum_sim[i] = mdebin->ebin->e_sim[i].esum;
+        }
+    }
+    if (mdebin->dhc)
+    {
+        mde_delta_h_coll_update_energyhistory(mdebin->dhc, enerhist);
+    }
+}
+
+void restore_energyhistory_from_state(t_mdebin * mdebin,
+                                      energyhistory_t * enerhist)
+{
+    int i;
+
+    if ((enerhist->nsum > 0 || enerhist->nsum_sim > 0) &&
+        mdebin->ebin->nener != enerhist->nener)
+    {
+        gmx_fatal(FARGS,"Mismatch between number of energies in run input (%d) and checkpoint file (%d).",
+                  mdebin->ebin->nener,enerhist->nener);
+    }
+
+    mdebin->ebin->nsteps     = enerhist->nsteps;
+    mdebin->ebin->nsum       = enerhist->nsum;
+    mdebin->ebin->nsteps_sim = enerhist->nsteps_sim;
+    mdebin->ebin->nsum_sim   = enerhist->nsum_sim;
+
+    for(i=0; i<mdebin->ebin->nener; i++)
+    {
+        mdebin->ebin->e[i].eav  =
+                  (enerhist->nsum > 0 ? enerhist->ener_ave[i] : 0);
+        mdebin->ebin->e[i].esum =
+                  (enerhist->nsum > 0 ? enerhist->ener_sum[i] : 0);
+        mdebin->ebin->e_sim[i].esum =
+                  (enerhist->nsum_sim > 0 ? enerhist->ener_sum_sim[i] : 0);
+    }
+    if (mdebin->dhc)
+    {         
+        mde_delta_h_coll_restore_energyhistory(mdebin->dhc, enerhist);
+    }
+}
diff --git a/src/gromacs/mdlib/minimize.c b/src/gromacs/mdlib/minimize.c
new file mode 100644 (file)
index 0000000..c11481d
--- /dev/null
@@ -0,0 +1,2516 @@
+/* -*- 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
+ * 
+ *                        VERSION 3.2.0
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * 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.
+
+ * 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:
+ * GROwing Monsters And Cloning Shrimps
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <time.h>
+#include <math.h>
+#include "sysstuff.h"
+#include "string2.h"
+#include "network.h"
+#include "confio.h"
+#include "copyrite.h"
+#include "smalloc.h"
+#include "nrnb.h"
+#include "main.h"
+#include "force.h"
+#include "macros.h"
+#include "random.h"
+#include "names.h"
+#include "gmx_fatal.h"
+#include "txtdump.h"
+#include "typedefs.h"
+#include "update.h"
+#include "constr.h"
+#include "vec.h"
+#include "statutil.h"
+#include "tgroup.h"
+#include "mdebin.h"
+#include "vsite.h"
+#include "force.h"
+#include "mdrun.h"
+#include "domdec.h"
+#include "partdec.h"
+#include "trnio.h"
+#include "sparsematrix.h"
+#include "mtxio.h"
+#include "mdatoms.h"
+#include "ns.h"
+#include "gmx_wallcycle.h"
+#include "mtop_util.h"
+#include "gmxfio.h"
+#include "pme.h"
+#include "membed.h"
+
+typedef struct {
+  t_state s;
+  rvec    *f;
+  real    epot;
+  real    fnorm;
+  real    fmax;
+  int     a_fmax;
+} em_state_t;
+
+static em_state_t *init_em_state()
+{
+  em_state_t *ems;
+  
+  snew(ems,1);
+
+  return ems;
+}
+
+static void print_em_start(FILE *fplog,t_commrec *cr,gmx_runtime_t *runtime,
+                           gmx_wallcycle_t wcycle,
+                           const char *name)
+{
+    char buf[STRLEN];
+
+    runtime_start(runtime);
+
+    sprintf(buf,"Started %s",name);
+    print_date_and_time(fplog,cr->nodeid,buf,NULL);
+
+    wallcycle_start(wcycle,ewcRUN);
+}
+static void em_time_end(FILE *fplog,t_commrec *cr,gmx_runtime_t *runtime,
+                        gmx_wallcycle_t wcycle)
+{
+    wallcycle_stop(wcycle,ewcRUN);
+
+    runtime_end(runtime);
+}
+
+static void sp_header(FILE *out,const char *minimizer,real ftol,int nsteps)
+{
+    fprintf(out,"\n");
+    fprintf(out,"%s:\n",minimizer);
+    fprintf(out,"   Tolerance (Fmax)   = %12.5e\n",ftol);
+    fprintf(out,"   Number of steps    = %12d\n",nsteps);
+}
+
+static void warn_step(FILE *fp,real ftol,gmx_bool bLastStep,gmx_bool bConstrain)
+{
+    if (bLastStep)
+    {
+        fprintf(fp,"\nReached the maximum number of steps before reaching Fmax < %g\n",ftol);
+    }
+    else
+    {
+        fprintf(fp,"\nStepsize too small, or no change in energy.\n"
+                "Converged to machine precision,\n"
+                "but not to the requested precision Fmax < %g\n",
+                ftol);
+        if (sizeof(real)<sizeof(double))
+        {
+            fprintf(fp,"\nDouble precision normally gives you higher accuracy.\n");
+        }
+        if (bConstrain)
+        {
+            fprintf(fp,"You might need to increase your constraint accuracy, or turn\n"
+                    "off constraints alltogether (set constraints = none in mdp file)\n");
+        }
+    }
+}
+
+
+
+static void print_converged(FILE *fp,const char *alg,real ftol,
+                           gmx_large_int_t count,gmx_bool bDone,gmx_large_int_t nsteps,
+                           real epot,real fmax, int nfmax, real fnorm)
+{
+  char buf[STEPSTRSIZE];
+
+  if (bDone)
+    fprintf(fp,"\n%s converged to Fmax < %g in %s steps\n",
+           alg,ftol,gmx_step_str(count,buf)); 
+  else if(count<nsteps)
+    fprintf(fp,"\n%s converged to machine precision in %s steps,\n"
+               "but did not reach the requested Fmax < %g.\n",
+           alg,gmx_step_str(count,buf),ftol);
+  else 
+    fprintf(fp,"\n%s did not converge to Fmax < %g in %s steps.\n",
+           alg,ftol,gmx_step_str(count,buf));
+
+#ifdef GMX_DOUBLE
+  fprintf(fp,"Potential Energy  = %21.14e\n",epot); 
+  fprintf(fp,"Maximum force     = %21.14e on atom %d\n",fmax,nfmax+1); 
+  fprintf(fp,"Norm of force     = %21.14e\n",fnorm); 
+#else
+  fprintf(fp,"Potential Energy  = %14.7e\n",epot); 
+  fprintf(fp,"Maximum force     = %14.7e on atom %d\n",fmax,nfmax+1); 
+  fprintf(fp,"Norm of force     = %14.7e\n",fnorm); 
+#endif
+}
+
+static void get_f_norm_max(t_commrec *cr,
+                          t_grpopts *opts,t_mdatoms *mdatoms,rvec *f,
+                          real *fnorm,real *fmax,int *a_fmax)
+{
+  double fnorm2,*sum;
+  real fmax2,fmax2_0,fam;
+  int  la_max,a_max,start,end,i,m,gf;
+
+  /* This routine finds the largest force and returns it.
+   * On parallel machines the global max is taken.
+   */
+  fnorm2 = 0;
+  fmax2 = 0;
+  la_max = -1;
+  gf = 0;
+  start = mdatoms->start;
+  end   = mdatoms->homenr + start;
+  if (mdatoms->cFREEZE) {
+    for(i=start; i<end; i++) {
+      gf = mdatoms->cFREEZE[i];
+      fam = 0;
+      for(m=0; m<DIM; m++)
+       if (!opts->nFreeze[gf][m])
+         fam += sqr(f[i][m]);
+      fnorm2 += fam;
+      if (fam > fmax2) {
+       fmax2  = fam;
+       la_max = i;
+      }
+    }
+  } else {
+    for(i=start; i<end; i++) {
+      fam = norm2(f[i]);
+      fnorm2 += fam;
+      if (fam > fmax2) {
+       fmax2  = fam;
+       la_max = i;
+      }
+    }
+  }
+
+  if (la_max >= 0 && DOMAINDECOMP(cr)) {
+    a_max = cr->dd->gatindex[la_max];
+  } else {
+    a_max = la_max;
+  }
+  if (PAR(cr)) {
+    snew(sum,2*cr->nnodes+1);
+    sum[2*cr->nodeid]   = fmax2;
+    sum[2*cr->nodeid+1] = a_max;
+    sum[2*cr->nnodes]   = fnorm2;
+    gmx_sumd(2*cr->nnodes+1,sum,cr);
+    fnorm2 = sum[2*cr->nnodes];
+    /* Determine the global maximum */
+    for(i=0; i<cr->nnodes; i++) {
+      if (sum[2*i] > fmax2) {
+       fmax2 = sum[2*i];
+       a_max = (int)(sum[2*i+1] + 0.5);
+      }
+    }
+    sfree(sum);
+  }
+
+  if (fnorm)
+    *fnorm = sqrt(fnorm2);
+  if (fmax)
+    *fmax  = sqrt(fmax2);
+  if (a_fmax)
+    *a_fmax = a_max;
+}
+
+static void get_state_f_norm_max(t_commrec *cr,
+                          t_grpopts *opts,t_mdatoms *mdatoms,
+                          em_state_t *ems)
+{
+  get_f_norm_max(cr,opts,mdatoms,ems->f,&ems->fnorm,&ems->fmax,&ems->a_fmax);
+}
+
+void init_em(FILE *fplog,const char *title,
+             t_commrec *cr,t_inputrec *ir,
+             t_state *state_global,gmx_mtop_t *top_global,
+             em_state_t *ems,gmx_localtop_t **top,
+             rvec **f,rvec **f_global,
+             t_nrnb *nrnb,rvec mu_tot,
+             t_forcerec *fr,gmx_enerdata_t **enerd,
+             t_graph **graph,t_mdatoms *mdatoms,gmx_global_stat_t *gstat,
+             gmx_vsite_t *vsite,gmx_constr_t constr,
+             int nfile,const t_filenm fnm[],
+             gmx_mdoutf_t **outf,t_mdebin **mdebin)
+{
+    int  start,homenr,i;
+    real dvdlambda;
+    
+    if (fplog)
+    {
+        fprintf(fplog,"Initiating %s\n",title);
+    }
+    
+    state_global->ngtc = 0;
+    
+    /* Initiate some variables */
+    if (ir->efep != efepNO)
+    {
+        state_global->lambda = ir->init_lambda;
+    }
+    else 
+    {
+        state_global->lambda = 0.0;
+    }
+    
+    init_nrnb(nrnb);
+    
+    if (DOMAINDECOMP(cr))
+    {
+        *top = dd_init_local_top(top_global);
+        
+        dd_init_local_state(cr->dd,state_global,&ems->s);
+
+        *f = NULL;
+        
+        /* Distribute the charge groups over the nodes from the master node */
+        dd_partition_system(fplog,ir->init_step,cr,TRUE,1,
+                            state_global,top_global,ir,
+                            &ems->s,&ems->f,mdatoms,*top,
+                            fr,vsite,NULL,constr,
+                            nrnb,NULL,FALSE);
+        dd_store_state(cr->dd,&ems->s);
+        
+        if (ir->nstfout)
+        {
+            snew(*f_global,top_global->natoms);
+        }
+        else
+        {
+            *f_global = NULL;
+        }
+        *graph = NULL;
+    }
+    else
+    {
+        snew(*f,top_global->natoms);
+
+        /* Just copy the state */
+        ems->s = *state_global;
+        snew(ems->s.x,ems->s.nalloc);
+        snew(ems->f,ems->s.nalloc);
+        for(i=0; i<state_global->natoms; i++)
+        {
+            copy_rvec(state_global->x[i],ems->s.x[i]);
+        }
+        copy_mat(state_global->box,ems->s.box);
+        
+        if (PAR(cr) && ir->eI != eiNM)
+        {
+            /* Initialize the particle decomposition and split the topology */
+            *top = split_system(fplog,top_global,ir,cr);
+            
+            pd_cg_range(cr,&fr->cg0,&fr->hcg);
+        }
+        else
+        {
+            *top = gmx_mtop_generate_local_top(top_global,ir);
+        }
+        *f_global = *f;
+        
+        if (ir->ePBC != epbcNONE && !ir->bPeriodicMols)
+        {
+            *graph = mk_graph(fplog,&((*top)->idef),0,top_global->natoms,FALSE,FALSE);
+        }
+        else
+        {
+            *graph = NULL;
+        }
+
+        if (PARTDECOMP(cr))
+        {
+            pd_at_range(cr,&start,&homenr);
+            homenr -= start;
+        }
+        else
+        {
+            start  = 0;
+            homenr = top_global->natoms;
+        }
+        atoms2md(top_global,ir,0,NULL,start,homenr,mdatoms);
+        update_mdatoms(mdatoms,state_global->lambda);
+    
+        if (vsite)
+        {
+            set_vsite_top(vsite,*top,mdatoms,cr);
+        }
+    }
+    
+    if (constr)
+    {
+        if (ir->eConstrAlg == econtSHAKE &&
+            gmx_mtop_ftype_count(top_global,F_CONSTR) > 0)
+        {
+            gmx_fatal(FARGS,"Can not do energy minimization with %s, use %s\n",
+                      econstr_names[econtSHAKE],econstr_names[econtLINCS]);
+        }
+        
+        if (!DOMAINDECOMP(cr))
+        {
+            set_constraints(constr,*top,ir,mdatoms,cr);
+        }
+
+        if (!ir->bContinuation)
+        {
+            /* Constrain the starting coordinates */
+            dvdlambda=0;
+            constrain(PAR(cr) ? NULL : fplog,TRUE,TRUE,constr,&(*top)->idef,
+                      ir,NULL,cr,-1,0,mdatoms,
+                      ems->s.x,ems->s.x,NULL,ems->s.box,
+                      ems->s.lambda,&dvdlambda,
+                      NULL,NULL,nrnb,econqCoord,FALSE,0,0);
+        }
+    }
+    
+    if (PAR(cr))
+    {
+        *gstat = global_stat_init(ir);
+    }
+    
+    *outf = init_mdoutf(nfile,fnm,0,cr,ir,NULL);
+
+    snew(*enerd,1);
+    init_enerdata(top_global->groups.grps[egcENER].nr,ir->n_flambda,*enerd);
+
+    if (mdebin != NULL)
+    {
+        /* Init bin for energy stuff */
+        *mdebin = init_mdebin((*outf)->fp_ene,top_global,ir,NULL); 
+    }
+
+    clear_rvec(mu_tot);
+    calc_shifts(ems->s.box,fr->shift_vec);
+}
+
+static void finish_em(FILE *fplog,t_commrec *cr,gmx_mdoutf_t *outf,
+                      gmx_runtime_t *runtime,gmx_wallcycle_t wcycle)
+{
+  if (!(cr->duty & DUTY_PME)) {
+    /* Tell the PME only node to finish */
+    gmx_pme_finish(cr);
+  }
+
+  done_mdoutf(outf);
+
+  em_time_end(fplog,cr,runtime,wcycle);
+}
+
+static void swap_em_state(em_state_t *ems1,em_state_t *ems2)
+{
+  em_state_t tmp;
+
+  tmp   = *ems1;
+  *ems1 = *ems2;
+  *ems2 = tmp;
+}
+
+static void copy_em_coords_back(em_state_t *ems,t_state *state,rvec *f)
+{
+  int i;
+
+  for(i=0; (i<state->natoms); i++)
+    copy_rvec(ems->s.x[i],state->x[i]);
+  if (f != NULL)
+    copy_rvec(ems->f[i],f[i]);
+}
+
+static void write_em_traj(FILE *fplog,t_commrec *cr,
+                          gmx_mdoutf_t *outf,
+                          gmx_bool bX,gmx_bool bF,const char *confout,
+                          gmx_mtop_t *top_global,
+                          t_inputrec *ir,gmx_large_int_t step,
+                          em_state_t *state,
+                          t_state *state_global,rvec *f_global)
+{
+    int mdof_flags;
+
+    if ((bX || bF || confout != NULL) && !DOMAINDECOMP(cr))
+    {
+        f_global = state->f;
+        copy_em_coords_back(state,state_global,bF ? f_global : NULL);
+    }
+    
+    mdof_flags = 0;
+    if (bX) { mdof_flags |= MDOF_X; }
+    if (bF) { mdof_flags |= MDOF_F; }
+    write_traj(fplog,cr,outf,mdof_flags,
+               top_global,step,(double)step,
+               &state->s,state_global,state->f,f_global,NULL,NULL);
+    
+    if (confout != NULL && MASTER(cr))
+    {
+        if (ir->ePBC != epbcNONE && !ir->bPeriodicMols && DOMAINDECOMP(cr))
+        {
+            /* Make molecules whole only for confout writing */
+            do_pbc_mtop(fplog,ir->ePBC,state_global->box,top_global,
+                        state_global->x);
+        }
+
+        write_sto_conf_mtop(confout,
+                            *top_global->name,top_global,
+                            state_global->x,NULL,ir->ePBC,state_global->box);
+    }
+}
+
+static void do_em_step(t_commrec *cr,t_inputrec *ir,t_mdatoms *md,
+                      em_state_t *ems1,real a,rvec *f,em_state_t *ems2,
+                      gmx_constr_t constr,gmx_localtop_t *top,
+                      t_nrnb *nrnb,gmx_wallcycle_t wcycle,
+                      gmx_large_int_t count)
+
+{
+  t_state *s1,*s2;
+  int  start,end,gf,i,m;
+  rvec *x1,*x2;
+  real dvdlambda;
+
+  s1 = &ems1->s;
+  s2 = &ems2->s;
+
+  if (DOMAINDECOMP(cr) && s1->ddp_count != cr->dd->ddp_count)
+    gmx_incons("state mismatch in do_em_step");
+
+  s2->flags = s1->flags;
+
+  if (s2->nalloc != s1->nalloc) {
+    s2->nalloc = s1->nalloc;
+    srenew(s2->x,s1->nalloc);
+    srenew(ems2->f,  s1->nalloc);
+    if (s2->flags & (1<<estCGP))
+      srenew(s2->cg_p,  s1->nalloc);
+  }
+  
+  s2->natoms = s1->natoms;
+  s2->lambda = s1->lambda;
+  copy_mat(s1->box,s2->box);
+
+  start = md->start;
+  end   = md->start + md->homenr;
+
+  x1 = s1->x;
+  x2 = s2->x;
+  gf = 0;
+  for(i=start; i<end; i++) {
+    if (md->cFREEZE)
+      gf = md->cFREEZE[i];
+    for(m=0; m<DIM; m++) {
+      if (ir->opts.nFreeze[gf][m])
+       x2[i][m] = x1[i][m];
+      else
+       x2[i][m] = x1[i][m] + a*f[i][m];
+    }
+  }
+
+  if (s2->flags & (1<<estCGP)) {
+    /* Copy the CG p vector */
+    x1 = s1->cg_p;
+    x2 = s2->cg_p;
+    for(i=start; i<end; i++)
+      copy_rvec(x1[i],x2[i]);
+  }
+
+  if (DOMAINDECOMP(cr)) {
+    s2->ddp_count = s1->ddp_count;
+    if (s2->cg_gl_nalloc < s1->cg_gl_nalloc) {
+      s2->cg_gl_nalloc = s1->cg_gl_nalloc;
+      srenew(s2->cg_gl,s2->cg_gl_nalloc);
+    }
+    s2->ncg_gl = s1->ncg_gl;
+    for(i=0; i<s2->ncg_gl; i++)
+      s2->cg_gl[i] = s1->cg_gl[i];
+    s2->ddp_count_cg_gl = s1->ddp_count_cg_gl;
+  }
+
+  if (constr) {
+    wallcycle_start(wcycle,ewcCONSTR);
+    dvdlambda = 0;
+    constrain(NULL,TRUE,TRUE,constr,&top->idef,        
+              ir,NULL,cr,count,0,md,
+              s1->x,s2->x,NULL,s2->box,s2->lambda,
+              &dvdlambda,NULL,NULL,nrnb,econqCoord,FALSE,0,0);
+    wallcycle_stop(wcycle,ewcCONSTR);
+  }
+}
+
+static void do_x_step(t_commrec *cr,int n,rvec *x1,real a,rvec *f,rvec *x2)
+
+{
+  int  start,end,i,m;
+
+  if (DOMAINDECOMP(cr)) {
+    start = 0;
+    end   = cr->dd->nat_home;
+  } else if (PARTDECOMP(cr)) {
+    pd_at_range(cr,&start,&end);
+  } else {
+    start = 0;
+    end   = n;
+  }
+
+  for(i=start; i<end; i++) {
+    for(m=0; m<DIM; m++) {
+      x2[i][m] = x1[i][m] + a*f[i][m];
+    }
+  }
+}
+
+static void do_x_sub(t_commrec *cr,int n,rvec *x1,rvec *x2,real a,rvec *f)
+
+{
+  int  start,end,i,m;
+
+  if (DOMAINDECOMP(cr)) {
+    start = 0;
+    end   = cr->dd->nat_home;
+  } else if (PARTDECOMP(cr)) {
+    pd_at_range(cr,&start,&end);
+  } else {
+    start = 0;
+    end   = n;
+  }
+
+  for(i=start; i<end; i++) {
+    for(m=0; m<DIM; m++) {
+      f[i][m] = (x1[i][m] - x2[i][m])*a;
+    }
+  }
+}
+
+static void em_dd_partition_system(FILE *fplog,int step,t_commrec *cr,
+                                   gmx_mtop_t *top_global,t_inputrec *ir,
+                                   em_state_t *ems,gmx_localtop_t *top,
+                                   t_mdatoms *mdatoms,t_forcerec *fr,
+                                   gmx_vsite_t *vsite,gmx_constr_t constr,
+                                   t_nrnb *nrnb,gmx_wallcycle_t wcycle)
+{
+    /* Repartition the domain decomposition */
+    wallcycle_start(wcycle,ewcDOMDEC);
+    dd_partition_system(fplog,step,cr,FALSE,1,
+                        NULL,top_global,ir,
+                        &ems->s,&ems->f,
+                        mdatoms,top,fr,vsite,NULL,constr,
+                        nrnb,wcycle,FALSE);
+    dd_store_state(cr->dd,&ems->s);
+    wallcycle_stop(wcycle,ewcDOMDEC);
+}
+    
+static void evaluate_energy(FILE *fplog,gmx_bool bVerbose,t_commrec *cr,
+                            t_state *state_global,gmx_mtop_t *top_global,
+                            em_state_t *ems,gmx_localtop_t *top,
+                            t_inputrec *inputrec,
+                            t_nrnb *nrnb,gmx_wallcycle_t wcycle,
+                            gmx_global_stat_t gstat,
+                            gmx_vsite_t *vsite,gmx_constr_t constr,
+                            t_fcdata *fcd,
+                            t_graph *graph,t_mdatoms *mdatoms,
+                            t_forcerec *fr,rvec mu_tot,
+                            gmx_enerdata_t *enerd,tensor vir,tensor pres,
+                            gmx_large_int_t count,gmx_bool bFirst)
+{
+  real t;
+  gmx_bool bNS;
+  int  nabnsb;
+  tensor force_vir,shake_vir,ekin;
+  real dvdl,prescorr,enercorr,dvdlcorr;
+  real terminate=0;
+  
+  /* Set the time to the initial time, the time does not change during EM */
+  t = inputrec->init_t;
+
+  if (bFirst ||
+      (DOMAINDECOMP(cr) && ems->s.ddp_count < cr->dd->ddp_count)) {
+    /* This the first state or an old state used before the last ns */
+    bNS = TRUE;
+  } else {
+    bNS = FALSE;
+    if (inputrec->nstlist > 0) {
+      bNS = TRUE;
+    } else if (inputrec->nstlist == -1) {
+      nabnsb = natoms_beyond_ns_buffer(inputrec,fr,&top->cgs,NULL,ems->s.x);
+      if (PAR(cr))
+       gmx_sumi(1,&nabnsb,cr);
+      bNS = (nabnsb > 0);
+    }
+  }
+
+  if (vsite)
+    construct_vsites(fplog,vsite,ems->s.x,nrnb,1,NULL,
+                    top->idef.iparams,top->idef.il,
+                    fr->ePBC,fr->bMolPBC,graph,cr,ems->s.box);
+
+  if (DOMAINDECOMP(cr)) {
+    if (bNS) {
+      /* Repartition the domain decomposition */
+      em_dd_partition_system(fplog,count,cr,top_global,inputrec,
+                            ems,top,mdatoms,fr,vsite,constr,
+                            nrnb,wcycle);
+    }
+  }
+      
+    /* Calc force & energy on new trial position  */
+    /* do_force always puts the charge groups in the box and shifts again
+     * We do not unshift, so molecules are always whole in congrad.c
+     */
+    do_force(fplog,cr,inputrec,
+             count,nrnb,wcycle,top,top_global,&top_global->groups,
+             ems->s.box,ems->s.x,&ems->s.hist,
+             ems->f,force_vir,mdatoms,enerd,fcd,
+             ems->s.lambda,graph,fr,vsite,mu_tot,t,NULL,NULL,TRUE,
+             GMX_FORCE_STATECHANGED | GMX_FORCE_ALLFORCES | GMX_FORCE_VIRIAL |
+             (bNS ? GMX_FORCE_NS | GMX_FORCE_DOLR : 0));
+       
+  /* Clear the unused shake virial and pressure */
+  clear_mat(shake_vir);
+  clear_mat(pres);
+
+  /* Calculate long range corrections to pressure and energy */
+  calc_dispcorr(fplog,inputrec,fr,count,top_global->natoms,ems->s.box,ems->s.lambda,
+                pres,force_vir,&prescorr,&enercorr,&dvdlcorr);
+  /* don't think these next 4 lines  can be moved in for now, because we 
+     don't always want to write it -- figure out how to clean this up MRS 8/4/2009 */
+  enerd->term[F_DISPCORR] = enercorr;
+  enerd->term[F_EPOT] += enercorr;
+  enerd->term[F_PRES] += prescorr;
+  enerd->term[F_DVDL] += dvdlcorr;
+
+    /* Communicate stuff when parallel */
+    if (PAR(cr) && inputrec->eI != eiNM)
+    {
+        wallcycle_start(wcycle,ewcMoveE);
+
+        global_stat(fplog,gstat,cr,enerd,force_vir,shake_vir,mu_tot,
+                    inputrec,NULL,NULL,NULL,1,&terminate,
+                    top_global,&ems->s,FALSE,
+                    CGLO_ENERGY | 
+                    CGLO_PRESSURE | 
+                    CGLO_CONSTRAINT | 
+                    CGLO_FIRSTITERATE);
+
+        wallcycle_stop(wcycle,ewcMoveE);
+    }
+
+  ems->epot = enerd->term[F_EPOT];
+  
+  if (constr) {
+    /* Project out the constraint components of the force */
+    wallcycle_start(wcycle,ewcCONSTR);
+    dvdl = 0;
+    constrain(NULL,FALSE,FALSE,constr,&top->idef,
+              inputrec,NULL,cr,count,0,mdatoms,
+              ems->s.x,ems->f,ems->f,ems->s.box,ems->s.lambda,&dvdl,
+              NULL,&shake_vir,nrnb,econqForceDispl,FALSE,0,0);
+    if (fr->bSepDVDL && fplog)
+      fprintf(fplog,sepdvdlformat,"Constraints",t,dvdl);
+    enerd->term[F_DHDL_CON] += dvdl;
+    m_add(force_vir,shake_vir,vir);
+    wallcycle_stop(wcycle,ewcCONSTR);
+  } else {
+    copy_mat(force_vir,vir);
+  }
+
+  clear_mat(ekin);
+  enerd->term[F_PRES] =
+    calc_pres(fr->ePBC,inputrec->nwall,ems->s.box,ekin,vir,pres,
+             (fr->eeltype==eelPPPM)?enerd->term[F_COUL_RECIP]:0.0);
+
+  sum_dhdl(enerd,ems->s.lambda,inputrec);
+
+    if (EI_ENERGY_MINIMIZATION(inputrec->eI))
+    {
+        get_state_f_norm_max(cr,&(inputrec->opts),mdatoms,ems);
+    }
+}
+
+static double reorder_partsum(t_commrec *cr,t_grpopts *opts,t_mdatoms *mdatoms,
+                             gmx_mtop_t *mtop,
+                             em_state_t *s_min,em_state_t *s_b)
+{
+  rvec *fm,*fb,*fmg;
+  t_block *cgs_gl;
+  int ncg,*cg_gl,*index,c,cg,i,a0,a1,a,gf,m;
+  double partsum;
+  unsigned char *grpnrFREEZE;
+
+  if (debug)
+    fprintf(debug,"Doing reorder_partsum\n");
+
+  fm = s_min->f;
+  fb = s_b->f;
+
+  cgs_gl = dd_charge_groups_global(cr->dd);
+  index = cgs_gl->index;
+
+  /* Collect fm in a global vector fmg.
+   * This conflicts with the spirit of domain decomposition,
+   * but to fully optimize this a much more complicated algorithm is required.
+   */
+  snew(fmg,mtop->natoms);
+  
+  ncg   = s_min->s.ncg_gl;
+  cg_gl = s_min->s.cg_gl;
+  i = 0;
+  for(c=0; c<ncg; c++) {
+    cg = cg_gl[c];
+    a0 = index[cg];
+    a1 = index[cg+1];
+    for(a=a0; a<a1; a++) {
+      copy_rvec(fm[i],fmg[a]);
+      i++;
+    }
+  }
+  gmx_sum(mtop->natoms*3,fmg[0],cr);
+
+  /* Now we will determine the part of the sum for the cgs in state s_b */
+  ncg   = s_b->s.ncg_gl;
+  cg_gl = s_b->s.cg_gl;
+  partsum = 0;
+  i = 0;
+  gf = 0;
+  grpnrFREEZE = mtop->groups.grpnr[egcFREEZE];
+  for(c=0; c<ncg; c++) {
+    cg = cg_gl[c];
+    a0 = index[cg];
+    a1 = index[cg+1];
+    for(a=a0; a<a1; a++) {
+      if (mdatoms->cFREEZE && grpnrFREEZE) {
+       gf = grpnrFREEZE[i];
+      }
+      for(m=0; m<DIM; m++) {
+       if (!opts->nFreeze[gf][m]) {
+         partsum += (fb[i][m] - fmg[a][m])*fb[i][m];
+       }
+      }
+      i++;
+    }
+  }
+  
+  sfree(fmg);
+
+  return partsum;
+}
+
+static real pr_beta(t_commrec *cr,t_grpopts *opts,t_mdatoms *mdatoms,
+                   gmx_mtop_t *mtop,
+                   em_state_t *s_min,em_state_t *s_b)
+{
+  rvec *fm,*fb;
+  double sum;
+  int  gf,i,m;
+
+  /* This is just the classical Polak-Ribiere calculation of beta;
+   * it looks a bit complicated since we take freeze groups into account,
+   * and might have to sum it in parallel runs.
+   */
+  
+  if (!DOMAINDECOMP(cr) ||
+      (s_min->s.ddp_count == cr->dd->ddp_count &&
+       s_b->s.ddp_count   == cr->dd->ddp_count)) {
+    fm = s_min->f;
+    fb = s_b->f;
+    sum = 0;
+    gf = 0;
+    /* This part of code can be incorrect with DD,
+     * since the atom ordering in s_b and s_min might differ.
+     */
+    for(i=mdatoms->start; i<mdatoms->start+mdatoms->homenr; i++) {
+      if (mdatoms->cFREEZE)
+       gf = mdatoms->cFREEZE[i];
+      for(m=0; m<DIM; m++)
+       if (!opts->nFreeze[gf][m]) {
+         sum += (fb[i][m] - fm[i][m])*fb[i][m];
+       } 
+    }
+  } else {
+    /* We need to reorder cgs while summing */
+    sum = reorder_partsum(cr,opts,mdatoms,mtop,s_min,s_b);
+  }
+  if (PAR(cr))
+    gmx_sumd(1,&sum,cr);
+
+  return sum/sqr(s_min->fnorm);
+}
+
+double do_cg(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 *inputrec,
+             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_seed,
+             gmx_membed_t *membed,
+             real cpt_period,real max_hours,
+             const char *deviceOptions,
+             unsigned long Flags,
+             gmx_runtime_t *runtime)
+{
+  const char *CG="Polak-Ribiere Conjugate Gradients";
+
+  em_state_t *s_min,*s_a,*s_b,*s_c;
+  gmx_localtop_t *top;
+  gmx_enerdata_t *enerd;
+  rvec   *f;
+  gmx_global_stat_t gstat;
+  t_graph    *graph;
+  rvec   *f_global,*p,*sf,*sfm;
+  double gpa,gpb,gpc,tmp,sum[2],minstep;
+  real   fnormn;
+  real   stepsize;     
+  real   a,b,c,beta=0.0;
+  real   epot_repl=0;
+  real   pnorm;
+  t_mdebin   *mdebin;
+  gmx_bool   converged,foundlower;
+  rvec   mu_tot;
+  gmx_bool   do_log=FALSE,do_ene=FALSE,do_x,do_f;
+  tensor vir,pres;
+  int    number_steps,neval=0,nstcg=inputrec->nstcgsteep;
+  gmx_mdoutf_t *outf;
+  int    i,m,gf,step,nminstep;
+  real   terminate=0;  
+
+  step=0;
+
+  s_min = init_em_state();
+  s_a   = init_em_state();
+  s_b   = init_em_state();
+  s_c   = init_em_state();
+
+  /* Init em and store the local state in s_min */
+  init_em(fplog,CG,cr,inputrec,
+          state_global,top_global,s_min,&top,&f,&f_global,
+          nrnb,mu_tot,fr,&enerd,&graph,mdatoms,&gstat,vsite,constr,
+          nfile,fnm,&outf,&mdebin);
+  
+  /* Print to log file */
+  print_em_start(fplog,cr,runtime,wcycle,CG);
+  
+  /* Max number of steps */
+  number_steps=inputrec->nsteps;
+
+  if (MASTER(cr))
+    sp_header(stderr,CG,inputrec->em_tol,number_steps);
+  if (fplog)
+    sp_header(fplog,CG,inputrec->em_tol,number_steps);
+
+  /* Call the force routine and some auxiliary (neighboursearching etc.) */
+  /* do_force always puts the charge groups in the box and shifts again
+   * We do not unshift, so molecules are always whole in congrad.c
+   */
+  evaluate_energy(fplog,bVerbose,cr,
+                 state_global,top_global,s_min,top,
+                 inputrec,nrnb,wcycle,gstat,
+                 vsite,constr,fcd,graph,mdatoms,fr,
+                 mu_tot,enerd,vir,pres,-1,TRUE);
+  where();
+
+  if (MASTER(cr)) {
+    /* Copy stuff to the energy bin for easy printing etc. */
+    upd_mdebin(mdebin,FALSE,FALSE,(double)step,
+              mdatoms->tmass,enerd,&s_min->s,s_min->s.box,
+              NULL,NULL,vir,pres,NULL,mu_tot,constr);
+    
+    print_ebin_header(fplog,step,step,s_min->s.lambda);
+    print_ebin(outf->fp_ene,TRUE,FALSE,FALSE,fplog,step,step,eprNORMAL,
+               TRUE,mdebin,fcd,&(top_global->groups),&(inputrec->opts));
+  }
+  where();
+
+  /* Estimate/guess the initial stepsize */
+  stepsize = inputrec->em_stepsize/s_min->fnorm;
+  if (MASTER(cr)) {
+    fprintf(stderr,"   F-max             = %12.5e on atom %d\n",
+           s_min->fmax,s_min->a_fmax+1);
+    fprintf(stderr,"   F-Norm            = %12.5e\n",
+           s_min->fnorm/sqrt(state_global->natoms));
+    fprintf(stderr,"\n");
+    /* and copy to the log file too... */
+    fprintf(fplog,"   F-max             = %12.5e on atom %d\n",
+           s_min->fmax,s_min->a_fmax+1);
+    fprintf(fplog,"   F-Norm            = %12.5e\n",
+           s_min->fnorm/sqrt(state_global->natoms));
+    fprintf(fplog,"\n");
+  }  
+  /* Start the loop over CG steps.             
+   * Each successful step is counted, and we continue until
+   * we either converge or reach the max number of steps.
+   */
+  converged = FALSE;
+  for(step=0; (number_steps<0 || (number_steps>=0 && step<=number_steps)) && !converged;step++) {
+    
+    /* start taking steps in a new direction 
+     * First time we enter the routine, beta=0, and the direction is 
+     * simply the negative gradient.
+     */
+
+    /* Calculate the new direction in p, and the gradient in this direction, gpa */
+    p  = s_min->s.cg_p;
+    sf = s_min->f;
+    gpa = 0;
+    gf = 0;
+    for(i=mdatoms->start; i<mdatoms->start+mdatoms->homenr; i++) {
+      if (mdatoms->cFREEZE) 
+       gf = mdatoms->cFREEZE[i];
+      for(m=0; m<DIM; m++) {
+       if (!inputrec->opts.nFreeze[gf][m]) {
+         p[i][m] = sf[i][m] + beta*p[i][m];
+         gpa -= p[i][m]*sf[i][m];
+         /* f is negative gradient, thus the sign */
+       } else {
+          p[i][m] = 0;
+       }
+      }
+    }
+    
+    /* Sum the gradient along the line across CPUs */
+    if (PAR(cr))
+      gmx_sumd(1,&gpa,cr);
+
+    /* Calculate the norm of the search vector */
+    get_f_norm_max(cr,&(inputrec->opts),mdatoms,p,&pnorm,NULL,NULL);
+    
+    /* Just in case stepsize reaches zero due to numerical precision... */
+    if(stepsize<=0)      
+      stepsize = inputrec->em_stepsize/pnorm;
+    
+    /* 
+     * Double check the value of the derivative in the search direction.
+     * If it is positive it must be due to the old information in the
+     * CG formula, so just remove that and start over with beta=0.
+     * This corresponds to a steepest descent step.
+     */
+    if(gpa>0) {
+      beta = 0;
+      step--; /* Don't count this step since we are restarting */
+      continue; /* Go back to the beginning of the big for-loop */
+    }
+
+    /* Calculate minimum allowed stepsize, before the average (norm)
+     * relative change in coordinate is smaller than precision
+     */
+    minstep=0;
+    for (i=mdatoms->start; i<mdatoms->start+mdatoms->homenr; i++) {
+      for(m=0; m<DIM; m++) {
+       tmp = fabs(s_min->s.x[i][m]);
+       if(tmp < 1.0)
+         tmp = 1.0;
+       tmp = p[i][m]/tmp;
+       minstep += tmp*tmp;
+      }
+    }
+    /* Add up from all CPUs */
+    if(PAR(cr))
+      gmx_sumd(1,&minstep,cr);
+
+    minstep = GMX_REAL_EPS/sqrt(minstep/(3*state_global->natoms));
+
+    if(stepsize<minstep) {
+      converged=TRUE;
+      break;
+    }
+    
+    /* Write coordinates if necessary */
+    do_x = do_per_step(step,inputrec->nstxout);
+    do_f = do_per_step(step,inputrec->nstfout);
+    
+    write_em_traj(fplog,cr,outf,do_x,do_f,NULL,
+                  top_global,inputrec,step,
+                  s_min,state_global,f_global);
+    
+    /* Take a step downhill.
+     * In theory, we should minimize the function along this direction.
+     * That is quite possible, but it turns out to take 5-10 function evaluations
+     * for each line. However, we dont really need to find the exact minimum -
+     * it is much better to start a new CG step in a modified direction as soon
+     * as we are close to it. This will save a lot of energy evaluations.
+     *
+     * In practice, we just try to take a single step.
+     * If it worked (i.e. lowered the energy), we increase the stepsize but
+     * the continue straight to the next CG step without trying to find any minimum.
+     * If it didn't work (higher energy), there must be a minimum somewhere between
+     * the old position and the new one.
+     * 
+     * Due to the finite numerical accuracy, it turns out that it is a good idea
+     * to even accept a SMALL increase in energy, if the derivative is still downhill.
+     * This leads to lower final energies in the tests I've done. / Erik 
+     */
+    s_a->epot = s_min->epot;
+    a = 0.0;
+    c = a + stepsize; /* reference position along line is zero */
+    
+    if (DOMAINDECOMP(cr) && s_min->s.ddp_count < cr->dd->ddp_count) {
+      em_dd_partition_system(fplog,step,cr,top_global,inputrec,
+                            s_min,top,mdatoms,fr,vsite,constr,
+                            nrnb,wcycle);
+    }
+
+    /* Take a trial step (new coords in s_c) */
+    do_em_step(cr,inputrec,mdatoms,s_min,c,s_min->s.cg_p,s_c,
+              constr,top,nrnb,wcycle,-1);
+    
+    neval++;
+    /* Calculate energy for the trial step */
+    evaluate_energy(fplog,bVerbose,cr,
+                   state_global,top_global,s_c,top,
+                   inputrec,nrnb,wcycle,gstat,
+                   vsite,constr,fcd,graph,mdatoms,fr,
+                   mu_tot,enerd,vir,pres,-1,FALSE);
+    
+    /* Calc derivative along line */
+    p  = s_c->s.cg_p;
+    sf = s_c->f;
+    gpc=0;
+    for(i=mdatoms->start; i<mdatoms->start+mdatoms->homenr; i++) {
+      for(m=0; m<DIM; m++) 
+         gpc -= p[i][m]*sf[i][m];  /* f is negative gradient, thus the sign */
+    }
+    /* Sum the gradient along the line across CPUs */
+    if (PAR(cr))
+      gmx_sumd(1,&gpc,cr);
+
+    /* This is the max amount of increase in energy we tolerate */
+    tmp=sqrt(GMX_REAL_EPS)*fabs(s_a->epot);
+
+    /* Accept the step if the energy is lower, or if it is not significantly higher
+     * and the line derivative is still negative.
+     */
+    if (s_c->epot < s_a->epot || (gpc < 0 && s_c->epot < (s_a->epot + tmp))) {
+      foundlower = TRUE;
+      /* Great, we found a better energy. Increase step for next iteration
+       * if we are still going down, decrease it otherwise
+       */
+      if(gpc<0)
+       stepsize *= 1.618034;  /* The golden section */
+      else
+       stepsize *= 0.618034;  /* 1/golden section */
+    } else {
+      /* New energy is the same or higher. We will have to do some work
+       * to find a smaller value in the interval. Take smaller step next time!
+       */
+      foundlower = FALSE;
+      stepsize *= 0.618034;
+    }    
+
+
+
+    
+    /* OK, if we didn't find a lower value we will have to locate one now - there must
+     * be one in the interval [a=0,c].
+     * The same thing is valid here, though: Don't spend dozens of iterations to find
+     * the line minimum. We try to interpolate based on the derivative at the endpoints,
+     * and only continue until we find a lower value. In most cases this means 1-2 iterations.
+     *
+     * I also have a safeguard for potentially really patological functions so we never
+     * take more than 20 steps before we give up ...
+     *
+     * If we already found a lower value we just skip this step and continue to the update.
+     */
+    if (!foundlower) {
+      nminstep=0;
+
+      do {
+       /* Select a new trial point.
+        * If the derivatives at points a & c have different sign we interpolate to zero,
+        * otherwise just do a bisection.
+        */
+       if(gpa<0 && gpc>0)
+         b = a + gpa*(a-c)/(gpc-gpa);
+       else
+         b = 0.5*(a+c);                
+       
+       /* safeguard if interpolation close to machine accuracy causes errors:
+        * never go outside the interval
+        */
+       if(b<=a || b>=c)
+         b = 0.5*(a+c);
+       
+       if (DOMAINDECOMP(cr) && s_min->s.ddp_count != cr->dd->ddp_count) {
+         /* Reload the old state */
+         em_dd_partition_system(fplog,-1,cr,top_global,inputrec,
+                                s_min,top,mdatoms,fr,vsite,constr,
+                                nrnb,wcycle);
+       }
+
+       /* Take a trial step to this new point - new coords in s_b */
+       do_em_step(cr,inputrec,mdatoms,s_min,b,s_min->s.cg_p,s_b,
+                  constr,top,nrnb,wcycle,-1);
+       
+       neval++;
+       /* Calculate energy for the trial step */
+       evaluate_energy(fplog,bVerbose,cr,
+                       state_global,top_global,s_b,top,
+                       inputrec,nrnb,wcycle,gstat,
+                       vsite,constr,fcd,graph,mdatoms,fr,
+                       mu_tot,enerd,vir,pres,-1,FALSE);
+       
+       /* p does not change within a step, but since the domain decomposition
+        * might change, we have to use cg_p of s_b here.
+        */
+       p  = s_b->s.cg_p;
+       sf = s_b->f;
+       gpb=0;
+       for(i=mdatoms->start; i<mdatoms->start+mdatoms->homenr; i++) {
+         for(m=0; m<DIM; m++)
+             gpb -= p[i][m]*sf[i][m];   /* f is negative gradient, thus the sign */
+       }
+       /* Sum the gradient along the line across CPUs */
+       if (PAR(cr))
+         gmx_sumd(1,&gpb,cr);
+       
+       if (debug)
+         fprintf(debug,"CGE: EpotA %f EpotB %f EpotC %f gpb %f\n",
+                 s_a->epot,s_b->epot,s_c->epot,gpb);
+
+       epot_repl = s_b->epot;
+       
+       /* Keep one of the intervals based on the value of the derivative at the new point */
+       if (gpb > 0) {
+         /* Replace c endpoint with b */
+         swap_em_state(s_b,s_c);
+         c = b;
+         gpc = gpb;
+       } else {
+         /* Replace a endpoint with b */
+         swap_em_state(s_b,s_a);
+         a = b;
+         gpa = gpb;
+       }
+       
+       /* 
+        * Stop search as soon as we find a value smaller than the endpoints.
+        * Never run more than 20 steps, no matter what.
+        */
+       nminstep++;
+      } while ((epot_repl > s_a->epot || epot_repl > s_c->epot) &&
+              (nminstep < 20));     
+      
+      if (fabs(epot_repl - s_min->epot) < fabs(s_min->epot)*GMX_REAL_EPS ||
+         nminstep >= 20) {
+       /* OK. We couldn't find a significantly lower energy.
+        * If beta==0 this was steepest descent, and then we give up.
+        * If not, set beta=0 and restart with steepest descent before quitting.
+         */
+       if (beta == 0.0) {
+         /* Converged */
+         converged = TRUE;
+         break;
+       } else {
+         /* Reset memory before giving up */
+         beta = 0.0;
+         continue;
+       }
+      }
+      
+      /* Select min energy state of A & C, put the best in B.
+       */
+      if (s_c->epot < s_a->epot) {
+       if (debug)
+         fprintf(debug,"CGE: C (%f) is lower than A (%f), moving C to B\n",
+                 s_c->epot,s_a->epot);
+       swap_em_state(s_b,s_c);
+       gpb = gpc;
+       b = c;
+      } else {
+       if (debug)
+         fprintf(debug,"CGE: A (%f) is lower than C (%f), moving A to B\n",
+                 s_a->epot,s_c->epot);
+       swap_em_state(s_b,s_a);
+       gpb = gpa;
+       b = a;
+      }
+      
+    } else {
+      if (debug)
+       fprintf(debug,"CGE: Found a lower energy %f, moving C to B\n",
+               s_c->epot);
+      swap_em_state(s_b,s_c);
+      gpb = gpc;
+      b = c;
+    }
+    
+    /* new search direction */
+    /* beta = 0 means forget all memory and restart with steepest descents. */
+    if (nstcg && ((step % nstcg)==0)) 
+      beta = 0.0;
+    else {
+      /* s_min->fnorm cannot be zero, because then we would have converged
+       * and broken out.
+       */
+
+      /* Polak-Ribiere update.
+       * Change to fnorm2/fnorm2_old for Fletcher-Reeves
+       */
+      beta = pr_beta(cr,&inputrec->opts,mdatoms,top_global,s_min,s_b);
+    }
+    /* Limit beta to prevent oscillations */
+    if (fabs(beta) > 5.0)
+      beta = 0.0;
+    
+    
+    /* update positions */
+    swap_em_state(s_min,s_b);
+    gpa = gpb;
+    
+    /* Print it if necessary */
+    if (MASTER(cr)) {
+      if(bVerbose)
+       fprintf(stderr,"\rStep %d, Epot=%12.6e, Fnorm=%9.3e, Fmax=%9.3e (atom %d)\n",
+               step,s_min->epot,s_min->fnorm/sqrt(state_global->natoms),
+               s_min->fmax,s_min->a_fmax+1);
+      /* Store the new (lower) energies */
+      upd_mdebin(mdebin,FALSE,FALSE,(double)step,
+                mdatoms->tmass,enerd,&s_min->s,s_min->s.box,
+                NULL,NULL,vir,pres,NULL,mu_tot,constr);
+      do_log = do_per_step(step,inputrec->nstlog);
+      do_ene = do_per_step(step,inputrec->nstenergy);
+      if(do_log)
+       print_ebin_header(fplog,step,step,s_min->s.lambda);
+      print_ebin(outf->fp_ene,do_ene,FALSE,FALSE,
+                do_log ? fplog : NULL,step,step,eprNORMAL,
+                TRUE,mdebin,fcd,&(top_global->groups),&(inputrec->opts));
+    }
+    
+    /* Stop when the maximum force lies below tolerance.
+     * If we have reached machine precision, converged is already set to true.
+     */        
+    converged = converged || (s_min->fmax < inputrec->em_tol);
+    
+  } /* End of the loop */
+  
+  if (converged)       
+    step--; /* we never took that last step in this case */
+  
+    if (s_min->fmax > inputrec->em_tol)
+    {
+        if (MASTER(cr))
+        {
+            warn_step(stderr,inputrec->em_tol,step-1==number_steps,FALSE);
+            warn_step(fplog ,inputrec->em_tol,step-1==number_steps,FALSE);
+        }
+        converged = FALSE; 
+    }
+  
+  if (MASTER(cr)) {
+    /* If we printed energy and/or logfile last step (which was the last step)
+     * we don't have to do it again, but otherwise print the final values.
+     */
+    if(!do_log) {
+      /* Write final value to log since we didn't do anything the last step */
+      print_ebin_header(fplog,step,step,s_min->s.lambda);
+    }
+    if (!do_ene || !do_log) {
+      /* Write final energy file entries */
+      print_ebin(outf->fp_ene,!do_ene,FALSE,FALSE,
+                !do_log ? fplog : NULL,step,step,eprNORMAL,
+                TRUE,mdebin,fcd,&(top_global->groups),&(inputrec->opts));
+    }
+  }
+
+  /* Print some stuff... */
+  if (MASTER(cr))
+    fprintf(stderr,"\nwriting lowest energy coordinates.\n");
+  
+  /* IMPORTANT!
+   * For accurate normal mode calculation it is imperative that we
+   * store the last conformation into the full precision binary trajectory.
+   *
+   * However, we should only do it if we did NOT already write this step
+   * above (which we did if do_x or do_f was true).
+   */  
+  do_x = !do_per_step(step,inputrec->nstxout);
+  do_f = (inputrec->nstfout > 0 && !do_per_step(step,inputrec->nstfout));
+  
+  write_em_traj(fplog,cr,outf,do_x,do_f,ftp2fn(efSTO,nfile,fnm),
+                top_global,inputrec,step,
+                s_min,state_global,f_global);
+  
+  fnormn = s_min->fnorm/sqrt(state_global->natoms);
+  
+  if (MASTER(cr)) {
+    print_converged(stderr,CG,inputrec->em_tol,step,converged,number_steps,
+                   s_min->epot,s_min->fmax,s_min->a_fmax,fnormn);
+    print_converged(fplog,CG,inputrec->em_tol,step,converged,number_steps,
+                   s_min->epot,s_min->fmax,s_min->a_fmax,fnormn);
+    
+    fprintf(fplog,"\nPerformed %d energy evaluations in total.\n",neval);
+  }
+  
+  finish_em(fplog,cr,outf,runtime,wcycle);
+  
+  /* To print the actual number of steps we needed somewhere */
+  runtime->nsteps_done = step;
+
+  return 0;
+} /* That's all folks */
+
+
+double do_lbfgs(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 *inputrec,
+                gmx_mtop_t *top_global,t_fcdata *fcd,
+                t_state *state,
+                t_mdatoms *mdatoms,
+                t_nrnb *nrnb,gmx_wallcycle_t wcycle,
+                gmx_edsam_t ed,
+                t_forcerec *fr,
+                int repl_ex_nst,int repl_ex_seed,
+                gmx_membed_t *membed,
+                real cpt_period,real max_hours,
+                const char *deviceOptions,
+                unsigned long Flags,
+                gmx_runtime_t *runtime)
+{
+  static const char *LBFGS="Low-Memory BFGS Minimizer";
+  em_state_t ems;
+  gmx_localtop_t *top;
+  gmx_enerdata_t *enerd;
+  rvec   *f;
+  gmx_global_stat_t gstat;
+  t_graph    *graph;
+  rvec   *f_global;
+  int    ncorr,nmaxcorr,point,cp,neval,nminstep;
+  double stepsize,gpa,gpb,gpc,tmp,minstep;
+  real   *rho,*alpha,*ff,*xx,*p,*s,*lastx,*lastf,**dx,**dg;    
+  real   *xa,*xb,*xc,*fa,*fb,*fc,*xtmp,*ftmp;
+  real   a,b,c,maxdelta,delta;
+  real   diag,Epot0,Epot,EpotA,EpotB,EpotC;
+  real   dgdx,dgdg,sq,yr,beta;
+  t_mdebin   *mdebin;
+  gmx_bool   converged,first;
+  rvec   mu_tot;
+  real   fnorm,fmax;
+  gmx_bool   do_log,do_ene,do_x,do_f,foundlower,*frozen;
+  tensor vir,pres;
+  int    start,end,number_steps;
+  gmx_mdoutf_t *outf;
+  int    i,k,m,n,nfmax,gf,step;
+  /* not used */
+  real   terminate;
+
+  if (PAR(cr))
+    gmx_fatal(FARGS,"Cannot do parallel L-BFGS Minimization - yet.\n");
+  
+  n = 3*state->natoms;
+  nmaxcorr = inputrec->nbfgscorr;
+  
+  /* Allocate memory */
+  /* Use pointers to real so we dont have to loop over both atoms and
+   * dimensions all the time...
+   * x/f are allocated as rvec *, so make new x0/f0 pointers-to-real
+   * that point to the same memory.
+   */
+  snew(xa,n);
+  snew(xb,n);
+  snew(xc,n);
+  snew(fa,n);
+  snew(fb,n);
+  snew(fc,n);
+  snew(frozen,n);
+
+  snew(p,n); 
+  snew(lastx,n); 
+  snew(lastf,n); 
+  snew(rho,nmaxcorr);
+  snew(alpha,nmaxcorr);
+  
+  snew(dx,nmaxcorr);
+  for(i=0;i<nmaxcorr;i++)
+    snew(dx[i],n);
+  
+  snew(dg,nmaxcorr);
+  for(i=0;i<nmaxcorr;i++)
+    snew(dg[i],n);
+
+  step = 0;
+  neval = 0; 
+
+  /* Init em */
+  init_em(fplog,LBFGS,cr,inputrec,
+          state,top_global,&ems,&top,&f,&f_global,
+          nrnb,mu_tot,fr,&enerd,&graph,mdatoms,&gstat,vsite,constr,
+          nfile,fnm,&outf,&mdebin);
+  /* Do_lbfgs is not completely updated like do_steep and do_cg,
+   * so we free some memory again.
+   */
+  sfree(ems.s.x);
+  sfree(ems.f);
+
+  xx = (real *)state->x;
+  ff = (real *)f;
+
+  start = mdatoms->start;
+  end   = mdatoms->homenr + start;
+    
+  /* Print to log file */
+  print_em_start(fplog,cr,runtime,wcycle,LBFGS);
+  
+  do_log = do_ene = do_x = do_f = TRUE;
+  
+  /* Max number of steps */
+  number_steps=inputrec->nsteps;
+
+  /* Create a 3*natoms index to tell whether each degree of freedom is frozen */
+  gf = 0;
+  for(i=start; i<end; i++) {
+    if (mdatoms->cFREEZE)
+      gf = mdatoms->cFREEZE[i];
+     for(m=0; m<DIM; m++) 
+       frozen[3*i+m]=inputrec->opts.nFreeze[gf][m];  
+  }
+  if (MASTER(cr))
+    sp_header(stderr,LBFGS,inputrec->em_tol,number_steps);
+  if (fplog)
+    sp_header(fplog,LBFGS,inputrec->em_tol,number_steps);
+  
+  if (vsite)
+    construct_vsites(fplog,vsite,state->x,nrnb,1,NULL,
+                    top->idef.iparams,top->idef.il,
+                    fr->ePBC,fr->bMolPBC,graph,cr,state->box);
+  
+  /* Call the force routine and some auxiliary (neighboursearching etc.) */
+  /* do_force always puts the charge groups in the box and shifts again
+   * We do not unshift, so molecules are always whole
+   */
+  neval++;
+  ems.s.x = state->x;
+  ems.f = f;
+  evaluate_energy(fplog,bVerbose,cr,
+                 state,top_global,&ems,top,
+                 inputrec,nrnb,wcycle,gstat,
+                 vsite,constr,fcd,graph,mdatoms,fr,
+                 mu_tot,enerd,vir,pres,-1,TRUE);
+  where();
+       
+  if (MASTER(cr)) {
+    /* Copy stuff to the energy bin for easy printing etc. */
+    upd_mdebin(mdebin,FALSE,FALSE,(double)step,
+              mdatoms->tmass,enerd,state,state->box,
+              NULL,NULL,vir,pres,NULL,mu_tot,constr);
+    
+    print_ebin_header(fplog,step,step,state->lambda);
+    print_ebin(outf->fp_ene,TRUE,FALSE,FALSE,fplog,step,step,eprNORMAL,
+               TRUE,mdebin,fcd,&(top_global->groups),&(inputrec->opts));
+  }
+  where();
+  
+  /* This is the starting energy */
+  Epot = enerd->term[F_EPOT];
+  
+  fnorm = ems.fnorm;
+  fmax  = ems.fmax;
+  nfmax = ems.a_fmax;
+  
+  /* Set the initial step.
+   * since it will be multiplied by the non-normalized search direction 
+   * vector (force vector the first time), we scale it by the
+   * norm of the force.
+   */
+  
+  if (MASTER(cr)) {
+    fprintf(stderr,"Using %d BFGS correction steps.\n\n",nmaxcorr);
+    fprintf(stderr,"   F-max             = %12.5e on atom %d\n",fmax,nfmax+1);
+    fprintf(stderr,"   F-Norm            = %12.5e\n",fnorm/sqrt(state->natoms));
+    fprintf(stderr,"\n");
+    /* and copy to the log file too... */
+    fprintf(fplog,"Using %d BFGS correction steps.\n\n",nmaxcorr);
+    fprintf(fplog,"   F-max             = %12.5e on atom %d\n",fmax,nfmax+1);
+    fprintf(fplog,"   F-Norm            = %12.5e\n",fnorm/sqrt(state->natoms));
+    fprintf(fplog,"\n");
+  }   
+  
+  point=0;
+  for(i=0;i<n;i++)
+    if(!frozen[i])
+      dx[point][i] = ff[i];  /* Initial search direction */
+    else
+      dx[point][i] = 0;
+
+  stepsize = 1.0/fnorm;
+  converged = FALSE;
+  
+  /* Start the loop over BFGS steps.           
+   * Each successful step is counted, and we continue until
+   * we either converge or reach the max number of steps.
+   */
+  
+  ncorr=0;
+
+  /* Set the gradient from the force */
+  converged = FALSE;
+  for(step=0; (number_steps<0 || (number_steps>=0 && step<=number_steps)) && !converged; step++) {
+    
+    /* Write coordinates if necessary */
+    do_x = do_per_step(step,inputrec->nstxout);
+    do_f = do_per_step(step,inputrec->nstfout);
+    
+    write_traj(fplog,cr,outf,MDOF_X | MDOF_F,
+               top_global,step,(real)step,state,state,f,f,NULL,NULL);
+
+    /* Do the linesearching in the direction dx[point][0..(n-1)] */
+    
+    /* pointer to current direction - point=0 first time here */
+    s=dx[point];
+    
+    /* calculate line gradient */
+    for(gpa=0,i=0;i<n;i++) 
+       gpa-=s[i]*ff[i];
+
+    /* Calculate minimum allowed stepsize, before the average (norm) 
+     * relative change in coordinate is smaller than precision 
+     */
+    for(minstep=0,i=0;i<n;i++) {
+      tmp=fabs(xx[i]);
+      if(tmp<1.0)
+       tmp=1.0;
+      tmp = s[i]/tmp;
+      minstep += tmp*tmp;
+    }
+    minstep = GMX_REAL_EPS/sqrt(minstep/n);
+    
+    if(stepsize<minstep) {
+      converged=TRUE;
+      break;
+    }
+    
+    /* Store old forces and coordinates */
+    for(i=0;i<n;i++) {
+      lastx[i]=xx[i];
+      lastf[i]=ff[i];
+    }
+    Epot0=Epot;
+    
+    first=TRUE;
+    
+    for(i=0;i<n;i++)
+      xa[i]=xx[i];
+    
+    /* Take a step downhill.
+     * In theory, we should minimize the function along this direction.
+     * That is quite possible, but it turns out to take 5-10 function evaluations
+     * for each line. However, we dont really need to find the exact minimum -
+     * it is much better to start a new BFGS step in a modified direction as soon
+     * as we are close to it. This will save a lot of energy evaluations.
+     *
+     * In practice, we just try to take a single step.
+     * If it worked (i.e. lowered the energy), we increase the stepsize but
+     * the continue straight to the next BFGS step without trying to find any minimum.
+     * If it didn't work (higher energy), there must be a minimum somewhere between
+     * the old position and the new one.
+     * 
+     * Due to the finite numerical accuracy, it turns out that it is a good idea
+     * to even accept a SMALL increase in energy, if the derivative is still downhill.
+     * This leads to lower final energies in the tests I've done. / Erik 
+     */
+    foundlower=FALSE;
+    EpotA = Epot0;
+    a = 0.0;
+    c = a + stepsize; /* reference position along line is zero */
+
+    /* Check stepsize first. We do not allow displacements 
+     * larger than emstep.
+     */
+    do {
+      c = a + stepsize;
+      maxdelta=0;
+      for(i=0;i<n;i++) {
+       delta=c*s[i];
+       if(delta>maxdelta)
+         maxdelta=delta;
+      }
+      if(maxdelta>inputrec->em_stepsize)
+       stepsize*=0.1;
+    } while(maxdelta>inputrec->em_stepsize);
+
+    /* Take a trial step */
+    for (i=0; i<n; i++)
+      xc[i] = lastx[i] + c*s[i];
+    
+    neval++;
+    /* Calculate energy for the trial step */
+    ems.s.x = (rvec *)xc;
+    ems.f   = (rvec *)fc;
+    evaluate_energy(fplog,bVerbose,cr,
+                   state,top_global,&ems,top,
+                   inputrec,nrnb,wcycle,gstat,
+                   vsite,constr,fcd,graph,mdatoms,fr,
+                   mu_tot,enerd,vir,pres,step,FALSE);
+    EpotC = ems.epot;
+    
+    /* Calc derivative along line */
+    for(gpc=0,i=0; i<n; i++) {
+       gpc -= s[i]*fc[i];   /* f is negative gradient, thus the sign */
+    }
+    /* Sum the gradient along the line across CPUs */
+    if (PAR(cr))
+      gmx_sumd(1,&gpc,cr);
+    
+     /* This is the max amount of increase in energy we tolerate */
+   tmp=sqrt(GMX_REAL_EPS)*fabs(EpotA);
+    
+    /* Accept the step if the energy is lower, or if it is not significantly higher
+     * and the line derivative is still negative.
+     */
+    if(EpotC<EpotA || (gpc<0 && EpotC<(EpotA+tmp))) {
+      foundlower = TRUE;
+      /* Great, we found a better energy. Increase step for next iteration
+       * if we are still going down, decrease it otherwise
+       */
+      if(gpc<0)
+       stepsize *= 1.618034;  /* The golden section */
+      else
+       stepsize *= 0.618034;  /* 1/golden section */
+    } else {
+      /* New energy is the same or higher. We will have to do some work
+       * to find a smaller value in the interval. Take smaller step next time!
+       */
+      foundlower = FALSE;
+      stepsize *= 0.618034;
+    }    
+    
+    /* OK, if we didn't find a lower value we will have to locate one now - there must
+     * be one in the interval [a=0,c].
+     * The same thing is valid here, though: Don't spend dozens of iterations to find
+     * the line minimum. We try to interpolate based on the derivative at the endpoints,
+     * and only continue until we find a lower value. In most cases this means 1-2 iterations.
+     *
+     * I also have a safeguard for potentially really patological functions so we never
+     * take more than 20 steps before we give up ...
+     *
+     * If we already found a lower value we just skip this step and continue to the update.
+     */
+
+    if(!foundlower) {
+     
+      nminstep=0;
+      do {
+       /* Select a new trial point.
+        * If the derivatives at points a & c have different sign we interpolate to zero,
+        * otherwise just do a bisection.
+        */
+       
+       if(gpa<0 && gpc>0)
+         b = a + gpa*(a-c)/(gpc-gpa);
+       else
+         b = 0.5*(a+c);                
+       
+       /* safeguard if interpolation close to machine accuracy causes errors:
+        * never go outside the interval
+        */
+       if(b<=a || b>=c)
+         b = 0.5*(a+c);
+       
+       /* Take a trial step */
+       for (i=0; i<n; i++) 
+         xb[i] = lastx[i] + b*s[i];
+       
+       neval++;
+       /* Calculate energy for the trial step */
+       ems.s.x = (rvec *)xb;
+       ems.f   = (rvec *)fb;
+       evaluate_energy(fplog,bVerbose,cr,
+                       state,top_global,&ems,top,
+                       inputrec,nrnb,wcycle,gstat,
+                       vsite,constr,fcd,graph,mdatoms,fr,
+                       mu_tot,enerd,vir,pres,step,FALSE);
+       EpotB = ems.epot;
+       
+       fnorm = ems.fnorm;
+       
+       for(gpb=0,i=0; i<n; i++) 
+         gpb -= s[i]*fb[i];   /* f is negative gradient, thus the sign */
+       
+       /* Sum the gradient along the line across CPUs */
+       if (PAR(cr))
+         gmx_sumd(1,&gpb,cr);
+       
+       /* Keep one of the intervals based on the value of the derivative at the new point */
+       if(gpb>0) {
+         /* Replace c endpoint with b */
+         EpotC = EpotB;
+         c = b;
+         gpc = gpb;
+         /* swap coord pointers b/c */
+         xtmp = xb; 
+         ftmp = fb;
+         xb = xc; 
+         fb = fc;
+         xc = xtmp;
+         fc = ftmp;
+       } else {
+         /* Replace a endpoint with b */
+         EpotA = EpotB;
+         a = b;
+         gpa = gpb;
+         /* swap coord pointers a/b */
+         xtmp = xb; 
+         ftmp = fb;
+         xb = xa; 
+         fb = fa;
+         xa = xtmp; 
+         fa = ftmp;
+       }
+       
+       /* 
+        * Stop search as soon as we find a value smaller than the endpoints,
+        * or if the tolerance is below machine precision.
+        * Never run more than 20 steps, no matter what.
+        */
+       nminstep++; 
+      } while((EpotB>EpotA || EpotB>EpotC) && (nminstep<20));
+
+      if(fabs(EpotB-Epot0)<GMX_REAL_EPS || nminstep>=20) {
+       /* OK. We couldn't find a significantly lower energy.
+        * If ncorr==0 this was steepest descent, and then we give up.
+        * If not, reset memory to restart as steepest descent before quitting.
+         */
+       if(ncorr==0) {
+       /* Converged */
+         converged=TRUE;
+         break;
+       } else {
+         /* Reset memory */
+         ncorr=0;
+         /* Search in gradient direction */
+         for(i=0;i<n;i++)
+           dx[point][i]=ff[i];
+         /* Reset stepsize */
+         stepsize = 1.0/fnorm;
+         continue;
+       }
+      }
+      
+      /* Select min energy state of A & C, put the best in xx/ff/Epot
+       */
+      if(EpotC<EpotA) {
+       Epot = EpotC;
+       /* Use state C */
+       for(i=0;i<n;i++) {
+         xx[i]=xc[i];
+         ff[i]=fc[i];
+       }
+       stepsize=c;
+      } else {
+       Epot = EpotA;
+       /* Use state A */
+       for(i=0;i<n;i++) {
+         xx[i]=xa[i];
+         ff[i]=fa[i];
+       }
+       stepsize=a;
+      }
+      
+    } else {
+      /* found lower */
+      Epot = EpotC;
+      /* Use state C */
+      for(i=0;i<n;i++) {
+       xx[i]=xc[i];
+       ff[i]=fc[i];
+      }
+      stepsize=c;
+    }
+
+    /* Update the memory information, and calculate a new 
+     * approximation of the inverse hessian 
+     */
+    
+    /* Have new data in Epot, xx, ff */        
+    if(ncorr<nmaxcorr)
+      ncorr++;
+
+    for(i=0;i<n;i++) {
+      dg[point][i]=lastf[i]-ff[i];
+      dx[point][i]*=stepsize;
+    }
+    
+    dgdg=0;
+    dgdx=0;    
+    for(i=0;i<n;i++) {
+      dgdg+=dg[point][i]*dg[point][i];
+      dgdx+=dg[point][i]*dx[point][i];
+    }
+    
+    diag=dgdx/dgdg;
+    
+    rho[point]=1.0/dgdx;
+    point++;
+    
+    if(point>=nmaxcorr)
+      point=0;
+    
+    /* Update */
+    for(i=0;i<n;i++)
+      p[i]=ff[i];
+    
+    cp=point;
+    
+    /* Recursive update. First go back over the memory points */
+    for(k=0;k<ncorr;k++) {
+      cp--;
+      if(cp<0) 
+       cp=ncorr-1;
+      
+      sq=0;
+      for(i=0;i<n;i++)
+       sq+=dx[cp][i]*p[i];
+      
+      alpha[cp]=rho[cp]*sq;
+      
+      for(i=0;i<n;i++)
+       p[i] -= alpha[cp]*dg[cp][i];            
+    }
+    
+    for(i=0;i<n;i++)
+      p[i] *= diag;
+    
+    /* And then go forward again */
+    for(k=0;k<ncorr;k++) {
+      yr = 0;
+      for(i=0;i<n;i++)
+       yr += p[i]*dg[cp][i];
+      
+      beta = rho[cp]*yr;           
+      beta = alpha[cp]-beta;
+      
+      for(i=0;i<n;i++)
+       p[i] += beta*dx[cp][i];
+      
+      cp++;    
+      if(cp>=ncorr)
+       cp=0;
+    }
+    
+    for(i=0;i<n;i++)
+      if(!frozen[i])
+       dx[point][i] = p[i];
+      else
+       dx[point][i] = 0;
+
+    stepsize=1.0;
+    
+    /* Test whether the convergence criterion is met */
+    get_f_norm_max(cr,&(inputrec->opts),mdatoms,f,&fnorm,&fmax,&nfmax);
+    
+    /* Print it if necessary */
+    if (MASTER(cr)) {
+      if(bVerbose)
+       fprintf(stderr,"\rStep %d, Epot=%12.6e, Fnorm=%9.3e, Fmax=%9.3e (atom %d)\n",
+               step,Epot,fnorm/sqrt(state->natoms),fmax,nfmax+1);
+      /* Store the new (lower) energies */
+      upd_mdebin(mdebin,FALSE,FALSE,(double)step,
+                mdatoms->tmass,enerd,state,state->box,
+                NULL,NULL,vir,pres,NULL,mu_tot,constr);
+      do_log = do_per_step(step,inputrec->nstlog);
+      do_ene = do_per_step(step,inputrec->nstenergy);
+      if(do_log)
+       print_ebin_header(fplog,step,step,state->lambda);
+      print_ebin(outf->fp_ene,do_ene,FALSE,FALSE,
+                do_log ? fplog : NULL,step,step,eprNORMAL,
+                TRUE,mdebin,fcd,&(top_global->groups),&(inputrec->opts));
+    }
+    
+    /* Stop when the maximum force lies below tolerance.
+     * If we have reached machine precision, converged is already set to true.
+     */
+    
+    converged = converged || (fmax < inputrec->em_tol);
+    
+  } /* End of the loop */
+  
+  if(converged)        
+    step--; /* we never took that last step in this case */
+  
+    if(fmax>inputrec->em_tol)
+    {
+        if (MASTER(cr))
+        {
+            warn_step(stderr,inputrec->em_tol,step-1==number_steps,FALSE);
+            warn_step(fplog ,inputrec->em_tol,step-1==number_steps,FALSE);
+        }
+        converged = FALSE; 
+    }
+  
+  /* If we printed energy and/or logfile last step (which was the last step)
+   * we don't have to do it again, but otherwise print the final values.
+   */
+  if(!do_log) /* Write final value to log since we didn't do anythin last step */
+    print_ebin_header(fplog,step,step,state->lambda);
+  if(!do_ene || !do_log) /* Write final energy file entries */
+    print_ebin(outf->fp_ene,!do_ene,FALSE,FALSE,
+              !do_log ? fplog : NULL,step,step,eprNORMAL,
+              TRUE,mdebin,fcd,&(top_global->groups),&(inputrec->opts));
+  
+  /* Print some stuff... */
+  if (MASTER(cr))
+    fprintf(stderr,"\nwriting lowest energy coordinates.\n");
+  
+  /* IMPORTANT!
+   * For accurate normal mode calculation it is imperative that we
+   * store the last conformation into the full precision binary trajectory.
+   *
+   * However, we should only do it if we did NOT already write this step
+   * above (which we did if do_x or do_f was true).
+   */  
+  do_x = !do_per_step(step,inputrec->nstxout);
+  do_f = !do_per_step(step,inputrec->nstfout);
+  write_em_traj(fplog,cr,outf,do_x,do_f,ftp2fn(efSTO,nfile,fnm),
+                top_global,inputrec,step,
+                &ems,state,f);
+  
+  if (MASTER(cr)) {
+    print_converged(stderr,LBFGS,inputrec->em_tol,step,converged,
+                   number_steps,Epot,fmax,nfmax,fnorm/sqrt(state->natoms));
+    print_converged(fplog,LBFGS,inputrec->em_tol,step,converged,
+                   number_steps,Epot,fmax,nfmax,fnorm/sqrt(state->natoms));
+    
+    fprintf(fplog,"\nPerformed %d energy evaluations in total.\n",neval);
+  }
+  
+  finish_em(fplog,cr,outf,runtime,wcycle);
+
+  /* To print the actual number of steps we needed somewhere */
+  runtime->nsteps_done = step;
+
+  return 0;
+} /* That's all folks */
+
+
+double do_steep(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 *inputrec,
+                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_seed,
+                gmx_membed_t *membed,
+                real cpt_period,real max_hours,
+                const char *deviceOptions,
+                unsigned long Flags,
+                gmx_runtime_t *runtime)
+{ 
+  const char *SD="Steepest Descents";
+  em_state_t *s_min,*s_try;
+  rvec       *f_global;
+  gmx_localtop_t *top;
+  gmx_enerdata_t *enerd;
+  rvec   *f;
+  gmx_global_stat_t gstat;
+  t_graph    *graph;
+  real   stepsize,constepsize;
+  real   ustep,dvdlambda,fnormn;
+  gmx_mdoutf_t *outf;
+  t_mdebin   *mdebin; 
+  gmx_bool   bDone,bAbort,do_x,do_f; 
+  tensor vir,pres; 
+  rvec   mu_tot;
+  int    nsteps;
+  int    count=0; 
+  int    steps_accepted=0; 
+  /* not used */
+  real   terminate=0;
+
+  s_min = init_em_state();
+  s_try = init_em_state();
+
+  /* Init em and store the local state in s_try */
+  init_em(fplog,SD,cr,inputrec,
+          state_global,top_global,s_try,&top,&f,&f_global,
+          nrnb,mu_tot,fr,&enerd,&graph,mdatoms,&gstat,vsite,constr,
+          nfile,fnm,&outf,&mdebin);
+       
+  /* Print to log file  */
+  print_em_start(fplog,cr,runtime,wcycle,SD);
+    
+  /* Set variables for stepsize (in nm). This is the largest  
+   * step that we are going to make in any direction. 
+   */
+  ustep = inputrec->em_stepsize; 
+  stepsize = 0;
+  
+  /* Max number of steps  */
+  nsteps = inputrec->nsteps; 
+  
+  if (MASTER(cr)) 
+    /* Print to the screen  */
+    sp_header(stderr,SD,inputrec->em_tol,nsteps);
+  if (fplog)
+    sp_header(fplog,SD,inputrec->em_tol,nsteps);
+    
+  /**** HERE STARTS THE LOOP ****
+   * count is the counter for the number of steps 
+   * bDone will be TRUE when the minimization has converged
+   * bAbort will be TRUE when nsteps steps have been performed or when
+   * the stepsize becomes smaller than is reasonable for machine precision
+   */
+  count  = 0;
+  bDone  = FALSE;
+  bAbort = FALSE;
+  while( !bDone && !bAbort ) {
+    bAbort = (nsteps >= 0) && (count == nsteps);
+    
+    /* set new coordinates, except for first step */
+    if (count > 0) {
+      do_em_step(cr,inputrec,mdatoms,s_min,stepsize,s_min->f,s_try,
+                constr,top,nrnb,wcycle,count);
+    }
+    
+    evaluate_energy(fplog,bVerbose,cr,
+                   state_global,top_global,s_try,top,
+                   inputrec,nrnb,wcycle,gstat,
+                   vsite,constr,fcd,graph,mdatoms,fr,
+                   mu_tot,enerd,vir,pres,count,count==0);
+        
+    if (MASTER(cr))
+      print_ebin_header(fplog,count,count,s_try->s.lambda);
+
+    if (count == 0)
+      s_min->epot = s_try->epot + 1;
+    
+    /* Print it if necessary  */
+    if (MASTER(cr)) {
+      if (bVerbose) {
+       fprintf(stderr,"Step=%5d, Dmax= %6.1e nm, Epot= %12.5e Fmax= %11.5e, atom= %d%c",
+               count,ustep,s_try->epot,s_try->fmax,s_try->a_fmax+1,
+               (s_try->epot < s_min->epot) ? '\n' : '\r');
+      }
+      
+      if (s_try->epot < s_min->epot) {
+       /* Store the new (lower) energies  */
+       upd_mdebin(mdebin,FALSE,FALSE,(double)count,
+                  mdatoms->tmass,enerd,&s_try->s,s_try->s.box,
+                  NULL,NULL,vir,pres,NULL,mu_tot,constr);
+       print_ebin(outf->fp_ene,TRUE,
+                  do_per_step(steps_accepted,inputrec->nstdisreout),
+                  do_per_step(steps_accepted,inputrec->nstorireout),
+                  fplog,count,count,eprNORMAL,TRUE,
+                  mdebin,fcd,&(top_global->groups),&(inputrec->opts));
+       fflush(fplog);
+      }
+    } 
+    
+    /* Now if the new energy is smaller than the previous...  
+     * or if this is the first step!
+     * or if we did random steps! 
+     */
+    
+    if ( (count==0) || (s_try->epot < s_min->epot) ) {
+      steps_accepted++; 
+
+      /* Test whether the convergence criterion is met...  */
+      bDone = (s_try->fmax < inputrec->em_tol);
+      
+      /* Copy the arrays for force, positions and energy  */
+      /* The 'Min' array always holds the coords and forces of the minimal 
+        sampled energy  */
+      swap_em_state(s_min,s_try);
+      if (count > 0)
+       ustep *= 1.2;
+
+      /* Write to trn, if necessary */
+      do_x = do_per_step(steps_accepted,inputrec->nstxout);
+      do_f = do_per_step(steps_accepted,inputrec->nstfout);
+      write_em_traj(fplog,cr,outf,do_x,do_f,NULL,
+                    top_global,inputrec,count,
+                    s_min,state_global,f_global);
+    } 
+    else {
+      /* If energy is not smaller make the step smaller...  */
+      ustep *= 0.5;
+
+      if (DOMAINDECOMP(cr) && s_min->s.ddp_count != cr->dd->ddp_count) {
+       /* Reload the old state */
+       em_dd_partition_system(fplog,count,cr,top_global,inputrec,
+                              s_min,top,mdatoms,fr,vsite,constr,
+                              nrnb,wcycle);
+      }
+    }
+    
+    /* Determine new step  */
+    stepsize = ustep/s_min->fmax;
+    
+    /* Check if stepsize is too small, with 1 nm as a characteristic length */
+#ifdef GMX_DOUBLE
+        if (count == nsteps || ustep < 1e-12)
+#else
+        if (count == nsteps || ustep < 1e-6)
+#endif
+        {
+            if (MASTER(cr))
+            {
+                warn_step(stderr,inputrec->em_tol,count==nsteps,constr!=NULL);
+                warn_step(fplog ,inputrec->em_tol,count==nsteps,constr!=NULL);
+            }
+            bAbort=TRUE;
+        }
+    
+    count++;
+  } /* End of the loop  */
+  
+    /* Print some shit...  */
+  if (MASTER(cr)) 
+    fprintf(stderr,"\nwriting lowest energy coordinates.\n"); 
+  write_em_traj(fplog,cr,outf,TRUE,inputrec->nstfout,ftp2fn(efSTO,nfile,fnm),
+               top_global,inputrec,count,
+               s_min,state_global,f_global);
+
+  fnormn = s_min->fnorm/sqrt(state_global->natoms);
+
+  if (MASTER(cr)) {
+    print_converged(stderr,SD,inputrec->em_tol,count,bDone,nsteps,
+                   s_min->epot,s_min->fmax,s_min->a_fmax,fnormn);
+    print_converged(fplog,SD,inputrec->em_tol,count,bDone,nsteps,
+                   s_min->epot,s_min->fmax,s_min->a_fmax,fnormn);
+  }
+
+  finish_em(fplog,cr,outf,runtime,wcycle);
+  
+  /* To print the actual number of steps we needed somewhere */
+  inputrec->nsteps=count;
+
+  runtime->nsteps_done = count;
+  
+  return 0;
+} /* That's all folks */
+
+
+double do_nm(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 *inputrec,
+             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_seed,
+             gmx_membed_t *membed,
+             real cpt_period,real max_hours,
+             const char *deviceOptions,
+             unsigned long Flags,
+             gmx_runtime_t *runtime)
+{
+    const char *NM = "Normal Mode Analysis";
+    gmx_mdoutf_t *outf;
+    int        natoms,atom,d;
+    int        nnodes,node;
+    rvec       *f_global;
+    gmx_localtop_t *top;
+    gmx_enerdata_t *enerd;
+    rvec       *f;
+    gmx_global_stat_t gstat;
+    t_graph    *graph;
+    real       t,lambda;
+    gmx_bool       bNS;
+    tensor     vir,pres;
+    rvec       mu_tot;
+    rvec       *fneg,*dfdx;
+    gmx_bool       bSparse; /* use sparse matrix storage format */
+    size_t     sz;
+    gmx_sparsematrix_t * sparse_matrix = NULL;
+    real *     full_matrix             = NULL;
+    em_state_t *   state_work;
+       
+    /* added with respect to mdrun */
+    int        i,j,k,row,col;
+    real       der_range=10.0*sqrt(GMX_REAL_EPS);
+    real       x_min;
+    real       fnorm,fmax;
+    
+    if (constr != NULL)
+    {
+        gmx_fatal(FARGS,"Constraints present with Normal Mode Analysis, this combination is not supported");
+    }
+
+    state_work = init_em_state();
+    
+    /* Init em and store the local state in state_minimum */
+    init_em(fplog,NM,cr,inputrec,
+            state_global,top_global,state_work,&top,
+            &f,&f_global,
+            nrnb,mu_tot,fr,&enerd,&graph,mdatoms,&gstat,vsite,constr,
+            nfile,fnm,&outf,NULL);
+    
+    natoms = top_global->natoms;
+    snew(fneg,natoms);
+    snew(dfdx,natoms);
+    
+#ifndef GMX_DOUBLE
+    if (MASTER(cr))
+    {
+        fprintf(stderr,
+                "NOTE: This version of Gromacs has been compiled in single precision,\n"
+                "      which MIGHT not be accurate enough for normal mode analysis.\n"
+                "      Gromacs now uses sparse matrix storage, so the memory requirements\n"
+                "      are fairly modest even if you recompile in double precision.\n\n");
+    }
+#endif
+    
+    /* Check if we can/should use sparse storage format.
+     *
+     * Sparse format is only useful when the Hessian itself is sparse, which it
+      * will be when we use a cutoff.    
+      * For small systems (n<1000) it is easier to always use full matrix format, though.
+      */
+    if(EEL_FULL(fr->eeltype) || fr->rlist==0.0)
+    {
+        fprintf(stderr,"Non-cutoff electrostatics used, forcing full Hessian format.\n");
+        bSparse = FALSE;
+    }
+    else if(top_global->natoms < 1000)
+    {
+        fprintf(stderr,"Small system size (N=%d), using full Hessian format.\n",top_global->natoms);
+        bSparse = FALSE;
+    }
+    else
+    {
+        fprintf(stderr,"Using compressed symmetric sparse Hessian format.\n");
+        bSparse = TRUE;
+    }
+    
+    sz = DIM*top_global->natoms;
+    
+    fprintf(stderr,"Allocating Hessian memory...\n\n");
+
+    if(bSparse)
+    {
+        sparse_matrix=gmx_sparsematrix_init(sz);
+        sparse_matrix->compressed_symmetric = TRUE;
+    }
+    else
+    {
+        snew(full_matrix,sz*sz);
+    }
+    
+    /* Initial values */
+    t      = inputrec->init_t;
+    lambda = inputrec->init_lambda;
+    
+    init_nrnb(nrnb);
+    
+    where();
+    
+    /* Write start time and temperature */
+    print_em_start(fplog,cr,runtime,wcycle,NM);
+
+    /* fudge nr of steps to nr of atoms */
+    inputrec->nsteps = natoms*2;
+
+    if (MASTER(cr)) 
+    {
+        fprintf(stderr,"starting normal mode calculation '%s'\n%d steps.\n\n",
+                *(top_global->name),(int)inputrec->nsteps);
+    }
+
+    nnodes = cr->nnodes;
+   
+    /* Make evaluate_energy do a single node force calculation */
+    cr->nnodes = 1;
+    evaluate_energy(fplog,bVerbose,cr,
+                    state_global,top_global,state_work,top,
+                    inputrec,nrnb,wcycle,gstat,
+                    vsite,constr,fcd,graph,mdatoms,fr,
+                    mu_tot,enerd,vir,pres,-1,TRUE);
+    cr->nnodes = nnodes;
+
+    /* if forces are not small, warn user */
+    get_state_f_norm_max(cr,&(inputrec->opts),mdatoms,state_work);
+
+    if (MASTER(cr))
+    {
+        fprintf(stderr,"Maximum force:%12.5e\n",state_work->fmax);
+        if (state_work->fmax > 1.0e-3) 
+        {
+            fprintf(stderr,"Maximum force probably not small enough to");
+            fprintf(stderr," ensure that you are in an \nenergy well. ");
+            fprintf(stderr,"Be aware that negative eigenvalues may occur");
+            fprintf(stderr," when the\nresulting matrix is diagonalized.\n");
+        }
+    }
+    
+    /***********************************************************
+     *
+     *      Loop over all pairs in matrix 
+     * 
+     *      do_force called twice. Once with positive and 
+     *      once with negative displacement 
+     *
+     ************************************************************/
+
+    /* Steps are divided one by one over the nodes */
+    for(atom=cr->nodeid; atom<natoms; atom+=nnodes) 
+    {
+        
+        for (d=0; d<DIM; d++) 
+        {
+            x_min = state_work->s.x[atom][d];
+
+            state_work->s.x[atom][d] = x_min - der_range;
+          
+            /* Make evaluate_energy do a single node force calculation */
+            cr->nnodes = 1;
+            evaluate_energy(fplog,bVerbose,cr,
+                            state_global,top_global,state_work,top,
+                            inputrec,nrnb,wcycle,gstat,
+                            vsite,constr,fcd,graph,mdatoms,fr,
+                            mu_tot,enerd,vir,pres,atom*2,FALSE);
+                       
+            for(i=0; i<natoms; i++)
+            {
+                copy_rvec(state_work->f[i], fneg[i]);
+            }
+            
+            state_work->s.x[atom][d] = x_min + der_range;
+            
+            evaluate_energy(fplog,bVerbose,cr,
+                            state_global,top_global,state_work,top,
+                            inputrec,nrnb,wcycle,gstat,
+                            vsite,constr,fcd,graph,mdatoms,fr,
+                            mu_tot,enerd,vir,pres,atom*2+1,FALSE);
+            cr->nnodes = nnodes;
+
+            /* x is restored to original */
+            state_work->s.x[atom][d] = x_min;
+
+            for(j=0; j<natoms; j++) 
+            {
+                for (k=0; (k<DIM); k++) 
+                {
+                    dfdx[j][k] =
+                        -(state_work->f[j][k] - fneg[j][k])/(2*der_range);
+                }
+            }
+
+            if (!MASTER(cr))
+            {
+#ifdef GMX_MPI
+#ifdef GMX_DOUBLE
+#define mpi_type MPI_DOUBLE
+#else
+#define mpi_type MPI_FLOAT
+#endif
+                MPI_Send(dfdx[0],natoms*DIM,mpi_type,MASTERNODE(cr),cr->nodeid,
+                         cr->mpi_comm_mygroup);
+#endif
+            }
+            else
+            {
+                for(node=0; (node<nnodes && atom+node<natoms); node++)
+                {
+                    if (node > 0)
+                    {
+#ifdef GMX_MPI
+                        MPI_Status stat;
+                        MPI_Recv(dfdx[0],natoms*DIM,mpi_type,node,node,
+                                 cr->mpi_comm_mygroup,&stat);
+#undef mpi_type
+#endif
+                    }
+
+                    row = (atom + node)*DIM + d;
+
+                    for(j=0; j<natoms; j++) 
+                    {
+                        for(k=0; k<DIM; k++) 
+                        {
+                            col = j*DIM + k;
+                            
+                            if (bSparse)
+                            {
+                                if (col >= row && dfdx[j][k] != 0.0)
+                                {
+                                    gmx_sparsematrix_increment_value(sparse_matrix,
+                                                                     row,col,dfdx[j][k]);
+                                }
+                            }
+                            else
+                            {
+                                full_matrix[row*sz+col] = dfdx[j][k];
+                            }
+                        }
+                    }
+                }
+            }
+            
+            if (bVerbose && fplog)
+            {
+                fflush(fplog);            
+            }
+        }
+        /* write progress */
+        if (MASTER(cr) && bVerbose) 
+        {
+            fprintf(stderr,"\rFinished step %d out of %d",
+                    min(atom+nnodes,natoms),natoms); 
+            fflush(stderr);
+        }
+    }
+    
+    if (MASTER(cr)) 
+    {
+        fprintf(stderr,"\n\nWriting Hessian...\n");
+        gmx_mtxio_write(ftp2fn(efMTX,nfile,fnm),sz,sz,full_matrix,sparse_matrix);
+    }
+
+    finish_em(fplog,cr,outf,runtime,wcycle);
+
+    runtime->nsteps_done = natoms*2;
+    
+    return 0;
+}
similarity index 100%
rename from src/mdlib/mvxvf.c
rename to src/gromacs/mdlib/mvxvf.c
diff --git a/src/gromacs/mdlib/ns.c b/src/gromacs/mdlib/ns.c
new file mode 100644 (file)
index 0000000..7c1a244
--- /dev/null
@@ -0,0 +1,2789 @@
+/* -*- 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
+ * 
+ *                        VERSION 3.2.0
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * 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.
+
+ * 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:
+ * GROwing Monsters And Cloning Shrimps
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef GMX_THREAD_SHM_FDECOMP
+#include <pthread.h> 
+#endif
+
+#include <math.h>
+#include <string.h>
+#include "sysstuff.h"
+#include "smalloc.h"
+#include "macros.h"
+#include "maths.h"
+#include "vec.h"
+#include "network.h"
+#include "nsgrid.h"
+#include "force.h"
+#include "nonbonded.h"
+#include "ns.h"
+#include "pbc.h"
+#include "names.h"
+#include "gmx_fatal.h"
+#include "nrnb.h"
+#include "txtdump.h"
+#include "mtop_util.h"
+
+#include "domdec.h"
+
+
+/* 
+ *    E X C L U S I O N   H A N D L I N G
+ */
+
+#ifdef DEBUG
+static void SETEXCL_(t_excl e[],atom_id i,atom_id j)
+{   e[j] = e[j] | (1<<i); }
+static void RMEXCL_(t_excl e[],atom_id i,atom_id j) 
+{ e[j]=e[j] & ~(1<<i); }
+static gmx_bool ISEXCL_(t_excl e[],atom_id i,atom_id j) 
+{ return (gmx_bool)(e[j] & (1<<i)); }
+static gmx_bool NOTEXCL_(t_excl e[],atom_id i,atom_id j)
+{  return !(ISEXCL(e,i,j)); }
+#else
+#define SETEXCL(e,i,j) (e)[((atom_id) (j))] |= (1<<((atom_id) (i)))
+#define RMEXCL(e,i,j)  (e)[((atom_id) (j))] &= (~(1<<((atom_id) (i))))
+#define ISEXCL(e,i,j)  (gmx_bool) ((e)[((atom_id) (j))] & (1<<((atom_id) (i))))
+#define NOTEXCL(e,i,j) !(ISEXCL(e,i,j))
+#endif
+
+/************************************************
+ *
+ *  U T I L I T I E S    F O R    N S
+ *
+ ************************************************/
+
+static void reallocate_nblist(t_nblist *nl)
+{
+    if (gmx_debug_at)
+    {
+        fprintf(debug,"reallocating neigborlist il_code=%d, maxnri=%d\n",
+                nl->il_code,nl->maxnri); 
+    }
+    srenew(nl->iinr,   nl->maxnri);
+    if (nl->enlist == enlistCG_CG)
+    {
+        srenew(nl->iinr_end,nl->maxnri);
+    }
+    srenew(nl->gid,    nl->maxnri);
+    srenew(nl->shift,  nl->maxnri);
+    srenew(nl->jindex, nl->maxnri+1);
+}
+
+/* ivdw/icoul are used to determine the type of interaction, so we
+ * can set an innerloop index here. The obvious choice for this would have
+ * been the vdwtype/coultype values in the forcerecord, but unfortunately 
+ * those types are braindead - for instance both Buckingham and normal 
+ * Lennard-Jones use the same value (evdwCUT), and a separate gmx_boolean variable
+ * to determine which interaction is used. There is further no special value
+ * for 'no interaction'. For backward compatibility with old TPR files we won't
+ * change this in the 3.x series, so when calling this routine you should use:
+ *
+ * icoul=0 no coulomb interaction
+ * icoul=1 cutoff standard coulomb
+ * icoul=2 reaction-field coulomb
+ * icoul=3 tabulated coulomb
+ *
+ * ivdw=0 no vdw interaction
+ * ivdw=1 standard L-J interaction
+ * ivdw=2 Buckingham
+ * ivdw=3 tabulated vdw.
+ *
+ * Kind of ugly, but it works.
+ */
+static void init_nblist(t_nblist *nl_sr,t_nblist *nl_lr,
+                        int maxsr,int maxlr,
+                        int ivdw, int icoul, 
+                        gmx_bool bfree, int enlist)
+{
+    t_nblist *nl;
+    int      homenr;
+    int      i,nn;
+    
+    int inloop[20] =
+    { 
+        eNR_NBKERNEL_NONE,
+        eNR_NBKERNEL010,
+        eNR_NBKERNEL020,
+        eNR_NBKERNEL030,
+        eNR_NBKERNEL100,
+        eNR_NBKERNEL110,
+        eNR_NBKERNEL120,
+        eNR_NBKERNEL130,
+        eNR_NBKERNEL200,
+        eNR_NBKERNEL210,
+        eNR_NBKERNEL220,
+        eNR_NBKERNEL230,
+        eNR_NBKERNEL300,
+        eNR_NBKERNEL310,
+        eNR_NBKERNEL320,
+        eNR_NBKERNEL330,
+        eNR_NBKERNEL400,
+        eNR_NBKERNEL410,
+        eNR_NBKERNEL_NONE,
+        eNR_NBKERNEL430
+    };
+  
+    for(i=0; (i<2); i++)
+    {
+        nl     = (i == 0) ? nl_sr : nl_lr;
+        homenr = (i == 0) ? maxsr : maxlr;
+
+        if (nl == NULL)
+        {
+            continue;
+        }
+        
+        /* Set coul/vdw in neighborlist, and for the normal loops we determine
+         * an index of which one to call.
+         */
+        nl->ivdw  = ivdw;
+        nl->icoul = icoul;
+        nl->free_energy = bfree;
+    
+        if (bfree)
+        {
+            nl->enlist  = enlistATOM_ATOM;
+            nl->il_code = eNR_NBKERNEL_FREE_ENERGY;
+        }
+        else
+        {
+            nl->enlist = enlist;
+
+            nn = inloop[4*icoul + ivdw];
+            
+            /* solvent loops follow directly after the corresponding
+            * ordinary loops, in the order:
+            *
+            * SPC, SPC-SPC, TIP4p, TIP4p-TIP4p
+            *   
+            */
+            switch (enlist) {
+            case enlistATOM_ATOM:
+            case enlistCG_CG:
+                break;
+            case enlistSPC_ATOM:     nn += 1; break;
+            case enlistSPC_SPC:      nn += 2; break;
+            case enlistTIP4P_ATOM:   nn += 3; break;
+            case enlistTIP4P_TIP4P:  nn += 4; break;
+            }
+            
+            nl->il_code = nn;
+        }
+
+        if (debug)
+            fprintf(debug,"Initiating neighbourlist type %d for %s interactions,\nwith %d SR, %d LR atoms.\n",
+                    nl->il_code,ENLISTTYPE(enlist),maxsr,maxlr);
+        
+        /* maxnri is influenced by the number of shifts (maximum is 8)
+         * and the number of energy groups.
+         * If it is not enough, nl memory will be reallocated during the run.
+         * 4 seems to be a reasonable factor, which only causes reallocation
+         * during runs with tiny and many energygroups.
+         */
+        nl->maxnri      = homenr*4;
+        nl->maxnrj      = 0;
+        nl->maxlen      = 0;
+        nl->nri         = -1;
+        nl->nrj         = 0;
+        nl->iinr        = NULL;
+        nl->gid         = NULL;
+        nl->shift       = NULL;
+        nl->jindex      = NULL;
+        reallocate_nblist(nl);
+        nl->jindex[0] = 0;
+#ifdef GMX_THREAD_SHM_FDECOMP
+        nl->counter = 0;
+        snew(nl->mtx,1);
+        pthread_mutex_init(nl->mtx,NULL);
+#endif
+    }
+}
+
+void init_neighbor_list(FILE *log,t_forcerec *fr,int homenr)
+{
+   /* Make maxlr tunable! (does not seem to be a big difference though) 
+    * This parameter determines the number of i particles in a long range 
+    * neighbourlist. Too few means many function calls, too many means
+    * cache trashing.
+    */
+   int maxsr,maxsr_wat,maxlr,maxlr_wat;
+   int icoul,icoulf,ivdw;
+   int solvent;
+   int enlist_def,enlist_w,enlist_ww;
+   int i;
+   t_nblists *nbl;
+
+   /* maxsr     = homenr-fr->nWatMol*3; */
+   maxsr     = homenr;
+
+   if (maxsr < 0)
+   {
+     gmx_fatal(FARGS,"%s, %d: Negative number of short range atoms.\n"
+                "Call your Gromacs dealer for assistance.",__FILE__,__LINE__);
+   }
+   /* This is just for initial allocation, so we do not reallocate
+    * all the nlist arrays many times in a row.
+    * The numbers seem very accurate, but they are uncritical.
+    */
+   maxsr_wat = min(fr->nWatMol,(homenr+2)/3); 
+   if (fr->bTwinRange) 
+   {
+       maxlr     = 50;
+       maxlr_wat = min(maxsr_wat,maxlr);
+   }
+   else
+   {
+     maxlr = maxlr_wat = 0;
+   }  
+
+   /* Determine the values for icoul/ivdw. */
+   /* Start with GB */
+   if(fr->bGB)
+   {
+       icoul=4;
+   }
+   else if (fr->bcoultab)
+   {
+       icoul = 3;
+   }
+   else if (EEL_RF(fr->eeltype))
+   {
+       icoul = 2;
+   }
+   else 
+   {
+       icoul = 1;
+   }
+   
+   if (fr->bvdwtab)
+   {
+       ivdw = 3;
+   }
+   else if (fr->bBHAM)
+   {
+       ivdw = 2;
+   }
+   else 
+   {
+       ivdw = 1;
+   }
+
+   fr->ns.bCGlist = (getenv("GMX_NBLISTCG") != 0);
+   if (!fr->ns.bCGlist)
+   {
+       enlist_def = enlistATOM_ATOM;
+   }
+   else
+   {
+       enlist_def = enlistCG_CG;
+       if (log != NULL)
+       {
+           fprintf(log,"\nUsing charge-group - charge-group neighbor lists and kernels\n\n");
+       }
+       if (!fr->bExcl_IntraCGAll_InterCGNone)
+       {
+           gmx_fatal(FARGS,"The charge-group - charge-group force loops only support systems with all intra-cg interactions excluded and no inter-cg exclusions, this is not the case for this system.");
+       }
+   }
+   
+   if (fr->solvent_opt == esolTIP4P) {
+       enlist_w  = enlistTIP4P_ATOM;
+       enlist_ww = enlistTIP4P_TIP4P;
+   } else {
+       enlist_w  = enlistSPC_ATOM;
+       enlist_ww = enlistSPC_SPC;
+   }
+
+   for(i=0; i<fr->nnblists; i++) 
+   {
+       nbl = &(fr->nblists[i]);
+       init_nblist(&nbl->nlist_sr[eNL_VDWQQ],&nbl->nlist_lr[eNL_VDWQQ],
+                   maxsr,maxlr,ivdw,icoul,FALSE,enlist_def);
+       init_nblist(&nbl->nlist_sr[eNL_VDW],&nbl->nlist_lr[eNL_VDW],
+                   maxsr,maxlr,ivdw,0,FALSE,enlist_def);
+       init_nblist(&nbl->nlist_sr[eNL_QQ],&nbl->nlist_lr[eNL_QQ],
+                   maxsr,maxlr,0,icoul,FALSE,enlist_def);
+       init_nblist(&nbl->nlist_sr[eNL_VDWQQ_WATER],&nbl->nlist_lr[eNL_VDWQQ_WATER],
+                   maxsr_wat,maxlr_wat,ivdw,icoul, FALSE,enlist_w);
+       init_nblist(&nbl->nlist_sr[eNL_QQ_WATER],&nbl->nlist_lr[eNL_QQ_WATER],
+                   maxsr_wat,maxlr_wat,0,icoul, FALSE,enlist_w);
+       init_nblist(&nbl->nlist_sr[eNL_VDWQQ_WATERWATER],&nbl->nlist_lr[eNL_VDWQQ_WATERWATER],
+                   maxsr_wat,maxlr_wat,ivdw,icoul, FALSE,enlist_ww);
+       init_nblist(&nbl->nlist_sr[eNL_QQ_WATERWATER],&nbl->nlist_lr[eNL_QQ_WATERWATER],
+                   maxsr_wat,maxlr_wat,0,icoul, FALSE,enlist_ww);
+       
+       if (fr->efep != efepNO) 
+       {
+           if (fr->bEwald)
+           {
+               icoulf = 5;
+           }
+           else
+           {
+               icoulf = icoul;
+           }
+
+           init_nblist(&nbl->nlist_sr[eNL_VDWQQ_FREE],&nbl->nlist_lr[eNL_VDWQQ_FREE],
+                       maxsr,maxlr,ivdw,icoulf,TRUE,enlistATOM_ATOM);
+           init_nblist(&nbl->nlist_sr[eNL_VDW_FREE],&nbl->nlist_lr[eNL_VDW_FREE],
+                       maxsr,maxlr,ivdw,0,TRUE,enlistATOM_ATOM);
+           init_nblist(&nbl->nlist_sr[eNL_QQ_FREE],&nbl->nlist_lr[eNL_QQ_FREE],
+                       maxsr,maxlr,0,icoulf,TRUE,enlistATOM_ATOM);
+       }  
+   }
+   /* QMMM MM list */
+   if (fr->bQMMM && fr->qr->QMMMscheme != eQMMMschemeoniom)
+   {
+       init_nblist(&fr->QMMMlist,NULL,
+                   maxsr,maxlr,0,icoul,FALSE,enlistATOM_ATOM);
+   }
+
+   fr->ns.nblist_initialized=TRUE;
+}
+
+static void reset_nblist(t_nblist *nl)
+{
+     nl->nri       = -1;
+     nl->nrj       = 0;
+     nl->maxlen    = 0;
+     if (nl->jindex)
+     {
+         nl->jindex[0] = 0;
+     }
+}
+
+static void reset_neighbor_list(t_forcerec *fr,gmx_bool bLR,int nls,int eNL)
+{
+    int n,i;
+  
+    if (bLR) 
+    {
+        reset_nblist(&(fr->nblists[nls].nlist_lr[eNL]));
+    }
+    else 
+    {
+        for(n=0; n<fr->nnblists; n++)
+        {
+            for(i=0; i<eNL_NR; i++)
+            {
+                reset_nblist(&(fr->nblists[n].nlist_sr[i]));
+            }
+        }
+        if (fr->bQMMM)
+        { 
+            /* only reset the short-range nblist */
+            reset_nblist(&(fr->QMMMlist));
+        }
+    }
+}
+
+
+
+
+static inline void new_i_nblist(t_nblist *nlist,
+                                gmx_bool bLR,atom_id i_atom,int shift,int gid)
+{
+    int    i,k,nri,nshift;
+    
+    nri = nlist->nri;
+    
+    /* Check whether we have to increase the i counter */
+    if ((nri == -1) ||
+        (nlist->iinr[nri]  != i_atom) || 
+        (nlist->shift[nri] != shift) || 
+        (nlist->gid[nri]   != gid))
+    {
+        /* This is something else. Now see if any entries have 
+         * been added in the list of the previous atom.
+         */
+        if ((nri == -1) ||
+            ((nlist->jindex[nri+1] > nlist->jindex[nri]) && 
+             (nlist->gid[nri] != -1)))
+        {
+            /* If so increase the counter */
+            nlist->nri++;
+            nri++;
+            if (nlist->nri >= nlist->maxnri)
+            {
+                nlist->maxnri += over_alloc_large(nlist->nri);
+                reallocate_nblist(nlist);
+            }
+        }
+        /* Set the number of neighbours and the atom number */
+        nlist->jindex[nri+1] = nlist->jindex[nri];
+        nlist->iinr[nri]     = i_atom;
+        nlist->gid[nri]      = gid;
+        nlist->shift[nri]    = shift;
+    }
+}
+
+static inline void close_i_nblist(t_nblist *nlist) 
+{
+    int nri = nlist->nri;
+    int len;
+    
+    if (nri >= 0)
+    {
+        nlist->jindex[nri+1] = nlist->nrj;
+        
+        len=nlist->nrj -  nlist->jindex[nri];
+        
+        /* nlist length for water i molecules is treated statically 
+         * in the innerloops 
+         */
+        if (len > nlist->maxlen)
+        {
+            nlist->maxlen = len;
+        }
+    }
+}
+
+static inline void close_nblist(t_nblist *nlist)
+{
+    /* Only close this nblist when it has been initialized.
+     * Avoid the creation of i-lists with no j-particles.
+     */
+    if (nlist->nrj == 0)
+    {
+        /* Some assembly kernels do not support empty lists,
+         * make sure here that we don't generate any empty lists.
+         * With the current ns code this branch is taken in two cases:
+         * No i-particles at all: nri=-1 here
+         * There are i-particles, but no j-particles; nri=0 here
+         */
+        nlist->nri = 0;
+    }
+    else
+    {
+        /* Close list number nri by incrementing the count */
+        nlist->nri++;
+    }
+}
+
+static inline void close_neighbor_list(t_forcerec *fr,gmx_bool bLR,int nls,int eNL, 
+                                       gmx_bool bMakeQMMMnblist)
+{
+    int n,i;
+    
+    if (bMakeQMMMnblist) {
+        if (!bLR)
+        {
+            close_nblist(&(fr->QMMMlist));
+        }
+    }
+    else 
+    {
+        if (bLR)
+        {
+            close_nblist(&(fr->nblists[nls].nlist_lr[eNL]));
+        }
+        else
+        { 
+            for(n=0; n<fr->nnblists; n++)
+            {
+                for(i=0; (i<eNL_NR); i++)
+                {
+                    close_nblist(&(fr->nblists[n].nlist_sr[i]));
+                }
+            }
+        }
+    }
+}
+
+static inline void add_j_to_nblist(t_nblist *nlist,atom_id j_atom,gmx_bool bLR)
+{
+    int nrj=nlist->nrj;
+    
+    if (nlist->nrj >= nlist->maxnrj)
+    {
+        nlist->maxnrj = over_alloc_small(nlist->nrj + 1);
+        if (gmx_debug_at)
+            fprintf(debug,"Increasing %s nblist %s j size to %d\n",
+                    bLR ? "LR" : "SR",nrnb_str(nlist->il_code),nlist->maxnrj);
+        
+        srenew(nlist->jjnr,nlist->maxnrj);
+    }
+
+    nlist->jjnr[nrj] = j_atom;
+    nlist->nrj ++;
+}
+
+static inline void add_j_to_nblist_cg(t_nblist *nlist,
+                                      atom_id j_start,int j_end,
+                                      t_excl *bexcl,gmx_bool bLR)
+{
+    int nrj=nlist->nrj;
+    int j;
+
+    if (nlist->nrj >= nlist->maxnrj)
+    {
+        nlist->maxnrj = over_alloc_small(nlist->nrj + 1);
+        if (gmx_debug_at)
+            fprintf(debug,"Increasing %s nblist %s j size to %d\n",
+                    bLR ? "LR" : "SR",nrnb_str(nlist->il_code),nlist->maxnrj);
+        
+        srenew(nlist->jjnr    ,nlist->maxnrj);
+        srenew(nlist->jjnr_end,nlist->maxnrj);
+        srenew(nlist->excl    ,nlist->maxnrj*MAX_CGCGSIZE);
+    }
+
+    nlist->jjnr[nrj]     = j_start;
+    nlist->jjnr_end[nrj] = j_end;
+
+    if (j_end - j_start > MAX_CGCGSIZE)
+    {
+        gmx_fatal(FARGS,"The charge-group - charge-group neighborlist do not support charge groups larger than %d, found a charge group of size %d",MAX_CGCGSIZE,j_end-j_start);
+    }
+
+    /* Set the exclusions */
+    for(j=j_start; j<j_end; j++)
+    {
+        nlist->excl[nrj*MAX_CGCGSIZE + j - j_start] = bexcl[j];
+    }
+
+    nlist->nrj ++;
+}
+
+typedef void
+put_in_list_t(gmx_bool              bHaveVdW[],
+              int               ngid,
+              t_mdatoms *       md,
+              int               icg,
+              int               jgid,
+              int               nj,
+              atom_id           jjcg[],
+              atom_id           index[],
+              t_excl            bExcl[],
+              int               shift,
+              t_forcerec *      fr,
+              gmx_bool              bLR,
+              gmx_bool              bDoVdW,
+              gmx_bool              bDoCoul);
+
+static void 
+put_in_list_at(gmx_bool              bHaveVdW[],
+               int               ngid,
+               t_mdatoms *       md,
+               int               icg,
+               int               jgid,
+               int               nj,
+               atom_id           jjcg[],
+               atom_id           index[],
+               t_excl            bExcl[],
+               int               shift,
+               t_forcerec *      fr,
+               gmx_bool              bLR,
+               gmx_bool              bDoVdW,
+               gmx_bool              bDoCoul)
+{
+    /* The a[] index has been removed,
+     * to put it back in i_atom should be a[i0] and jj should be a[jj].
+     */
+    t_nblist *   vdwc;
+    t_nblist *   vdw;
+    t_nblist *   coul;
+    t_nblist *   vdwc_free  = NULL;
+    t_nblist *   vdw_free   = NULL;
+    t_nblist *   coul_free  = NULL;
+    t_nblist *   vdwc_ww    = NULL;
+    t_nblist *   coul_ww    = NULL;
+    
+    int            i,j,jcg,igid,gid,nbl_ind,ind_ij;
+    atom_id   jj,jj0,jj1,i_atom;
+    int       i0,nicg,len;
+    
+    int       *cginfo;
+    int       *type,*typeB;
+    real      *charge,*chargeB;
+    real      qi,qiB,qq,rlj;
+    gmx_bool      bFreeEnergy,bFree,bFreeJ,bNotEx,*bPert;
+    gmx_bool      bDoVdW_i,bDoCoul_i,bDoCoul_i_sol;
+    int       iwater,jwater;
+    t_nblist  *nlist;
+    
+    /* Copy some pointers */
+    cginfo  = fr->cginfo;
+    charge  = md->chargeA;
+    chargeB = md->chargeB;
+    type    = md->typeA;
+    typeB   = md->typeB;
+    bPert   = md->bPerturbed;
+    
+    /* Get atom range */
+    i0     = index[icg];
+    nicg   = index[icg+1]-i0;
+    
+    /* Get the i charge group info */
+    igid   = GET_CGINFO_GID(cginfo[icg]);
+    iwater = GET_CGINFO_SOLOPT(cginfo[icg]);
+    
+    bFreeEnergy = FALSE;
+    if (md->nPerturbed) 
+    {
+        /* Check if any of the particles involved are perturbed. 
+         * If not we can do the cheaper normal put_in_list
+         * and use more solvent optimization.
+         */
+        for(i=0; i<nicg; i++)
+        {
+            bFreeEnergy |= bPert[i0+i];
+        }
+        /* Loop over the j charge groups */
+        for(j=0; (j<nj && !bFreeEnergy); j++) 
+        {
+            jcg = jjcg[j];
+            jj0 = index[jcg];
+            jj1 = index[jcg+1];
+            /* Finally loop over the atoms in the j-charge group */    
+            for(jj=jj0; jj<jj1; jj++)
+            {
+                bFreeEnergy |= bPert[jj];
+            }
+        }
+    }
+    
+    /* Unpack pointers to neighbourlist structs */
+    if (fr->nnblists == 1)
+    {
+        nbl_ind = 0;
+    }
+    else
+    {
+        nbl_ind = fr->gid2nblists[GID(igid,jgid,ngid)];
+    }
+    if (bLR)
+    {
+        nlist = fr->nblists[nbl_ind].nlist_lr;
+    }
+    else
+    {
+        nlist = fr->nblists[nbl_ind].nlist_sr;
+    }
+    
+    if (iwater != esolNO)
+    {
+        vdwc = &nlist[eNL_VDWQQ_WATER];
+        vdw  = &nlist[eNL_VDW];
+        coul = &nlist[eNL_QQ_WATER];
+#ifndef DISABLE_WATERWATER_NLIST
+        vdwc_ww = &nlist[eNL_VDWQQ_WATERWATER];
+        coul_ww = &nlist[eNL_QQ_WATERWATER];
+#endif
+    } 
+    else 
+    {
+        vdwc = &nlist[eNL_VDWQQ];
+        vdw  = &nlist[eNL_VDW];
+        coul = &nlist[eNL_QQ];
+    }
+    
+    if (!bFreeEnergy) 
+    {
+        if (iwater != esolNO) 
+        {
+            /* Loop over the atoms in the i charge group */    
+            i_atom  = i0;
+            gid     = GID(igid,jgid,ngid);
+            /* Create new i_atom for each energy group */
+            if (bDoCoul && bDoVdW)
+            {
+                new_i_nblist(vdwc,bLR,i_atom,shift,gid);
+#ifndef DISABLE_WATERWATER_NLIST
+                new_i_nblist(vdwc_ww,bLR,i_atom,shift,gid);
+#endif
+            }
+            if (bDoVdW)
+            {
+                new_i_nblist(vdw,bLR,i_atom,shift,gid);
+            }
+            if (bDoCoul) 
+            {
+                new_i_nblist(coul,bLR,i_atom,shift,gid);
+#ifndef DISABLE_WATERWATER_NLIST
+                new_i_nblist(coul_ww,bLR,i_atom,shift,gid);
+#endif
+            }      
+         /* Loop over the j charge groups */
+            for(j=0; (j<nj); j++) 
+            {
+                jcg=jjcg[j];
+                
+                if (jcg == icg)
+                {
+                    continue;
+                }
+                
+                jj0 = index[jcg];
+                jwater = GET_CGINFO_SOLOPT(cginfo[jcg]);
+                
+                if (iwater == esolSPC && jwater == esolSPC)
+                {
+                    /* Interaction between two SPC molecules */
+                    if (!bDoCoul)
+                    {
+                        /* VdW only - only first atoms in each water interact */
+                        add_j_to_nblist(vdw,jj0,bLR);
+                    }
+                    else 
+                    {
+#ifdef DISABLE_WATERWATER_NLIST        
+                        /* Add entries for the three atoms - only do VdW if we need to */
+                        if (!bDoVdW)
+                        {
+                            add_j_to_nblist(coul,jj0,bLR);
+                        }
+                        else
+                        {
+                            add_j_to_nblist(vdwc,jj0,bLR);
+                        }
+                        add_j_to_nblist(coul,jj0+1,bLR);
+                        add_j_to_nblist(coul,jj0+2,bLR);           
+#else
+                        /* One entry for the entire water-water interaction */
+                        if (!bDoVdW)
+                        {
+                            add_j_to_nblist(coul_ww,jj0,bLR);
+                        }
+                        else
+                        {
+                            add_j_to_nblist(vdwc_ww,jj0,bLR);
+                        }
+#endif
+                    }  
+                } 
+                else if (iwater == esolTIP4P && jwater == esolTIP4P) 
+                {
+                    /* Interaction between two TIP4p molecules */
+                    if (!bDoCoul)
+                    {
+                        /* VdW only - only first atoms in each water interact */
+                        add_j_to_nblist(vdw,jj0,bLR);
+                    }
+                    else 
+                    {
+#ifdef DISABLE_WATERWATER_NLIST        
+                        /* Add entries for the four atoms - only do VdW if we need to */
+                        if (bDoVdW)
+                        {
+                            add_j_to_nblist(vdw,jj0,bLR);
+                        }
+                        add_j_to_nblist(coul,jj0+1,bLR);
+                        add_j_to_nblist(coul,jj0+2,bLR);           
+                        add_j_to_nblist(coul,jj0+3,bLR);           
+#else
+                        /* One entry for the entire water-water interaction */
+                        if (!bDoVdW)
+                        {
+                            add_j_to_nblist(coul_ww,jj0,bLR);
+                        }
+                        else
+                        {
+                            add_j_to_nblist(vdwc_ww,jj0,bLR);
+                        }
+#endif
+                    }                                          
+                }
+                else 
+                {
+                    /* j charge group is not water, but i is.
+                     * Add entries to the water-other_atom lists; the geometry of the water
+                     * molecule doesn't matter - that is taken care of in the nonbonded kernel,
+                     * so we don't care if it is SPC or TIP4P...
+                     */
+                    
+                    jj1 = index[jcg+1];
+                    
+                    if (!bDoVdW) 
+                    {
+                        for(jj=jj0; (jj<jj1); jj++) 
+                        {
+                            if (charge[jj] != 0)
+                            {
+                                add_j_to_nblist(coul,jj,bLR);
+                            }
+                        }
+                    }
+                    else if (!bDoCoul)
+                    {
+                        for(jj=jj0; (jj<jj1); jj++)
+                        {
+                            if (bHaveVdW[type[jj]])
+                            {
+                                add_j_to_nblist(vdw,jj,bLR);
+                            }
+                        }
+                    }
+                    else 
+                    {
+                        /* _charge_ _groups_ interact with both coulomb and LJ */
+                        /* Check which atoms we should add to the lists!       */
+                        for(jj=jj0; (jj<jj1); jj++) 
+                        {
+                            if (bHaveVdW[type[jj]]) 
+                            {
+                                if (charge[jj] != 0)
+                                {
+                                    add_j_to_nblist(vdwc,jj,bLR);
+                                }
+                                else
+                                {
+                                    add_j_to_nblist(vdw,jj,bLR);
+                                }
+                            }
+                            else if (charge[jj] != 0)
+                            {
+                                add_j_to_nblist(coul,jj,bLR);
+                            }
+                        }
+                    }
+                }
+            }
+            close_i_nblist(vdw); 
+            close_i_nblist(coul); 
+            close_i_nblist(vdwc);  
+#ifndef DISABLE_WATERWATER_NLIST
+            close_i_nblist(coul_ww);
+            close_i_nblist(vdwc_ww); 
+#endif
+        } 
+        else
+        { 
+            /* no solvent as i charge group */
+            /* Loop over the atoms in the i charge group */    
+            for(i=0; i<nicg; i++) 
+            {
+                i_atom  = i0+i;
+                gid     = GID(igid,jgid,ngid);
+                qi      = charge[i_atom];
+                
+                /* Create new i_atom for each energy group */
+                if (bDoVdW && bDoCoul)
+                {
+                    new_i_nblist(vdwc,bLR,i_atom,shift,gid);
+                }
+                if (bDoVdW)
+                {
+                    new_i_nblist(vdw,bLR,i_atom,shift,gid);
+                }
+                if (bDoCoul)
+                {
+                    new_i_nblist(coul,bLR,i_atom,shift,gid);
+                }
+                bDoVdW_i  = (bDoVdW  && bHaveVdW[type[i_atom]]);
+                bDoCoul_i = (bDoCoul && qi!=0);
+                
+                if (bDoVdW_i || bDoCoul_i) 
+                {
+                    /* Loop over the j charge groups */
+                    for(j=0; (j<nj); j++) 
+                    {
+                        jcg=jjcg[j];
+                        
+                        /* Check for large charge groups */
+                        if (jcg == icg)
+                        {
+                            jj0 = i0 + i + 1;
+                        }
+                        else
+                        {
+                            jj0 = index[jcg];
+                        }
+                        
+                        jj1=index[jcg+1];
+                        /* Finally loop over the atoms in the j-charge group */        
+                        for(jj=jj0; jj<jj1; jj++) 
+                        {
+                            bNotEx = NOTEXCL(bExcl,i,jj);
+                            
+                            if (bNotEx) 
+                            {
+                                if (!bDoVdW_i) 
+                                { 
+                                    if (charge[jj] != 0)
+                                    {
+                                        add_j_to_nblist(coul,jj,bLR);
+                                    }
+                                }
+                                else if (!bDoCoul_i) 
+                                {
+                                    if (bHaveVdW[type[jj]])
+                                    {
+                                        add_j_to_nblist(vdw,jj,bLR);
+                                    }
+                                }
+                                else 
+                                {
+                                    if (bHaveVdW[type[jj]]) 
+                                    {
+                                        if (charge[jj] != 0)
+                                        {
+                                            add_j_to_nblist(vdwc,jj,bLR);
+                                        }
+                                        else
+                                        {
+                                            add_j_to_nblist(vdw,jj,bLR);
+                                        }
+                                    } 
+                                    else if (charge[jj] != 0)
+                                    {
+                                        add_j_to_nblist(coul,jj,bLR);
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+                close_i_nblist(vdw);
+                close_i_nblist(coul);
+                close_i_nblist(vdwc);
+            }
+        }
+    }
+    else
+    {
+        /* we are doing free energy */
+        vdwc_free = &nlist[eNL_VDWQQ_FREE];
+        vdw_free  = &nlist[eNL_VDW_FREE];
+        coul_free = &nlist[eNL_QQ_FREE];
+        /* Loop over the atoms in the i charge group */    
+        for(i=0; i<nicg; i++) 
+        {
+            i_atom  = i0+i;
+            gid     = GID(igid,jgid,ngid);
+            qi      = charge[i_atom];
+            qiB     = chargeB[i_atom];
+            
+            /* Create new i_atom for each energy group */
+            if (bDoVdW && bDoCoul) 
+                new_i_nblist(vdwc,bLR,i_atom,shift,gid);
+            if (bDoVdW)   
+                new_i_nblist(vdw,bLR,i_atom,shift,gid);
+            if (bDoCoul) 
+                new_i_nblist(coul,bLR,i_atom,shift,gid);
+            
+            new_i_nblist(vdw_free,bLR,i_atom,shift,gid);
+            new_i_nblist(coul_free,bLR,i_atom,shift,gid);
+            new_i_nblist(vdwc_free,bLR,i_atom,shift,gid);
+            
+            bDoVdW_i  = (bDoVdW  &&
+                         (bHaveVdW[type[i_atom]] || bHaveVdW[typeB[i_atom]]));
+            bDoCoul_i = (bDoCoul && (qi!=0 || qiB!=0));
+            /* For TIP4P the first atom does not have a charge,
+             * but the last three do. So we should still put an atom
+             * without LJ but with charge in the water-atom neighborlist
+             * for a TIP4p i charge group.
+             * For SPC type water the first atom has LJ and charge,
+             * so there is no such problem.
+             */
+            if (iwater == esolNO)
+            {
+                bDoCoul_i_sol = bDoCoul_i;
+            }
+            else
+            {
+                bDoCoul_i_sol = bDoCoul;
+            }
+            
+            if (bDoVdW_i || bDoCoul_i_sol) 
+            {
+                /* Loop over the j charge groups */
+                for(j=0; (j<nj); j++)
+                {
+                    jcg=jjcg[j];
+                    
+                    /* Check for large charge groups */
+                    if (jcg == icg)
+                    {
+                        jj0 = i0 + i + 1;
+                    }
+                    else
+                    {
+                        jj0 = index[jcg];
+                    }
+                    
+                    jj1=index[jcg+1];
+                    /* Finally loop over the atoms in the j-charge group */    
+                    bFree = bPert[i_atom];
+                    for(jj=jj0; (jj<jj1); jj++) 
+                    {
+                        bFreeJ = bFree || bPert[jj];
+                        /* Complicated if, because the water H's should also
+                         * see perturbed j-particles
+                         */
+                        if (iwater==esolNO || i==0 || bFreeJ) 
+                        {
+                            bNotEx = NOTEXCL(bExcl,i,jj);
+                            
+                            if (bNotEx) 
+                            {
+                                if (bFreeJ)
+                                {
+                                    if (!bDoVdW_i) 
+                                    {
+                                        if (charge[jj]!=0 || chargeB[jj]!=0)
+                                        {
+                                            add_j_to_nblist(coul_free,jj,bLR);
+                                        }
+                                    }
+                                    else if (!bDoCoul_i) 
+                                    {
+                                        if (bHaveVdW[type[jj]] || bHaveVdW[typeB[jj]])
+                                        {
+                                            add_j_to_nblist(vdw_free,jj,bLR);
+                                        }
+                                    }
+                                    else 
+                                    {
+                                        if (bHaveVdW[type[jj]] || bHaveVdW[typeB[jj]]) 
+                                        {
+                                            if (charge[jj]!=0 || chargeB[jj]!=0)
+                                            {
+                                                add_j_to_nblist(vdwc_free,jj,bLR);
+                                            }
+                                            else
+                                            {
+                                                add_j_to_nblist(vdw_free,jj,bLR);
+                                            }
+                                        }
+                                        else if (charge[jj]!=0 || chargeB[jj]!=0)
+                                            add_j_to_nblist(coul_free,jj,bLR);
+                                    }
+                                }
+                                else if (!bDoVdW_i) 
+                                { 
+                                    /* This is done whether or not bWater is set */
+                                    if (charge[jj] != 0)
+                                    {
+                                        add_j_to_nblist(coul,jj,bLR);
+                                    }
+                                }
+                                else if (!bDoCoul_i_sol) 
+                                { 
+                                    if (bHaveVdW[type[jj]])
+                                    {
+                                        add_j_to_nblist(vdw,jj,bLR);
+                                    }
+                                }
+                                else 
+                                {
+                                    if (bHaveVdW[type[jj]]) 
+                                    {
+                                        if (charge[jj] != 0)
+                                        {
+                                            add_j_to_nblist(vdwc,jj,bLR);
+                                        }
+                                        else
+                                        {
+                                            add_j_to_nblist(vdw,jj,bLR);
+                                        }
+                                    } 
+                                    else if (charge[jj] != 0)
+                                    {
+                                        add_j_to_nblist(coul,jj,bLR);
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+            close_i_nblist(vdw);
+            close_i_nblist(coul);
+            close_i_nblist(vdwc);
+            close_i_nblist(vdw_free);
+            close_i_nblist(coul_free);
+            close_i_nblist(vdwc_free);
+        }
+    }
+}
+
+static void 
+put_in_list_qmmm(gmx_bool              bHaveVdW[],
+                 int               ngid,
+                 t_mdatoms *       md,
+                 int               icg,
+                 int               jgid,
+                 int               nj,
+                 atom_id           jjcg[],
+                 atom_id           index[],
+                 t_excl            bExcl[],
+                 int               shift,
+                 t_forcerec *      fr,
+                 gmx_bool              bLR,
+                 gmx_bool              bDoVdW,
+                 gmx_bool              bDoCoul)
+{
+    t_nblist *   coul;
+    int          i,j,jcg,igid,gid;
+    atom_id   jj,jj0,jj1,i_atom;
+    int       i0,nicg;
+    gmx_bool      bNotEx;
+    
+    /* Get atom range */
+    i0     = index[icg];
+    nicg   = index[icg+1]-i0;
+    
+    /* Get the i charge group info */
+    igid   = GET_CGINFO_GID(fr->cginfo[icg]);
+    
+    coul = &fr->QMMMlist;
+    
+    /* Loop over atoms in the ith charge group */
+    for (i=0;i<nicg;i++)
+    {
+        i_atom = i0+i;
+        gid    = GID(igid,jgid,ngid);
+        /* Create new i_atom for each energy group */
+        new_i_nblist(coul,bLR,i_atom,shift,gid);
+        
+        /* Loop over the j charge groups */
+        for (j=0;j<nj;j++)
+        {
+            jcg=jjcg[j];
+            
+            /* Charge groups cannot have QM and MM atoms simultaneously */
+            if (jcg!=icg)
+            {
+                jj0 = index[jcg];
+                jj1 = index[jcg+1];
+                /* Finally loop over the atoms in the j-charge group */
+                for(jj=jj0; jj<jj1; jj++)
+                {
+                    bNotEx = NOTEXCL(bExcl,i,jj);
+                    if(bNotEx)
+                        add_j_to_nblist(coul,jj,bLR);
+                }
+            }
+        }
+        close_i_nblist(coul);
+    }
+}
+
+static void 
+put_in_list_cg(gmx_bool              bHaveVdW[],
+               int               ngid,
+               t_mdatoms *       md,
+               int               icg,
+               int               jgid,
+               int               nj,
+               atom_id           jjcg[],
+               atom_id           index[],
+               t_excl            bExcl[],
+               int               shift,
+               t_forcerec *      fr,
+               gmx_bool              bLR,
+               gmx_bool              bDoVdW,
+               gmx_bool              bDoCoul)
+{
+    int          cginfo;
+    int          igid,gid,nbl_ind;
+    t_nblist *   vdwc;
+    int          j,jcg;
+
+    cginfo = fr->cginfo[icg];
+
+    igid = GET_CGINFO_GID(cginfo);
+    gid  = GID(igid,jgid,ngid);
+
+    /* Unpack pointers to neighbourlist structs */
+    if (fr->nnblists == 1)
+    {
+        nbl_ind = 0;
+    }
+    else
+    {
+        nbl_ind = fr->gid2nblists[gid];
+    }
+    if (bLR)
+    {
+        vdwc = &fr->nblists[nbl_ind].nlist_lr[eNL_VDWQQ];
+    }
+    else
+    {
+        vdwc = &fr->nblists[nbl_ind].nlist_sr[eNL_VDWQQ];
+    }
+
+    /* Make a new neighbor list for charge group icg.
+     * Currently simply one neighbor list is made with LJ and Coulomb.
+     * If required, zero interactions could be removed here
+     * or in the force loop.
+     */
+    new_i_nblist(vdwc,bLR,index[icg],shift,gid);
+    vdwc->iinr_end[vdwc->nri] = index[icg+1];
+
+    for(j=0; (j<nj); j++) 
+    {
+        jcg = jjcg[j];
+        /* Skip the icg-icg pairs if all self interactions are excluded */
+        if (!(jcg == icg && GET_CGINFO_EXCL_INTRA(cginfo)))
+        {
+            /* Here we add the j charge group jcg to the list,
+             * exclusions are also added to the list.
+             */
+            add_j_to_nblist_cg(vdwc,index[jcg],index[jcg+1],bExcl,bLR);
+        }
+    }
+
+    close_i_nblist(vdwc);  
+}
+
+static void setexcl(atom_id start,atom_id end,t_blocka *excl,gmx_bool b,
+                    t_excl bexcl[])
+{
+    atom_id i,k;
+    
+    if (b)
+    {
+        for(i=start; i<end; i++)
+        {
+            for(k=excl->index[i]; k<excl->index[i+1]; k++)
+            {
+                SETEXCL(bexcl,i-start,excl->a[k]);
+            }
+        }
+    }
+    else
+    {
+        for(i=start; i<end; i++)
+        {
+            for(k=excl->index[i]; k<excl->index[i+1]; k++)
+            {
+                RMEXCL(bexcl,i-start,excl->a[k]);
+            }
+        }
+    }
+}
+
+int calc_naaj(int icg,int cgtot)
+{
+    int naaj;
+    
+    if ((cgtot % 2) == 1)
+    {
+        /* Odd number of charge groups, easy */
+        naaj = 1 + (cgtot/2);
+    }
+    else if ((cgtot % 4) == 0)
+    {
+    /* Multiple of four is hard */
+        if (icg < cgtot/2)
+        {
+            if ((icg % 2) == 0)
+            {
+                naaj=1+(cgtot/2);
+            }
+            else
+            {
+                naaj=cgtot/2;
+            }
+        }
+        else
+        {
+            if ((icg % 2) == 1)
+            {
+                naaj=1+(cgtot/2);
+            }
+            else
+            {
+                naaj=cgtot/2;
+            }
+        }
+    }
+    else
+    {
+        /* cgtot/2 = odd */
+        if ((icg % 2) == 0)
+        {
+            naaj=1+(cgtot/2);
+        }
+        else
+        {
+            naaj=cgtot/2;
+        }
+    }
+#ifdef DEBUG
+    fprintf(log,"naaj=%d\n",naaj);
+#endif
+
+    return naaj;
+}
+
+/************************************************
+ *
+ *  S I M P L E      C O R E     S T U F F
+ *
+ ************************************************/
+
+static real calc_image_tric(rvec xi,rvec xj,matrix box,
+                            rvec b_inv,int *shift)
+{
+    /* This code assumes that the cut-off is smaller than
+     * a half times the smallest diagonal element of the box.
+     */
+    const real h25=2.5;
+    real dx,dy,dz;
+    real r2;
+    int  tx,ty,tz;
+    
+    /* Compute diff vector */
+    dz = xj[ZZ] - xi[ZZ];
+    dy = xj[YY] - xi[YY];
+    dx = xj[XX] - xi[XX];
+    
+  /* Perform NINT operation, using trunc operation, therefore
+   * we first add 2.5 then subtract 2 again
+   */
+    tz = dz*b_inv[ZZ] + h25;
+    tz -= 2;
+    dz -= tz*box[ZZ][ZZ];
+    dy -= tz*box[ZZ][YY];
+    dx -= tz*box[ZZ][XX];
+
+    ty = dy*b_inv[YY] + h25;
+    ty -= 2;
+    dy -= ty*box[YY][YY];
+    dx -= ty*box[YY][XX];
+    
+    tx = dx*b_inv[XX]+h25;
+    tx -= 2;
+    dx -= tx*box[XX][XX];
+  
+    /* Distance squared */
+    r2 = (dx*dx) + (dy*dy) + (dz*dz);
+
+    *shift = XYZ2IS(tx,ty,tz);
+
+    return r2;
+}
+
+static real calc_image_rect(rvec xi,rvec xj,rvec box_size,
+                            rvec b_inv,int *shift)
+{
+    const real h15=1.5;
+    real ddx,ddy,ddz;
+    real dx,dy,dz;
+    real r2;
+    int  tx,ty,tz;
+    
+    /* Compute diff vector */
+    dx = xj[XX] - xi[XX];
+    dy = xj[YY] - xi[YY];
+    dz = xj[ZZ] - xi[ZZ];
+  
+    /* Perform NINT operation, using trunc operation, therefore
+     * we first add 1.5 then subtract 1 again
+     */
+    tx = dx*b_inv[XX] + h15;
+    ty = dy*b_inv[YY] + h15;
+    tz = dz*b_inv[ZZ] + h15;
+    tx--;
+    ty--;
+    tz--;
+    
+    /* Correct diff vector for translation */
+    ddx = tx*box_size[XX] - dx;
+    ddy = ty*box_size[YY] - dy;
+    ddz = tz*box_size[ZZ] - dz;
+    
+    /* Distance squared */
+    r2 = (ddx*ddx) + (ddy*ddy) + (ddz*ddz);
+    
+    *shift = XYZ2IS(tx,ty,tz);
+    
+    return r2;
+}
+
+static void add_simple(t_ns_buf *nsbuf,int nrj,atom_id cg_j,
+                       gmx_bool bHaveVdW[],int ngid,t_mdatoms *md,
+                       int icg,int jgid,t_block *cgs,t_excl bexcl[],
+                       int shift,t_forcerec *fr,put_in_list_t *put_in_list)
+{
+    if (nsbuf->nj + nrj > MAX_CG)
+    {
+        put_in_list(bHaveVdW,ngid,md,icg,jgid,nsbuf->ncg,nsbuf->jcg,
+                    cgs->index,bexcl,shift,fr,FALSE,TRUE,TRUE);
+        /* Reset buffer contents */
+        nsbuf->ncg = nsbuf->nj = 0;
+    }
+    nsbuf->jcg[nsbuf->ncg++] = cg_j;
+    nsbuf->nj += nrj;
+}
+
+static void ns_inner_tric(rvec x[],int icg,int *i_egp_flags,
+                          int njcg,atom_id jcg[],
+                          matrix box,rvec b_inv,real rcut2,
+                          t_block *cgs,t_ns_buf **ns_buf,
+                          gmx_bool bHaveVdW[],int ngid,t_mdatoms *md,
+                          t_excl bexcl[],t_forcerec *fr,
+                          put_in_list_t *put_in_list)
+{
+    int      shift;
+    int      j,nrj,jgid;
+    int      *cginfo=fr->cginfo;
+    atom_id  cg_j,*cgindex;
+    t_ns_buf *nsbuf;
+    
+    cgindex = cgs->index;
+    shift   = CENTRAL;
+    for(j=0; (j<njcg); j++)
+    {
+        cg_j   = jcg[j];
+        nrj    = cgindex[cg_j+1]-cgindex[cg_j];
+        if (calc_image_tric(x[icg],x[cg_j],box,b_inv,&shift) < rcut2)
+        {
+            jgid  = GET_CGINFO_GID(cginfo[cg_j]);
+            if (!(i_egp_flags[jgid] & EGP_EXCL))
+            {
+                add_simple(&ns_buf[jgid][shift],nrj,cg_j,
+                           bHaveVdW,ngid,md,icg,jgid,cgs,bexcl,shift,fr,
+                           put_in_list);
+            }
+        }
+    }
+}
+
+static void ns_inner_rect(rvec x[],int icg,int *i_egp_flags,
+                          int njcg,atom_id jcg[],
+                          gmx_bool bBox,rvec box_size,rvec b_inv,real rcut2,
+                          t_block *cgs,t_ns_buf **ns_buf,
+                          gmx_bool bHaveVdW[],int ngid,t_mdatoms *md,
+                          t_excl bexcl[],t_forcerec *fr,
+                          put_in_list_t *put_in_list)
+{
+    int      shift;
+    int      j,nrj,jgid;
+    int      *cginfo=fr->cginfo;
+    atom_id  cg_j,*cgindex;
+    t_ns_buf *nsbuf;
+
+    cgindex = cgs->index;
+    if (bBox)
+    {
+        shift = CENTRAL;
+        for(j=0; (j<njcg); j++)
+        {
+            cg_j   = jcg[j];
+            nrj    = cgindex[cg_j+1]-cgindex[cg_j];
+            if (calc_image_rect(x[icg],x[cg_j],box_size,b_inv,&shift) < rcut2)
+            {
+                jgid  = GET_CGINFO_GID(cginfo[cg_j]);
+                if (!(i_egp_flags[jgid] & EGP_EXCL))
+                {
+                    add_simple(&ns_buf[jgid][shift],nrj,cg_j,
+                               bHaveVdW,ngid,md,icg,jgid,cgs,bexcl,shift,fr,
+                               put_in_list);
+                }
+            }
+        }
+    } 
+    else
+    {
+        for(j=0; (j<njcg); j++)
+        {
+            cg_j   = jcg[j];
+            nrj    = cgindex[cg_j+1]-cgindex[cg_j];
+            if ((rcut2 == 0) || (distance2(x[icg],x[cg_j]) < rcut2)) {
+                jgid  = GET_CGINFO_GID(cginfo[cg_j]);
+                if (!(i_egp_flags[jgid] & EGP_EXCL))
+                {
+                    add_simple(&ns_buf[jgid][CENTRAL],nrj,cg_j,
+                               bHaveVdW,ngid,md,icg,jgid,cgs,bexcl,CENTRAL,fr,
+                               put_in_list);
+                }
+            }
+        }
+    }
+}
+
+/* ns_simple_core needs to be adapted for QMMM still 2005 */
+
+static int ns_simple_core(t_forcerec *fr,
+                          gmx_localtop_t *top,
+                          t_mdatoms *md,
+                          matrix box,rvec box_size,
+                          t_excl bexcl[],atom_id *aaj,
+                          int ngid,t_ns_buf **ns_buf,
+                          put_in_list_t *put_in_list,gmx_bool bHaveVdW[])
+{
+    int      naaj,k;
+    real     rlist2;
+    int      nsearch,icg,jcg,igid,i0,nri,nn;
+    int      *cginfo;
+    t_ns_buf *nsbuf;
+    /* atom_id  *i_atoms; */
+    t_block  *cgs=&(top->cgs);
+    t_blocka *excl=&(top->excls);
+    rvec     b_inv;
+    int      m;
+    gmx_bool     bBox,bTriclinic;
+    int      *i_egp_flags;
+    
+    rlist2 = sqr(fr->rlist);
+    
+    bBox = (fr->ePBC != epbcNONE);
+    if (bBox)
+    {
+        for(m=0; (m<DIM); m++)
+        {
+            b_inv[m] = divide_err(1.0,box_size[m]);
+        }
+        bTriclinic = TRICLINIC(box);
+    }
+    else
+    {
+        bTriclinic = FALSE;
+    }
+    
+    cginfo = fr->cginfo;
+    
+    nsearch=0;
+    for (icg=fr->cg0; (icg<fr->hcg); icg++)
+    {
+        /*
+          i0        = cgs->index[icg];
+          nri       = cgs->index[icg+1]-i0;
+          i_atoms   = &(cgs->a[i0]);
+          i_eg_excl = fr->eg_excl + ngid*md->cENER[*i_atoms];
+          setexcl(nri,i_atoms,excl,TRUE,bexcl);
+        */
+        igid = GET_CGINFO_GID(cginfo[icg]);
+        i_egp_flags = fr->egp_flags + ngid*igid;
+        setexcl(cgs->index[icg],cgs->index[icg+1],excl,TRUE,bexcl);
+        
+        naaj=calc_naaj(icg,cgs->nr);
+        if (bTriclinic)
+        {
+            ns_inner_tric(fr->cg_cm,icg,i_egp_flags,naaj,&(aaj[icg]),
+                          box,b_inv,rlist2,cgs,ns_buf,
+                          bHaveVdW,ngid,md,bexcl,fr,put_in_list);
+        }
+        else
+        {
+            ns_inner_rect(fr->cg_cm,icg,i_egp_flags,naaj,&(aaj[icg]),
+                          bBox,box_size,b_inv,rlist2,cgs,ns_buf,
+                          bHaveVdW,ngid,md,bexcl,fr,put_in_list);
+        }
+        nsearch += naaj;
+        
+        for(nn=0; (nn<ngid); nn++)
+        {
+            for(k=0; (k<SHIFTS); k++)
+            {
+                nsbuf = &(ns_buf[nn][k]);
+                if (nsbuf->ncg > 0)
+                {
+                    put_in_list(bHaveVdW,ngid,md,icg,nn,nsbuf->ncg,nsbuf->jcg,
+                                cgs->index,bexcl,k,fr,FALSE,TRUE,TRUE);
+                    nsbuf->ncg=nsbuf->nj=0;
+                }
+            }
+        }
+        /* setexcl(nri,i_atoms,excl,FALSE,bexcl); */
+        setexcl(cgs->index[icg],cgs->index[icg+1],excl,FALSE,bexcl);
+    }
+    close_neighbor_list(fr,FALSE,-1,-1,FALSE);
+    
+    return nsearch;
+}
+
+/************************************************
+ *
+ *    N S 5     G R I D     S T U F F
+ *
+ ************************************************/
+
+static inline void get_dx(int Nx,real gridx,real rc2,int xgi,real x,
+                          int *dx0,int *dx1,real *dcx2)
+{
+    real dcx,tmp;
+    int  xgi0,xgi1,i;
+    
+    if (xgi < 0)
+    {
+        *dx0 = 0;
+        xgi0 = -1;
+        *dx1 = -1;
+        xgi1 = 0;
+    }
+    else if (xgi >= Nx)
+    {
+        *dx0 = Nx;
+        xgi0 = Nx-1;
+        *dx1 = Nx-1;
+        xgi1 = Nx;
+    }
+    else
+    {
+        dcx2[xgi] = 0;
+        *dx0 = xgi;
+        xgi0 = xgi-1;
+        *dx1 = xgi;
+        xgi1 = xgi+1;
+    }
+    
+    for(i=xgi0; i>=0; i--)
+    {
+        dcx = (i+1)*gridx-x;
+        tmp = dcx*dcx;
+        if (tmp >= rc2)
+            break;
+        *dx0 = i;
+        dcx2[i] = tmp;
+    }
+    for(i=xgi1; i<Nx; i++)
+    {
+        dcx = i*gridx-x;
+        tmp = dcx*dcx;
+        if (tmp >= rc2)
+        {
+            break;
+        }
+        *dx1 = i;
+        dcx2[i] = tmp;
+    }
+}
+
+static inline void get_dx_dd(int Nx,real gridx,real rc2,int xgi,real x,
+                             int ncpddc,int shift_min,int shift_max,
+                             int *g0,int *g1,real *dcx2)
+{
+    real dcx,tmp;
+    int  g_min,g_max,shift_home;
+    
+    if (xgi < 0)
+    {
+        g_min = 0;
+        g_max = Nx - 1;
+        *g0   = 0;
+        *g1   = -1;
+    }
+    else if (xgi >= Nx)
+    {
+        g_min = 0;
+        g_max = Nx - 1;
+        *g0   = Nx;
+        *g1   = Nx - 1;
+    }
+    else
+    {
+        if (ncpddc == 0)
+        {
+            g_min = 0;
+            g_max = Nx - 1;
+        }
+        else
+        {
+            if (xgi < ncpddc)
+            {
+                shift_home = 0;
+            }
+            else
+            {
+                shift_home = -1;
+            }
+            g_min = (shift_min == shift_home ? 0          : ncpddc);
+            g_max = (shift_max == shift_home ? ncpddc - 1 : Nx - 1);
+        }
+        if (shift_min > 0)
+        {
+            *g0 = g_min;
+            *g1 = g_min - 1;
+        }
+        else if (shift_max < 0)
+        {
+            *g0 = g_max + 1;
+            *g1 = g_max;
+        }
+        else
+        {
+            *g0 = xgi;
+            *g1 = xgi;
+            dcx2[xgi] = 0;
+        }
+    }
+    
+    while (*g0 > g_min)
+    {
+        /* Check one grid cell down */
+        dcx = ((*g0 - 1) + 1)*gridx - x;
+        tmp = dcx*dcx;
+        if (tmp >= rc2)
+        {
+            break;
+        }
+        (*g0)--;
+        dcx2[*g0] = tmp;
+    }
+    
+    while (*g1 < g_max)
+    {
+        /* Check one grid cell up */
+        dcx = (*g1 + 1)*gridx - x;
+        tmp = dcx*dcx;
+        if (tmp >= rc2)
+        {
+            break;
+        }
+        (*g1)++;
+        dcx2[*g1] = tmp;
+    }
+}
+
+
+#define sqr(x) ((x)*(x))
+#define calc_dx2(XI,YI,ZI,y) (sqr(XI-y[XX]) + sqr(YI-y[YY]) + sqr(ZI-y[ZZ]))
+#define calc_cyl_dx2(XI,YI,y) (sqr(XI-y[XX]) + sqr(YI-y[YY]))
+/****************************************************
+ *
+ *    F A S T   N E I G H B O R  S E A R C H I N G
+ *
+ *    Optimized neighboursearching routine using grid 
+ *    at least 1x1x1, see GROMACS manual
+ *
+ ****************************************************/
+
+static void do_longrange(t_commrec *cr,gmx_localtop_t *top,t_forcerec *fr,
+                         int ngid,t_mdatoms *md,int icg,
+                         int jgid,int nlr,
+                         atom_id lr[],t_excl bexcl[],int shift,
+                         rvec x[],rvec box_size,t_nrnb *nrnb,
+                         real lambda,real *dvdlambda,
+                         gmx_grppairener_t *grppener,
+                         gmx_bool bDoVdW,gmx_bool bDoCoul,
+                         gmx_bool bEvaluateNow,put_in_list_t *put_in_list,
+                         gmx_bool bHaveVdW[],
+                         gmx_bool bDoForces,rvec *f)
+{
+    int n,i;
+    t_nblist *nl;
+    
+    for(n=0; n<fr->nnblists; n++)
+    {
+        for(i=0; (i<eNL_NR); i++)
+        {
+            nl = &fr->nblists[n].nlist_lr[i];
+            if ((nl->nri > nl->maxnri-32) || bEvaluateNow)
+            {
+                close_neighbor_list(fr,TRUE,n,i,FALSE);
+                /* Evaluate the energies and forces */
+                do_nonbonded(cr,fr,x,f,md,NULL,
+                             grppener->ener[fr->bBHAM ? egBHAMLR : egLJLR],
+                             grppener->ener[egCOULLR],
+                                                        grppener->ener[egGB],box_size,
+                             nrnb,lambda,dvdlambda,n,i,
+                             GMX_DONB_LR | GMX_DONB_FORCES);
+                
+                reset_neighbor_list(fr,TRUE,n,i);
+            }
+        }
+    }
+    
+    if (!bEvaluateNow)
+    {  
+        /* Put the long range particles in a list */
+        /* do_longrange is never called for QMMM  */
+        put_in_list(bHaveVdW,ngid,md,icg,jgid,nlr,lr,top->cgs.index,
+                    bexcl,shift,fr,TRUE,bDoVdW,bDoCoul);
+    }
+}
+
+static void get_cutoff2(t_forcerec *fr,gmx_bool bDoLongRange,
+                        real *rvdw2,real *rcoul2,
+                        real *rs2,real *rm2,real *rl2)
+{
+    *rs2 = sqr(fr->rlist);
+    if (bDoLongRange && fr->bTwinRange)
+    {
+        /* The VdW and elec. LR cut-off's could be different,
+         * so we can not simply set them to rlistlong.
+         */
+        if (EVDW_MIGHT_BE_ZERO_AT_CUTOFF(fr->vdwtype) &&
+            fr->rvdw > fr->rlist)
+        {
+            *rvdw2  = sqr(fr->rlistlong);
+        }
+        else
+        {
+            *rvdw2  = sqr(fr->rvdw);
+        }
+        if (EEL_MIGHT_BE_ZERO_AT_CUTOFF(fr->eeltype) &&
+            fr->rcoulomb > fr->rlist)
+        {
+            *rcoul2 = sqr(fr->rlistlong);
+        }
+        else
+        {
+            *rcoul2 = sqr(fr->rcoulomb);
+        }
+    }
+    else
+    {
+        /* Workaround for a gcc -O3 or -ffast-math problem */
+        *rvdw2  = *rs2;
+        *rcoul2 = *rs2;
+    }
+    *rm2 = min(*rvdw2,*rcoul2);
+    *rl2 = max(*rvdw2,*rcoul2);
+}
+
+static void init_nsgrid_lists(t_forcerec *fr,int ngid,gmx_ns_t *ns)
+{
+    real rvdw2,rcoul2,rs2,rm2,rl2;
+    int j;
+
+    get_cutoff2(fr,TRUE,&rvdw2,&rcoul2,&rs2,&rm2,&rl2);
+
+    /* Short range buffers */
+    snew(ns->nl_sr,ngid);
+    /* Counters */
+    snew(ns->nsr,ngid);
+    snew(ns->nlr_ljc,ngid);
+    snew(ns->nlr_one,ngid);
+    
+    if (rm2 > rs2)
+    {
+            /* Long range VdW and Coul buffers */
+        snew(ns->nl_lr_ljc,ngid);
+    }
+    if (rl2 > rm2)
+    {
+        /* Long range VdW or Coul only buffers */
+        snew(ns->nl_lr_one,ngid);
+    }
+    for(j=0; (j<ngid); j++) {
+        snew(ns->nl_sr[j],MAX_CG);
+        if (rm2 > rs2)
+        {
+            snew(ns->nl_lr_ljc[j],MAX_CG);
+        }
+        if (rl2 > rm2)
+        {
+            snew(ns->nl_lr_one[j],MAX_CG);
+        }
+    }
+    if (debug)
+    {
+        fprintf(debug,
+                "ns5_core: rs2 = %g, rm2 = %g, rl2 = %g (nm^2)\n",
+                rs2,rm2,rl2);
+    }
+}
+
+static int nsgrid_core(FILE *log,t_commrec *cr,t_forcerec *fr,
+                       matrix box,rvec box_size,int ngid,
+                       gmx_localtop_t *top,
+                       t_grid *grid,rvec x[],
+                       t_excl bexcl[],gmx_bool *bExcludeAlleg,
+                       t_nrnb *nrnb,t_mdatoms *md,
+                       real lambda,real *dvdlambda,
+                       gmx_grppairener_t *grppener,
+                       put_in_list_t *put_in_list,
+                       gmx_bool bHaveVdW[],
+                       gmx_bool bDoLongRange,gmx_bool bDoForces,rvec *f,
+                       gmx_bool bMakeQMMMnblist)
+{
+    gmx_ns_t *ns;
+    atom_id **nl_lr_ljc,**nl_lr_one,**nl_sr;
+    int     *nlr_ljc,*nlr_one,*nsr;
+    gmx_domdec_t *dd=NULL;
+    t_block *cgs=&(top->cgs);
+    int     *cginfo=fr->cginfo;
+    /* atom_id *i_atoms,*cgsindex=cgs->index; */
+    ivec    sh0,sh1,shp;
+    int     cell_x,cell_y,cell_z;
+    int     d,tx,ty,tz,dx,dy,dz,cj;
+#ifdef ALLOW_OFFDIAG_LT_HALFDIAG
+    int     zsh_ty,zsh_tx,ysh_tx;
+#endif
+    int     dx0,dx1,dy0,dy1,dz0,dz1;
+    int     Nx,Ny,Nz,shift=-1,j,nrj,nns,nn=-1;
+    real    gridx,gridy,gridz,grid_x,grid_y,grid_z;
+    real    *dcx2,*dcy2,*dcz2;
+    int     zgi,ygi,xgi;
+    int     cg0,cg1,icg=-1,cgsnr,i0,igid,nri,naaj,max_jcg;
+    int     jcg0,jcg1,jjcg,cgj0,jgid;
+    int     *grida,*gridnra,*gridind;
+    gmx_bool    rvdw_lt_rcoul,rcoul_lt_rvdw;
+    rvec    xi,*cgcm,grid_offset;
+    real    r2,rs2,rvdw2,rcoul2,rm2,rl2,XI,YI,ZI,dcx,dcy,dcz,tmp1,tmp2;
+    int     *i_egp_flags;
+    gmx_bool    bDomDec,bTriclinicX,bTriclinicY;
+    ivec    ncpddc;
+    
+    ns = &fr->ns;
+    
+    bDomDec = DOMAINDECOMP(cr);
+    if (bDomDec)
+    {
+        dd = cr->dd;
+    }
+    
+    bTriclinicX = ((YY < grid->npbcdim &&
+                    (!bDomDec || dd->nc[YY]==1) && box[YY][XX] != 0) ||
+                   (ZZ < grid->npbcdim &&
+                    (!bDomDec || dd->nc[ZZ]==1) && box[ZZ][XX] != 0));
+    bTriclinicY =  (ZZ < grid->npbcdim &&
+                    (!bDomDec || dd->nc[ZZ]==1) && box[ZZ][YY] != 0);
+    
+    cgsnr    = cgs->nr;
+
+    get_cutoff2(fr,bDoLongRange,&rvdw2,&rcoul2,&rs2,&rm2,&rl2);
+
+    rvdw_lt_rcoul = (rvdw2 >= rcoul2);
+    rcoul_lt_rvdw = (rcoul2 >= rvdw2);
+    
+    if (bMakeQMMMnblist)
+    {
+        rm2 = rl2;
+        rs2 = rl2;
+    }
+
+    nl_sr     = ns->nl_sr;
+    nsr       = ns->nsr;
+    nl_lr_ljc = ns->nl_lr_ljc;
+    nl_lr_one = ns->nl_lr_one;
+    nlr_ljc   = ns->nlr_ljc;
+    nlr_one   = ns->nlr_one;
+    
+    /* Unpack arrays */
+    cgcm    = fr->cg_cm;
+    Nx      = grid->n[XX];
+    Ny      = grid->n[YY];
+    Nz      = grid->n[ZZ];
+    grida   = grid->a;
+    gridind = grid->index;
+    gridnra = grid->nra;
+    nns     = 0;
+    
+    gridx      = grid->cell_size[XX];
+    gridy      = grid->cell_size[YY];
+    gridz      = grid->cell_size[ZZ];
+    grid_x     = 1/gridx;
+    grid_y     = 1/gridy;
+    grid_z     = 1/gridz;
+    copy_rvec(grid->cell_offset,grid_offset);
+    copy_ivec(grid->ncpddc,ncpddc);
+    dcx2       = grid->dcx2;
+    dcy2       = grid->dcy2;
+    dcz2       = grid->dcz2;
+    
+#ifdef ALLOW_OFFDIAG_LT_HALFDIAG
+    zsh_ty = floor(-box[ZZ][YY]/box[YY][YY]+0.5);
+    zsh_tx = floor(-box[ZZ][XX]/box[XX][XX]+0.5);
+    ysh_tx = floor(-box[YY][XX]/box[XX][XX]+0.5);
+    if (zsh_tx!=0 && ysh_tx!=0)
+    {
+        /* This could happen due to rounding, when both ratios are 0.5 */
+        ysh_tx = 0;
+    }
+#endif
+    
+    debug_gmx();
+
+    if (fr->n_tpi)
+    {
+        /* We only want a list for the test particle */
+        cg0 = cgsnr - 1;
+    }
+    else
+    {
+        cg0 = grid->icg0;
+    }
+    cg1 = grid->icg1;
+
+    /* Set the shift range */
+    for(d=0; d<DIM; d++)
+    {
+        sh0[d] = -1;
+        sh1[d] = 1;
+        /* Check if we need periodicity shifts.
+         * Without PBC or with domain decomposition we don't need them.
+         */
+        if (d >= ePBC2npbcdim(fr->ePBC) || (bDomDec && dd->nc[d] > 1))
+        {
+            shp[d] = 0;
+        }
+        else
+        {
+            if (d == XX &&
+                box[XX][XX] - fabs(box[YY][XX]) - fabs(box[ZZ][XX]) < sqrt(rl2))
+            {
+                shp[d] = 2;
+            }
+            else
+            {
+                shp[d] = 1;
+            }
+        }
+    }
+    
+    /* Loop over charge groups */
+    for(icg=cg0; (icg < cg1); icg++)
+    {
+        igid = GET_CGINFO_GID(cginfo[icg]);
+        /* Skip this charge group if all energy groups are excluded! */
+        if (bExcludeAlleg[igid])
+        {
+            continue;
+        }
+        
+        i0   = cgs->index[icg];
+        
+        if (bMakeQMMMnblist)
+        { 
+            /* Skip this charge group if it is not a QM atom while making a
+             * QM/MM neighbourlist
+             */
+            if (md->bQM[i0]==FALSE)
+            {
+                continue; /* MM particle, go to next particle */ 
+            }
+            
+            /* Compute the number of charge groups that fall within the control
+             * of this one (icg)
+             */
+            naaj    = calc_naaj(icg,cgsnr);
+            jcg0    = icg;
+            jcg1    = icg + naaj;
+            max_jcg = cgsnr;       
+        } 
+        else
+        { 
+            /* make a normal neighbourlist */
+            
+            if (bDomDec)
+            {
+                /* Get the j charge-group and dd cell shift ranges */
+                dd_get_ns_ranges(cr->dd,icg,&jcg0,&jcg1,sh0,sh1);
+                max_jcg = 0;
+            }
+            else
+            {
+                /* Compute the number of charge groups that fall within the control
+                 * of this one (icg)
+                 */
+                naaj = calc_naaj(icg,cgsnr);
+                jcg0 = icg;
+                jcg1 = icg + naaj;
+                
+                if (fr->n_tpi)
+                {
+                    /* The i-particle is awlways the test particle,
+                     * so we want all j-particles
+                     */
+                    max_jcg = cgsnr - 1;
+                }
+                else
+                {
+                    max_jcg  = jcg1 - cgsnr;
+                }
+            }
+        }
+        
+        i_egp_flags = fr->egp_flags + igid*ngid;
+        
+        /* Set the exclusions for the atoms in charge group icg using a bitmask */
+        setexcl(i0,cgs->index[icg+1],&top->excls,TRUE,bexcl);
+        
+        ci2xyz(grid,icg,&cell_x,&cell_y,&cell_z);
+        
+        /* Changed iicg to icg, DvdS 990115 
+         * (but see consistency check above, DvdS 990330) 
+         */
+#ifdef NS5DB
+        fprintf(log,"icg=%5d, naaj=%5d, cell %d %d %d\n",
+                icg,naaj,cell_x,cell_y,cell_z);
+#endif
+        /* Loop over shift vectors in three dimensions */
+        for (tz=-shp[ZZ]; tz<=shp[ZZ]; tz++)
+        {
+            ZI = cgcm[icg][ZZ]+tz*box[ZZ][ZZ];
+            /* Calculate range of cells in Z direction that have the shift tz */
+            zgi = cell_z + tz*Nz;
+#define FAST_DD_NS
+#ifndef FAST_DD_NS
+            get_dx(Nz,gridz,rl2,zgi,ZI,&dz0,&dz1,dcz2);
+#else
+            get_dx_dd(Nz,gridz,rl2,zgi,ZI-grid_offset[ZZ],
+                      ncpddc[ZZ],sh0[ZZ],sh1[ZZ],&dz0,&dz1,dcz2);
+#endif
+            if (dz0 > dz1)
+            {
+                continue;
+            }
+            for (ty=-shp[YY]; ty<=shp[YY]; ty++)
+            {
+                YI = cgcm[icg][YY]+ty*box[YY][YY]+tz*box[ZZ][YY];
+                /* Calculate range of cells in Y direction that have the shift ty */
+                if (bTriclinicY)
+                {
+                    ygi = (int)(Ny + (YI - grid_offset[YY])*grid_y) - Ny;
+                }
+                else
+                {
+                    ygi = cell_y + ty*Ny;
+                }
+#ifndef FAST_DD_NS
+                get_dx(Ny,gridy,rl2,ygi,YI,&dy0,&dy1,dcy2);
+#else
+                get_dx_dd(Ny,gridy,rl2,ygi,YI-grid_offset[YY],
+                          ncpddc[YY],sh0[YY],sh1[YY],&dy0,&dy1,dcy2);
+#endif
+                if (dy0 > dy1)
+                {
+                    continue;
+                }
+                for (tx=-shp[XX]; tx<=shp[XX]; tx++)
+                {
+                    XI = cgcm[icg][XX]+tx*box[XX][XX]+ty*box[YY][XX]+tz*box[ZZ][XX];
+                    /* Calculate range of cells in X direction that have the shift tx */
+                    if (bTriclinicX)
+                    {
+                        xgi = (int)(Nx + (XI - grid_offset[XX])*grid_x) - Nx;
+                    }
+                    else
+                    {
+                        xgi = cell_x + tx*Nx;
+                    }
+#ifndef FAST_DD_NS
+                    get_dx(Nx,gridx,rl2,xgi*Nx,XI,&dx0,&dx1,dcx2);
+#else
+                    get_dx_dd(Nx,gridx,rl2,xgi,XI-grid_offset[XX],
+                              ncpddc[XX],sh0[XX],sh1[XX],&dx0,&dx1,dcx2);
+#endif
+                    if (dx0 > dx1)
+                    {
+                        continue;
+                    }
+                    /* Get shift vector */       
+                    shift=XYZ2IS(tx,ty,tz);
+#ifdef NS5DB
+                    range_check(shift,0,SHIFTS);
+#endif
+                    for(nn=0; (nn<ngid); nn++)
+                    {
+                        nsr[nn]      = 0;
+                        nlr_ljc[nn]  = 0;
+                        nlr_one[nn] = 0;
+                    }
+#ifdef NS5DB
+                    fprintf(log,"shift: %2d, dx0,1: %2d,%2d, dy0,1: %2d,%2d, dz0,1: %2d,%2d\n",
+                            shift,dx0,dx1,dy0,dy1,dz0,dz1);
+                    fprintf(log,"cgcm: %8.3f  %8.3f  %8.3f\n",cgcm[icg][XX],
+                            cgcm[icg][YY],cgcm[icg][ZZ]);
+                    fprintf(log,"xi:   %8.3f  %8.3f  %8.3f\n",XI,YI,ZI);
+#endif
+                    for (dx=dx0; (dx<=dx1); dx++)
+                    {
+                        tmp1 = rl2 - dcx2[dx];
+                        for (dy=dy0; (dy<=dy1); dy++)
+                        {
+                            tmp2 = tmp1 - dcy2[dy];
+                            if (tmp2 > 0)
+                            {
+                                for (dz=dz0; (dz<=dz1); dz++) {
+                                    if (tmp2 > dcz2[dz]) {
+                                        /* Find grid-cell cj in which possible neighbours are */
+                                        cj   = xyz2ci(Ny,Nz,dx,dy,dz);
+                                        
+                                        /* Check out how many cgs (nrj) there in this cell */
+                                        nrj  = gridnra[cj];
+                                        
+                                        /* Find the offset in the cg list */
+                                        cgj0 = gridind[cj];
+                                        
+                                        /* Check if all j's are out of range so we
+                                         * can skip the whole cell.
+                                         * Should save some time, especially with DD.
+                                         */
+                                        if (nrj == 0 ||
+                                            (grida[cgj0] >= max_jcg &&
+                                             (grida[cgj0] >= jcg1 || grida[cgj0+nrj-1] < jcg0)))
+                                        {
+                                            continue;
+                                        }
+                                        
+                                        /* Loop over cgs */
+                                        for (j=0; (j<nrj); j++)
+                                        {
+                                            jjcg = grida[cgj0+j];
+                                            
+                                            /* check whether this guy is in range! */
+                                            if ((jjcg >= jcg0 && jjcg < jcg1) ||
+                                                (jjcg < max_jcg))
+                                            {
+                                                r2=calc_dx2(XI,YI,ZI,cgcm[jjcg]);
+                                                if (r2 < rl2) {
+                                                    /* jgid = gid[cgsatoms[cgsindex[jjcg]]]; */
+                                                    jgid = GET_CGINFO_GID(cginfo[jjcg]);
+                                                    /* check energy group exclusions */
+                                                    if (!(i_egp_flags[jgid] & EGP_EXCL))
+                                                    {
+                                                        if (r2 < rs2)
+                                                        {
+                                                            if (nsr[jgid] >= MAX_CG)
+                                                            {
+                                                                put_in_list(bHaveVdW,ngid,md,icg,jgid,
+                                                                            nsr[jgid],nl_sr[jgid],
+                                                                            cgs->index,/* cgsatoms, */ bexcl,
+                                                                            shift,fr,FALSE,TRUE,TRUE);
+                                                                nsr[jgid]=0;
+                                                            }
+                                                            nl_sr[jgid][nsr[jgid]++]=jjcg;
+                                                        } 
+                                                        else if (r2 < rm2)
+                                                        {
+                                                            if (nlr_ljc[jgid] >= MAX_CG)
+                                                            {
+                                                                do_longrange(cr,top,fr,ngid,md,icg,jgid,
+                                                                             nlr_ljc[jgid],
+                                                                             nl_lr_ljc[jgid],bexcl,shift,x,
+                                                                             box_size,nrnb,
+                                                                             lambda,dvdlambda,
+                                                                             grppener,
+                                                                             TRUE,TRUE,FALSE,
+                                                                             put_in_list,
+                                                                             bHaveVdW,
+                                                                             bDoForces,f);
+                                                                nlr_ljc[jgid]=0;
+                                                            }
+                                                            nl_lr_ljc[jgid][nlr_ljc[jgid]++]=jjcg;
+                                                        }
+                                                        else
+                                                        {
+                                                            if (nlr_one[jgid] >= MAX_CG) {
+                                                                do_longrange(cr,top,fr,ngid,md,icg,jgid,
+                                                                             nlr_one[jgid],
+                                                                             nl_lr_one[jgid],bexcl,shift,x,
+                                                                             box_size,nrnb,
+                                                                             lambda,dvdlambda,
+                                                                             grppener,
+                                                                             rvdw_lt_rcoul,rcoul_lt_rvdw,FALSE,
+                                                                             put_in_list,
+                                                                             bHaveVdW,
+                                                                             bDoForces,f);
+                                                                nlr_one[jgid]=0;
+                                                            }
+                                                            nl_lr_one[jgid][nlr_one[jgid]++]=jjcg;
+                                                        }
+                                                    }
+                                                }
+                                                nns++;
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                    /* CHECK whether there is anything left in the buffers */
+                    for(nn=0; (nn<ngid); nn++)
+                    {
+                        if (nsr[nn] > 0)
+                        {
+                            put_in_list(bHaveVdW,ngid,md,icg,nn,nsr[nn],nl_sr[nn],
+                                        cgs->index, /* cgsatoms, */ bexcl,
+                                        shift,fr,FALSE,TRUE,TRUE);
+                        }
+                        
+                        if (nlr_ljc[nn] > 0)
+                        {
+                            do_longrange(cr,top,fr,ngid,md,icg,nn,nlr_ljc[nn],
+                                         nl_lr_ljc[nn],bexcl,shift,x,box_size,nrnb,
+                                         lambda,dvdlambda,grppener,TRUE,TRUE,FALSE,
+                                         put_in_list,bHaveVdW,bDoForces,f);
+                        }
+                        
+                        if (nlr_one[nn] > 0)
+                        {
+                            do_longrange(cr,top,fr,ngid,md,icg,nn,nlr_one[nn],
+                                         nl_lr_one[nn],bexcl,shift,x,box_size,nrnb,
+                                         lambda,dvdlambda,grppener,
+                                         rvdw_lt_rcoul,rcoul_lt_rvdw,FALSE,
+                                         put_in_list,bHaveVdW,bDoForces,f);
+                        }
+                    }
+                }
+            }
+        }
+        /* setexcl(nri,i_atoms,&top->atoms.excl,FALSE,bexcl); */
+        setexcl(cgs->index[icg],cgs->index[icg+1],&top->excls,FALSE,bexcl);
+    }
+    /* Perform any left over force calculations */
+    for (nn=0; (nn<ngid); nn++)
+    {
+        if (rm2 > rs2)
+        {
+            do_longrange(cr,top,fr,0,md,icg,nn,nlr_ljc[nn],
+                         nl_lr_ljc[nn],bexcl,shift,x,box_size,nrnb,
+                         lambda,dvdlambda,grppener,
+                         TRUE,TRUE,TRUE,put_in_list,bHaveVdW,bDoForces,f);
+        }
+        if (rl2 > rm2) {
+            do_longrange(cr,top,fr,0,md,icg,nn,nlr_one[nn],
+                         nl_lr_one[nn],bexcl,shift,x,box_size,nrnb,
+                         lambda,dvdlambda,grppener,
+                         rvdw_lt_rcoul,rcoul_lt_rvdw,
+                         TRUE,put_in_list,bHaveVdW,bDoForces,f);
+        }
+    }
+    debug_gmx();
+    
+    /* Close off short range neighbourlists */
+    close_neighbor_list(fr,FALSE,-1,-1,bMakeQMMMnblist);
+    
+    return nns;
+}
+
+void ns_realloc_natoms(gmx_ns_t *ns,int natoms)
+{
+    int i;
+    
+    if (natoms > ns->nra_alloc)
+    {
+        ns->nra_alloc = over_alloc_dd(natoms);
+        srenew(ns->bexcl,ns->nra_alloc);
+        for(i=0; i<ns->nra_alloc; i++)
+        {
+            ns->bexcl[i] = 0;
+        }
+    }
+}
+
+void init_ns(FILE *fplog,const t_commrec *cr,
+             gmx_ns_t *ns,t_forcerec *fr,
+             const gmx_mtop_t *mtop,
+             matrix box)
+{
+    int  mt,icg,nr_in_cg,maxcg,i,j,jcg,ngid,ncg;
+    t_block *cgs;
+    char *ptr;
+    
+    /* Compute largest charge groups size (# atoms) */
+    nr_in_cg=1;
+    for(mt=0; mt<mtop->nmoltype; mt++) {
+        cgs = &mtop->moltype[mt].cgs;
+        for (icg=0; (icg < cgs->nr); icg++)
+        {
+            nr_in_cg=max(nr_in_cg,(int)(cgs->index[icg+1]-cgs->index[icg]));
+        }
+    }
+
+    /* Verify whether largest charge group is <= max cg.
+     * This is determined by the type of the local exclusion type 
+     * Exclusions are stored in bits. (If the type is not large
+     * enough, enlarge it, unsigned char -> unsigned short -> unsigned long)
+     */
+    maxcg = sizeof(t_excl)*8;
+    if (nr_in_cg > maxcg)
+    {
+        gmx_fatal(FARGS,"Max #atoms in a charge group: %d > %d\n",
+                  nr_in_cg,maxcg);
+    }
+    
+    ngid = mtop->groups.grps[egcENER].nr;
+    snew(ns->bExcludeAlleg,ngid);
+    for(i=0; i<ngid; i++) {
+        ns->bExcludeAlleg[i] = TRUE;
+        for(j=0; j<ngid; j++)
+        {
+            if (!(fr->egp_flags[i*ngid+j] & EGP_EXCL))
+            {
+                ns->bExcludeAlleg[i] = FALSE;
+            }
+        }
+    }
+    
+    if (fr->bGrid) {
+        /* Grid search */
+        ns->grid = init_grid(fplog,fr);
+        init_nsgrid_lists(fr,ngid,ns);
+    }
+    else
+    {
+        /* Simple search */
+        snew(ns->ns_buf,ngid);
+        for(i=0; (i<ngid); i++)
+        {
+            snew(ns->ns_buf[i],SHIFTS);
+        }
+        ncg = ncg_mtop(mtop);
+        snew(ns->simple_aaj,2*ncg);
+        for(jcg=0; (jcg<ncg); jcg++)
+        {
+            ns->simple_aaj[jcg]     = jcg;
+            ns->simple_aaj[jcg+ncg] = jcg;
+        }
+    }
+    
+    /* Create array that determines whether or not atoms have VdW */
+    snew(ns->bHaveVdW,fr->ntype);
+    for(i=0; (i<fr->ntype); i++)
+    {
+        for(j=0; (j<fr->ntype); j++)
+        {
+            ns->bHaveVdW[i] = (ns->bHaveVdW[i] || 
+                               (fr->bBHAM ? 
+                                ((BHAMA(fr->nbfp,fr->ntype,i,j) != 0) ||
+                                 (BHAMB(fr->nbfp,fr->ntype,i,j) != 0) ||
+                                 (BHAMC(fr->nbfp,fr->ntype,i,j) != 0)) :
+                                ((C6(fr->nbfp,fr->ntype,i,j) != 0) ||
+                                 (C12(fr->nbfp,fr->ntype,i,j) != 0))));
+        }
+    }
+    if (debug) 
+        pr_bvec(debug,0,"bHaveVdW",ns->bHaveVdW,fr->ntype,TRUE);
+    
+    ns->nra_alloc = 0;
+    ns->bexcl = NULL;
+    if (!DOMAINDECOMP(cr))
+    {
+        /* This could be reduced with particle decomposition */
+        ns_realloc_natoms(ns,mtop->natoms);
+    }
+
+    ns->nblist_initialized=FALSE;
+
+    /* nbr list debug dump */
+    {
+        char *ptr=getenv("GMX_DUMP_NL");
+        if (ptr)
+        {
+            ns->dump_nl=strtol(ptr,NULL,10);
+            if (fplog)
+            {
+                fprintf(fplog, "GMX_DUMP_NL = %d", ns->dump_nl);
+            }
+        }
+        else
+        {
+            ns->dump_nl=0;
+        }
+    }
+}
+
+                        
+int search_neighbours(FILE *log,t_forcerec *fr,
+                      rvec x[],matrix box,
+                      gmx_localtop_t *top,
+                      gmx_groups_t *groups,
+                      t_commrec *cr,
+                      t_nrnb *nrnb,t_mdatoms *md,
+                      real lambda,real *dvdlambda,
+                      gmx_grppairener_t *grppener,
+                      gmx_bool bFillGrid,
+                      gmx_bool bDoLongRange,
+                      gmx_bool bDoForces,rvec *f)
+{
+    t_block  *cgs=&(top->cgs);
+    rvec     box_size,grid_x0,grid_x1;
+    int      i,j,m,ngid;
+    real     min_size,grid_dens;
+    int      nsearch;
+    gmx_bool     bGrid;
+    char     *ptr;
+    gmx_bool     *i_egp_flags;
+    int      cg_start,cg_end,start,end;
+    gmx_ns_t *ns;
+    t_grid   *grid;
+    gmx_domdec_zones_t *dd_zones;
+    put_in_list_t *put_in_list;
+       
+    ns = &fr->ns;
+
+    /* Set some local variables */
+    bGrid = fr->bGrid;
+    ngid = groups->grps[egcENER].nr;
+    
+    for(m=0; (m<DIM); m++)
+    {
+        box_size[m] = box[m][m];
+    }
+  
+    if (fr->ePBC != epbcNONE)
+    {
+        if (sqr(fr->rlistlong) >= max_cutoff2(fr->ePBC,box))
+        {
+            gmx_fatal(FARGS,"One of the box vectors has become shorter than twice the cut-off length or box_yy-|box_zy| or box_zz has become smaller than the cut-off.");
+        }
+        if (!bGrid)
+        {
+            min_size = min(box_size[XX],min(box_size[YY],box_size[ZZ]));
+            if (2*fr->rlistlong >= min_size)
+                gmx_fatal(FARGS,"One of the box diagonal elements has become smaller than twice the cut-off length.");
+        }
+    }
+    
+    if (DOMAINDECOMP(cr))
+    {
+        ns_realloc_natoms(ns,cgs->index[cgs->nr]);
+    }
+    debug_gmx();
+    
+    /* Reset the neighbourlists */
+    reset_neighbor_list(fr,FALSE,-1,-1);
+    
+    if (bGrid && bFillGrid)
+    {
+               
+        grid = ns->grid;
+        if (DOMAINDECOMP(cr))
+        {
+            dd_zones = domdec_zones(cr->dd);
+        }
+        else
+        {
+            dd_zones = NULL;
+
+            get_nsgrid_boundaries(grid,NULL,box,NULL,NULL,NULL,
+                                  cgs->nr,fr->cg_cm,grid_x0,grid_x1,&grid_dens);
+
+            grid_first(log,grid,NULL,NULL,fr->ePBC,box,grid_x0,grid_x1,
+                       fr->rlistlong,grid_dens);
+        }
+        debug_gmx();
+        
+        /* Don't know why this all is... (DvdS 3/99) */
+#ifndef SEGV
+        start = 0;
+        end   = cgs->nr;
+#else
+        start = fr->cg0;
+        end   = (cgs->nr+1)/2;
+#endif
+        
+        if (DOMAINDECOMP(cr))
+        {
+            end = cgs->nr;
+            fill_grid(log,dd_zones,grid,end,-1,end,fr->cg_cm);
+            grid->icg0 = 0;
+            grid->icg1 = dd_zones->izone[dd_zones->nizone-1].cg1;
+        }
+        else
+        {
+            fill_grid(log,NULL,grid,cgs->nr,fr->cg0,fr->hcg,fr->cg_cm);
+            grid->icg0 = fr->cg0;
+            grid->icg1 = fr->hcg;
+            debug_gmx();
+            
+            if (PARTDECOMP(cr))
+                mv_grid(cr,grid);
+            debug_gmx();
+        }
+        
+        calc_elemnr(log,grid,start,end,cgs->nr);
+        calc_ptrs(grid);
+        grid_last(log,grid,start,end,cgs->nr);
+        
+        if (gmx_debug_at)
+        {
+            check_grid(debug,grid);
+            print_grid(debug,grid);
+        }
+    }
+    else if (fr->n_tpi)
+    {
+        /* Set the grid cell index for the test particle only.
+         * The cell to cg index is not corrected, but that does not matter.
+         */
+        fill_grid(log,NULL,ns->grid,fr->hcg,fr->hcg-1,fr->hcg,fr->cg_cm);
+    }
+    debug_gmx();
+    
+    if (!fr->ns.bCGlist)
+    {
+        put_in_list = put_in_list_at;
+    }
+    else
+    {
+        put_in_list = put_in_list_cg;
+    }
+
+    /* Do the core! */
+    if (bGrid)
+    {
+        grid = ns->grid;
+        nsearch = nsgrid_core(log,cr,fr,box,box_size,ngid,top,
+                              grid,x,ns->bexcl,ns->bExcludeAlleg,
+                              nrnb,md,lambda,dvdlambda,grppener,
+                              put_in_list,ns->bHaveVdW,
+                              bDoLongRange,bDoForces,f,
+                              FALSE);
+        
+        /* neighbour searching withouth QMMM! QM atoms have zero charge in
+         * the classical calculation. The charge-charge interaction
+         * between QM and MM atoms is handled in the QMMM core calculation
+         * (see QMMM.c). The VDW however, we'd like to compute classically
+         * and the QM MM atom pairs have just been put in the
+         * corresponding neighbourlists. in case of QMMM we still need to
+         * fill a special QMMM neighbourlist that contains all neighbours
+         * of the QM atoms. If bQMMM is true, this list will now be made: 
+         */
+        if (fr->bQMMM && fr->qr->QMMMscheme!=eQMMMschemeoniom)
+        {
+            nsearch += nsgrid_core(log,cr,fr,box,box_size,ngid,top,
+                                   grid,x,ns->bexcl,ns->bExcludeAlleg,
+                                   nrnb,md,lambda,dvdlambda,grppener,
+                                   put_in_list_qmmm,ns->bHaveVdW,
+                                   bDoLongRange,bDoForces,f,
+                                   TRUE);
+        }
+    }
+    else 
+    {
+        nsearch = ns_simple_core(fr,top,md,box,box_size,
+                                 ns->bexcl,ns->simple_aaj,
+                                 ngid,ns->ns_buf,put_in_list,ns->bHaveVdW);
+    }
+    debug_gmx();
+    
+#ifdef DEBUG
+    pr_nsblock(log);
+#endif
+    
+    inc_nrnb(nrnb,eNR_NS,nsearch);
+    /* inc_nrnb(nrnb,eNR_LR,fr->nlr); */
+    
+    return nsearch;
+}
+
+int natoms_beyond_ns_buffer(t_inputrec *ir,t_forcerec *fr,t_block *cgs,
+                            matrix scale_tot,rvec *x)
+{
+    int  cg0,cg1,cg,a0,a1,a,i,j;
+    real rint,hbuf2,scale;
+    rvec *cg_cm,cgsc;
+    gmx_bool bIsotropic;
+    int  nBeyond;
+    
+    nBeyond = 0;
+    
+    rint = max(ir->rcoulomb,ir->rvdw);
+    if (ir->rlist < rint)
+    {
+        gmx_fatal(FARGS,"The neighbor search buffer has negative size: %f nm",
+                  ir->rlist - rint);
+    }
+    cg_cm = fr->cg_cm;
+    
+    cg0 = fr->cg0;
+    cg1 = fr->hcg;
+    
+    if (!EI_DYNAMICS(ir->eI) || !DYNAMIC_BOX(*ir))
+    {
+        hbuf2 = sqr(0.5*(ir->rlist - rint));
+        for(cg=cg0; cg<cg1; cg++)
+        {
+            a0 = cgs->index[cg];
+            a1 = cgs->index[cg+1];
+            for(a=a0; a<a1; a++)
+            {
+                if (distance2(cg_cm[cg],x[a]) > hbuf2)
+                {
+                    nBeyond++;
+                }
+            }
+        }
+    }
+    else
+    {
+        bIsotropic = TRUE;
+        scale = scale_tot[0][0];
+        for(i=1; i<DIM; i++)
+        {
+            /* With anisotropic scaling, the original spherical ns volumes become
+             * ellipsoids. To avoid costly transformations we use the minimum
+             * eigenvalue of the scaling matrix for determining the buffer size.
+             * Since the lower half is 0, the eigenvalues are the diagonal elements.
+             */
+            scale = min(scale,scale_tot[i][i]);
+            if (scale_tot[i][i] != scale_tot[i-1][i-1])
+            {
+                bIsotropic = FALSE;
+            }
+            for(j=0; j<i; j++)
+            {
+                if (scale_tot[i][j] != 0)
+                {
+                    bIsotropic = FALSE;
+                }
+            }
+        }
+        hbuf2 = sqr(0.5*(scale*ir->rlist - rint));
+        if (bIsotropic)
+        {
+            for(cg=cg0; cg<cg1; cg++)
+            {
+                svmul(scale,cg_cm[cg],cgsc);
+                a0 = cgs->index[cg];
+                a1 = cgs->index[cg+1];
+                for(a=a0; a<a1; a++)
+                {
+                    if (distance2(cgsc,x[a]) > hbuf2)
+                    {                    
+                        nBeyond++;
+                    }
+                }
+            }
+        }
+        else
+        {
+            /* Anistropic scaling */
+            for(cg=cg0; cg<cg1; cg++)
+            {
+                /* Since scale_tot contains the transpose of the scaling matrix,
+                 * we need to multiply with the transpose.
+                 */
+                tmvmul_ur0(scale_tot,cg_cm[cg],cgsc);
+                a0 = cgs->index[cg];
+                a1 = cgs->index[cg+1];
+                for(a=a0; a<a1; a++)
+                {
+                    if (distance2(cgsc,x[a]) > hbuf2)
+                    {
+                        nBeyond++;
+                    }
+                }
+            }
+        }
+    }
+    
+    return nBeyond;
+}
similarity index 100%
rename from src/mdlib/pme.c
rename to src/gromacs/mdlib/pme.c
similarity index 100%
rename from src/mdlib/pppm.c
rename to src/gromacs/mdlib/pppm.c
similarity index 100%
rename from src/mdlib/pull.c
rename to src/gromacs/mdlib/pull.c
diff --git a/src/gromacs/mdlib/pull_rotation.c b/src/gromacs/mdlib/pull_rotation.c
new file mode 100644 (file)
index 0000000..da4f40d
--- /dev/null
@@ -0,0 +1,3460 @@
+/*
+ * 
+ *                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
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "domdec.h"
+#include "gmx_wallcycle.h"
+#include "trnio.h"
+#include "smalloc.h"
+#include "network.h"
+#include "pbc.h"
+#include "futil.h"
+#include "mdrun.h"
+#include "txtdump.h"
+#include "names.h"
+#include "mtop_util.h"
+#include "names.h"
+#include "nrjac.h"
+#include "vec.h"
+#include "gmx_ga2la.h"
+#include "xvgr.h"
+#include "gmxfio.h"
+#include "mpelogging.h"
+#include "groupcoord.h"
+#include "pull_rotation.h"
+#include "gmx_sort.h"
+
+
+static char *RotStr = {"Enforced rotation:"};
+
+
+/* Set the minimum weight for the determination of the slab centers */
+#define WEIGHT_MIN (10*GMX_FLOAT_MIN)
+
+/* Helper structure for sorting positions along rotation vector             */
+typedef struct {
+    real xcproj;            /* Projection of xc on the rotation vector        */
+    int ind;                /* Index of xc                                    */
+    real m;                 /* Mass                                           */
+    rvec x;                 /* Position                                       */
+    rvec x_ref;             /* Reference position                             */
+} sort_along_vec_t;
+
+
+/* Enforced rotation / flexible: determine the angle of each slab             */
+typedef struct gmx_slabdata
+{
+    int  nat;               /* Number of atoms belonging to this slab         */
+    rvec *x;                /* The positions belonging to this slab. In 
+                               general, this should be all positions of the 
+                               whole rotation group, but we leave those away 
+                               that have a small enough weight                */
+    rvec *ref;              /* Same for reference                             */
+    real *weight;           /* The weight for each atom                       */
+} t_gmx_slabdata;
+
+
+/* Enforced rotation data for all groups                                      */
+typedef struct gmx_enfrot
+{
+    FILE  *out_rot;         /* Output file for rotation data                  */
+    FILE  *out_torque;      /* Output file for torque data                    */
+    FILE  *out_angles;      /* Output file for slab angles for flexible type  */
+    FILE  *out_slabs;       /* Output file for slab centers                   */
+    int   bufsize;          /* Allocation size of buf                         */
+    rvec  *xbuf;            /* Coordinate buffer variable for sorting         */
+    real  *mbuf;            /* Masses buffer variable for sorting             */
+    sort_along_vec_t *data; /* Buffer variable needed for position sorting    */
+    real  *mpi_inbuf;       /* MPI buffer                                     */
+    real  *mpi_outbuf;      /* MPI buffer                                     */
+    int   mpi_bufsize;      /* Allocation size of in & outbuf                 */
+    real  Vrot;             /* (Local) part of the enf. rotation potential    */
+    unsigned long Flags;    /* mdrun flags                                    */
+    gmx_bool bOut;          /* Used to skip first output when appending to 
+                             * avoid duplicate entries in rotation outfiles   */
+} t_gmx_enfrot;
+
+
+/* Global enforced rotation data for a single rotation group                  */
+typedef struct gmx_enfrotgrp
+{
+    real    degangle;       /* Rotation angle in degrees                      */
+    matrix  rotmat;         /* Rotation matrix                                */
+    atom_id *ind_loc;       /* Local rotation indices                         */
+    int     nat_loc;        /* Number of local group atoms                    */
+    int     nalloc_loc;     /* Allocation size for ind_loc and weight_loc     */
+
+    real  V;                /* Rotation potential for this rotation group     */
+    rvec  *f_rot_loc;       /* Array to store the forces on the local atoms
+                               resulting from enforced rotation potential     */
+
+    /* Collective coordinates for the whole rotation group */
+    real  *xc_ref_length;   /* Length of each x_rotref vector after x_rotref 
+                               has been put into origin                       */
+    int   *xc_ref_ind;      /* Position of each local atom in the collective
+                               array                                          */
+    rvec  xc_center;        /* Center of the rotation group positions, may
+                               be mass weighted                               */
+    rvec  xc_ref_center;    /* dito, for the reference positions              */
+    rvec  *xc;              /* Current (collective) positions                 */
+    ivec  *xc_shifts;       /* Current (collective) shifts                    */
+    ivec  *xc_eshifts;      /* Extra shifts since last DD step                */
+    rvec  *xc_old;          /* Old (collective) positions                     */
+    rvec  *xc_norm;         /* Normalized form of the current positions       */
+    rvec  *xc_ref_sorted;   /* Reference positions (sorted in the same order 
+                               as xc when sorted)                             */
+    int   *xc_sortind;      /* Where is a position found after sorting?       */
+    real  *mc;              /* Collective masses                              */
+    real  *mc_sorted;
+    real  invmass;          /* one over the total mass of the rotation group  */
+
+    real  torque_v;         /* Torque in the direction of rotation vector     */
+    real  angle_v;          /* Actual angle of the whole rotation group       */
+    /* Fixed rotation only */
+    real  weight_v;         /* Weights for angle determination                */
+    rvec  *xr_loc;          /* Local reference coords, correctly rotated      */
+    rvec  *x_loc_pbc;       /* Local current coords, correct PBC image        */
+    real  *m_loc;           /* Masses of the current local atoms              */
+
+    /* Flexible rotation only */
+    int   nslabs_alloc;     /* For this many slabs memory is allocated        */
+    int   slab_first;       /* Lowermost slab for that the calculation needs 
+                               to be performed at a given time step           */
+    int   slab_last;        /* Uppermost slab ...                             */
+    int   slab_first_ref;   /* First slab for which ref. center is stored     */
+    int   slab_last_ref;    /* Last ...                                       */
+    int   slab_buffer;      /* Slab buffer region around reference slabs      */
+    int   *firstatom;       /* First relevant atom for a slab                 */
+    int   *lastatom;        /* Last relevant atom for a slab                  */
+    rvec  *slab_center;     /* Gaussian-weighted slab center                  */
+    rvec  *slab_center_ref; /* Gaussian-weighted slab center for the
+                               reference positions                            */
+    real  *slab_weights;    /* Sum of gaussian weights in a slab              */
+    real  *slab_torque_v;   /* Torque T = r x f for each slab.                */
+                            /* torque_v = m.v = angular momentum in the 
+                               direction of v                                 */
+    real  max_beta;         /* min_gaussian from inputrec->rotgrp is the
+                               minimum value the gaussian must have so that 
+                               the force is actually evaluated max_beta is 
+                               just another way to put it                     */
+    real  *gn_atom;         /* Precalculated gaussians for a single atom      */
+    int   *gn_slabind;      /* Tells to which slab each precalculated gaussian 
+                               belongs                                        */
+    rvec  *slab_innersumvec;/* Inner sum of the flexible2 potential per slab;
+                               this is precalculated for optimization reasons */
+    t_gmx_slabdata *slab_data; /* Holds atom positions and gaussian weights 
+                               of atoms belonging to a slab                   */
+} t_gmx_enfrotgrp;
+
+
+/* Activate output of forces for correctness checks */
+/* #define PRINT_FORCES */
+#ifdef PRINT_FORCES
+#define PRINT_FORCE_J  fprintf(stderr,"f%d = %15.8f %15.8f %15.8f\n",erg->xc_ref_ind[j],erg->f_rot_loc[j][XX], erg->f_rot_loc[j][YY], erg->f_rot_loc[j][ZZ]);
+#define PRINT_POT_TAU  if (MASTER(cr)) { \
+                           fprintf(stderr,"potential = %15.8f\n" "torque    = %15.8f\n", erg->V, erg->torque_v); \
+                       }
+#else
+#define PRINT_FORCE_J
+#define PRINT_POT_TAU
+#endif
+
+/* Shortcuts for often used queries */
+#define ISFLEX(rg) ( (rg->eType==erotgFLEX) || (rg->eType==erotgFLEXT) || (rg->eType==erotgFLEX2) || (rg->eType==erotgFLEX2T) )
+#define ISCOLL(rg) ( (rg->eType==erotgFLEX) || (rg->eType==erotgFLEXT) || (rg->eType==erotgFLEX2) || (rg->eType==erotgFLEX2T) || (rg->eType==erotgRMPF) || (rg->eType==erotgRM2PF) )
+
+
+/* Does any of the rotation groups use slab decomposition? */
+static gmx_bool HaveFlexibleGroups(t_rot *rot)
+{
+    int g;
+    t_rotgrp *rotg;
+    gmx_bool bHaveFlexGroups=FALSE;
+
+
+    for (g=0; g<rot->ngrp; g++)
+    {
+        rotg = &rot->grp[g];
+        if (ISFLEX(rotg))
+            bHaveFlexGroups = TRUE;
+    }
+
+    return bHaveFlexGroups;
+}
+
+
+static double** allocate_square_matrix(int dim)
+{
+    int i;
+    double** mat = NULL; 
+    
+    
+    snew(mat, dim);
+    for(i=0; i<dim; i++)
+        snew(mat[i], dim);
+
+    return mat;
+}
+
+
+static void free_square_matrix(double** mat, int dim)
+{
+    int i;
+    
+    
+    for (i=0; i<dim; i++)
+        sfree(mat[i]);
+    sfree(mat);
+}
+
+
+/* Output rotation energy, torques, etc. for each rotation group */
+static void reduce_output(t_commrec *cr, t_rot *rot, real t, gmx_large_int_t step)
+{
+    int      g,i,islab,nslabs=0;
+    int      count;      /* MPI element counter                               */
+    t_rotgrp *rotg;
+    gmx_enfrot_t er;     /* Pointer to the enforced rotation buffer variables */
+    gmx_enfrotgrp_t erg; /* Pointer to enforced rotation group data           */
+    gmx_bool bFlex;
+
+    
+    er=rot->enfrot;
+    
+    /* Fill the MPI buffer with stuff to reduce: */
+    if (PAR(cr))
+    {
+        count=0;
+        for (g=0; g < rot->ngrp; g++)
+        {
+            rotg = &rot->grp[g];
+            erg = rotg->enfrotgrp;
+            nslabs = erg->slab_last - erg->slab_first + 1;
+            er->mpi_inbuf[count++] = erg->V;
+            er->mpi_inbuf[count++] = erg->torque_v;
+            er->mpi_inbuf[count++] = erg->angle_v;
+            er->mpi_inbuf[count++] = erg->weight_v; /* weights are not needed for flex types, but this is just a single value */
+            if (ISFLEX(rotg))
+            {
+                /* (Re-)allocate memory for MPI buffer: */
+                if (er->mpi_bufsize < count+nslabs)
+                {
+                    er->mpi_bufsize = count+nslabs;
+                    srenew(er->mpi_inbuf , er->mpi_bufsize);
+                    srenew(er->mpi_outbuf, er->mpi_bufsize);
+                }
+                for (i=0; i<nslabs; i++)
+                    er->mpi_inbuf[count++] = erg->slab_torque_v[i];
+            }
+        }
+#ifdef GMX_MPI
+        MPI_Reduce(er->mpi_inbuf, er->mpi_outbuf, count, GMX_MPI_REAL, MPI_SUM, MASTERRANK(cr), cr->mpi_comm_mygroup);
+#endif
+        /* Copy back the reduced data from the buffer on the master */
+        if (MASTER(cr))
+        {
+            count=0;
+            for (g=0; g < rot->ngrp; g++)
+            {
+                rotg = &rot->grp[g];
+                erg = rotg->enfrotgrp;
+                nslabs = erg->slab_last - erg->slab_first + 1;
+                erg->V        = er->mpi_outbuf[count++];
+                erg->torque_v = er->mpi_outbuf[count++];
+                erg->angle_v  = er->mpi_outbuf[count++];
+                erg->weight_v = er->mpi_outbuf[count++];
+                if (ISFLEX(rotg))
+                {
+                    for (i=0; i<nslabs; i++)
+                        erg->slab_torque_v[i] = er->mpi_outbuf[count++];
+                }
+            }
+        }
+    }
+    
+    /* Output */
+    if (MASTER(cr))
+    {
+        /* Angle and torque for each rotation group */
+        for (g=0; g < rot->ngrp; g++)
+        {
+            rotg=&rot->grp[g];
+            bFlex = ISFLEX(rotg);
+
+            erg=rotg->enfrotgrp;
+            
+            /* Output to main rotation output file: */
+            if ( do_per_step(step, rot->nstrout) )
+            {
+                if (bFlex)
+                    fprintf(er->out_rot, "%12.4f", erg->angle_v); /* RMSD fit angle */
+                else
+                    fprintf(er->out_rot, "%12.4f", (erg->angle_v/erg->weight_v)*180.0*M_1_PI);
+                fprintf(er->out_rot, "%12.3e", erg->torque_v);
+                fprintf(er->out_rot, "%12.3e", erg->V);
+            }
+
+            /* Output to torque log file: */
+            if ( bFlex && do_per_step(step, rot->nstsout) )
+            {
+                fprintf(er->out_torque, "%12.3e%6d", t, g);
+                for (i=erg->slab_first; i<=erg->slab_last; i++)
+                {
+                    islab = i - erg->slab_first;  /* slab index */
+                    /* Only output if enough weight is in slab */
+                    if (erg->slab_weights[islab] > rotg->min_gaussian)
+                        fprintf(er->out_torque, "%6d%12.3e", i, erg->slab_torque_v[islab]);
+                }
+                fprintf(er->out_torque , "\n");
+            }
+        }
+        if ( do_per_step(step, rot->nstrout) )
+            fprintf(er->out_rot, "\n");
+    }
+}
+
+
+/* Add the forces from enforced rotation potential to the local forces.
+ * Should be called after the SR forces have been evaluated */
+extern real add_rot_forces(t_rot *rot, rvec f[], t_commrec *cr, gmx_large_int_t step, real t)
+{
+    int g,l,ii;
+    t_rotgrp *rotg;
+    gmx_enfrot_t er;     /* Pointer to the enforced rotation buffer variables */
+    gmx_enfrotgrp_t erg; /* Pointer to enforced rotation group data           */
+
+    
+    er=rot->enfrot;
+    
+    GMX_MPE_LOG(ev_add_rot_forces_start);
+    
+    /* Reduce energy,torque, angles etc. to get the sum values (per rotation group) 
+     * on the master and output these values to file. */
+    if ( (do_per_step(step, rot->nstrout) || do_per_step(step, rot->nstsout)) && er->bOut)
+        reduce_output(cr, rot, t, step);
+
+    /* When appending, er->bOut is FALSE the first time to avoid duplicate entries */
+    er->bOut = TRUE;
+
+    /* Total rotation potential is the sum over all rotation groups */
+    er->Vrot = 0.0; 
+        
+    /* Loop over enforced rotation groups (usually 1, though)
+     * Apply the forces from rotation potentials */
+    for (g=0; g<rot->ngrp; g++)
+    {
+        rotg = &rot->grp[g];
+        erg=rotg->enfrotgrp;
+        er->Vrot += erg->V;
+        for (l=0; l<erg->nat_loc; l++)
+        {
+            /* Get the right index of the local force */
+            ii = erg->ind_loc[l];
+            /* Add */
+            rvec_inc(f[ii],erg->f_rot_loc[l]);
+        }
+    }
+    
+    PRINT_POT_TAU
+
+    GMX_MPE_LOG(ev_add_rot_forces_finish);
+
+    return (MASTER(cr)? er->Vrot : 0.0);
+}
+
+
+/* The Gaussian norm is chosen such that the sum of the gaussian functions
+ * over the slabs is approximately 1.0 everywhere */
+#define GAUSS_NORM   0.569917543430618
+
+
+/* Calculate the maximum beta that leads to a gaussian larger min_gaussian,
+ * also does some checks
+ */
+static double calc_beta_max(real min_gaussian, real slab_dist)
+{
+    double sigma;
+    double arg;
+    
+    
+    /* Actually the next two checks are already made in grompp */
+    if (slab_dist <= 0)
+        gmx_fatal(FARGS, "Slab distance of flexible rotation groups must be >=0 !");
+    if (min_gaussian <= 0)
+        gmx_fatal(FARGS, "Cutoff value for Gaussian must be > 0. (You requested %f)");
+
+    /* Define the sigma value */
+    sigma = 0.7*slab_dist;
+
+    /* Calculate the argument for the logarithm and check that the log() result is negative or 0 */
+    arg = min_gaussian/GAUSS_NORM;
+    if (arg > 1.0)
+        gmx_fatal(FARGS, "min_gaussian of flexible rotation groups must be <%g", GAUSS_NORM);
+    
+    return sqrt(-2.0*sigma*sigma*log(min_gaussian/GAUSS_NORM));
+}
+
+
+static inline real calc_beta(rvec curr_x, t_rotgrp *rotg, int n)
+{
+    return iprod(curr_x, rotg->vec) - rotg->slab_dist * n;
+}
+
+
+static inline real gaussian_weight(rvec curr_x, t_rotgrp *rotg, int n)
+{
+    const real norm = GAUSS_NORM;
+    real       sigma;
+
+    
+    /* Define the sigma value */
+    sigma = 0.7*rotg->slab_dist;
+    /* Calculate the Gaussian value of slab n for position curr_x */
+    return norm * exp( -0.5 * sqr( calc_beta(curr_x, rotg, n)/sigma ) );
+}
+
+
+/* Returns the weight in a single slab, also calculates the Gaussian- and mass-
+ * weighted sum of positions for that slab */
+static real get_slab_weight(int j, t_rotgrp *rotg, rvec xc[], real mc[], rvec *x_weighted_sum)
+{
+    rvec curr_x;              /* The position of an atom                      */
+    rvec curr_x_weighted;     /* The gaussian-weighted position               */
+    real gaussian;            /* A single gaussian weight                     */
+    real wgauss;              /* gaussian times current mass                  */
+    real slabweight = 0.0;    /* The sum of weights in the slab               */
+    int i,islab;
+    gmx_enfrotgrp_t erg;      /* Pointer to enforced rotation group data      */
+
+    
+    erg=rotg->enfrotgrp;
+    clear_rvec(*x_weighted_sum);
+    
+    /* Slab index */
+    islab = j - erg->slab_first;
+    
+    /* Loop over all atoms in the rotation group */
+     for (i=0; i<rotg->nat; i++)
+     {
+         copy_rvec(xc[i], curr_x);
+         gaussian = gaussian_weight(curr_x, rotg, j);
+         wgauss = gaussian * mc[i];
+         svmul(wgauss, curr_x, curr_x_weighted);
+         rvec_add(*x_weighted_sum, curr_x_weighted, *x_weighted_sum);
+         slabweight += wgauss;
+     } /* END of loop over rotation group atoms */
+
+     return slabweight;
+}
+
+
+static void get_slab_centers(
+        t_rotgrp *rotg,       /* The rotation group information               */
+        rvec      *xc,        /* The rotation group positions; will 
+                                 typically be enfrotgrp->xc, but at first call 
+                                 it is enfrotgrp->xc_ref                      */
+        real      *mc,        /* The masses of the rotation group atoms       */
+        t_commrec *cr,        /* Communication record                         */
+        int       g,          /* The number of the rotation group             */
+        real      time,       /* Used for output only                         */
+        FILE      *out_slabs, /* For outputting center per slab information   */
+        gmx_bool  bOutStep,   /* Is this an output step?                      */
+        gmx_bool  bReference) /* If this routine is called from
+                                 init_rot_group we need to store
+                                 the reference slab centers                   */
+{
+    int j,islab;
+    gmx_enfrotgrp_t erg;      /* Pointer to enforced rotation group data */
+    
+    
+    erg=rotg->enfrotgrp;
+
+    /* Loop over slabs */
+    for (j = erg->slab_first; j <= erg->slab_last; j++)
+    {
+        islab = j - erg->slab_first;
+        erg->slab_weights[islab] = get_slab_weight(j, rotg, xc, mc, &erg->slab_center[islab]);
+        
+        /* We can do the calculations ONLY if there is weight in the slab! */
+        if (erg->slab_weights[islab] > WEIGHT_MIN)
+        {
+            svmul(1.0/erg->slab_weights[islab], erg->slab_center[islab], erg->slab_center[islab]);
+        }
+        else
+        {
+            /* We need to check this here, since we divide through slab_weights
+             * in the flexible low-level routines! */
+            gmx_fatal(FARGS, "Not enough weight in slab %d. Slab center cannot be determined!", j);
+        }
+        
+        /* At first time step: save the centers of the reference structure */
+        if (bReference)
+            copy_rvec(erg->slab_center[islab], erg->slab_center_ref[islab]);
+    } /* END of loop over slabs */
+    
+    /* Output on the master */
+    if (MASTER(cr) && bOutStep)
+    {
+        fprintf(out_slabs, "%12.3e%6d", time, g);
+        for (j = erg->slab_first; j <= erg->slab_last; j++)
+        {
+            islab = j - erg->slab_first;
+            fprintf(out_slabs, "%6d%12.3e%12.3e%12.3e",
+                    j,erg->slab_center[islab][XX],erg->slab_center[islab][YY],erg->slab_center[islab][ZZ]);
+        }
+        fprintf(out_slabs, "\n");
+    }
+}
+
+
+static void calc_rotmat(
+        rvec vec,
+        real degangle,  /* Angle alpha of rotation at time t in degrees       */
+        matrix rotmat)  /* Rotation matrix                                    */
+{
+    real radangle;            /* Rotation angle in radians */
+    real cosa;                /* cosine alpha              */
+    real sina;                /* sine alpha                */
+    real OMcosa;              /* 1 - cos(alpha)            */
+    real dumxy, dumxz, dumyz; /* save computations         */
+    rvec rot_vec;             /* Rotate around rot_vec ... */
+
+
+    radangle = degangle * M_PI/180.0;
+    copy_rvec(vec , rot_vec );
+
+    /* Precompute some variables: */
+    cosa   = cos(radangle);
+    sina   = sin(radangle);
+    OMcosa = 1.0 - cosa;
+    dumxy  = rot_vec[XX]*rot_vec[YY]*OMcosa;
+    dumxz  = rot_vec[XX]*rot_vec[ZZ]*OMcosa;
+    dumyz  = rot_vec[YY]*rot_vec[ZZ]*OMcosa;
+
+    /* Construct the rotation matrix for this rotation group: */
+    /* 1st column: */
+    rotmat[XX][XX] = cosa  + rot_vec[XX]*rot_vec[XX]*OMcosa;
+    rotmat[YY][XX] = dumxy + rot_vec[ZZ]*sina;
+    rotmat[ZZ][XX] = dumxz - rot_vec[YY]*sina;
+    /* 2nd column: */
+    rotmat[XX][YY] = dumxy - rot_vec[ZZ]*sina;
+    rotmat[YY][YY] = cosa  + rot_vec[YY]*rot_vec[YY]*OMcosa;
+    rotmat[ZZ][YY] = dumyz + rot_vec[XX]*sina;
+    /* 3rd column: */
+    rotmat[XX][ZZ] = dumxz + rot_vec[YY]*sina;
+    rotmat[YY][ZZ] = dumyz - rot_vec[XX]*sina;
+    rotmat[ZZ][ZZ] = cosa  + rot_vec[ZZ]*rot_vec[ZZ]*OMcosa;
+
+#ifdef PRINTMATRIX
+    int iii,jjj;
+
+    for (iii=0; iii<3; iii++) {
+        for (jjj=0; jjj<3; jjj++)
+            fprintf(stderr, " %10.8f ",  rotmat[iii][jjj]);
+        fprintf(stderr, "\n");
+    }
+#endif
+}
+
+
+/* Calculates torque on the rotation axis tau = position x force */
+static inline real torque(
+        rvec rotvec,  /* rotation vector; MUST be normalized!                 */
+        rvec force,   /* force                                                */
+        rvec x,       /* position of atom on which the force acts             */
+        rvec pivot)   /* pivot point of rotation axis                         */
+{
+    rvec vectmp, tau;
+
+    
+    /* Subtract offset */
+    rvec_sub(x,pivot,vectmp);
+    
+    /* position x force */
+    cprod(vectmp, force, tau);
+    
+    /* Return the part of the torque which is parallel to the rotation vector */
+    return iprod(tau, rotvec);
+}
+
+
+/* Right-aligned output of value with standard width */
+static void print_aligned(FILE *fp, char *str)
+{
+    fprintf(fp, "%12s", str);
+}
+
+
+/* Right-aligned output of value with standard short width */
+static void print_aligned_short(FILE *fp, char *str)
+{
+    fprintf(fp, "%6s", str);
+}
+
+
+static FILE *open_output_file(const char *fn, int steps, const char what[])
+{
+    FILE *fp;
+    
+    
+    fp = ffopen(fn, "w");
+
+    fprintf(fp, "# Output of %s is written in intervals of %d time step%s.\n#\n",
+            what,steps, steps>1 ? "s":"");
+    
+    return fp;
+}
+
+
+/* Open output file for slab center data. Call on master only */
+static FILE *open_slab_out(const char *fn, t_rot *rot, const output_env_t oenv)
+{
+    FILE      *fp;
+    int       g,i;
+    t_rotgrp  *rotg;
+
+
+    if (rot->enfrot->Flags & MD_APPENDFILES)
+    {
+        fp = gmx_fio_fopen(fn,"a");
+    }
+    else
+    {
+        fp = open_output_file(fn, rot->nstsout, "gaussian weighted slab centers");
+
+        for (g=0; g<rot->ngrp; g++)
+        {
+            rotg = &rot->grp[g];
+            if (ISFLEX(rotg))
+            {
+                fprintf(fp, "# Rotation group %d (%s), slab distance %f nm, %s.\n",
+                        g, erotg_names[rotg->eType], rotg->slab_dist,
+                        rotg->bMassW? "centers of mass":"geometrical centers");
+            }
+        }
+
+        fprintf(fp, "# Reference centers are listed first (t=-1).\n");
+        fprintf(fp, "# The following columns have the syntax:\n");
+        fprintf(fp, "#     ");
+        print_aligned_short(fp, "t");
+        print_aligned_short(fp, "grp");
+        /* Print legend for the first two entries only ... */
+        for (i=0; i<2; i++)
+        {
+            print_aligned_short(fp, "slab");
+            print_aligned(fp, "X center");
+            print_aligned(fp, "Y center");
+            print_aligned(fp, "Z center");
+        }
+        fprintf(fp, " ...\n");
+        fflush(fp);
+    }
+
+    return fp;
+}
+
+
+/* Open output file and print some general information about the rotation groups.
+ * Call on master only */
+static FILE *open_rot_out(const char *fn, t_rot *rot, const output_env_t oenv)
+{
+    FILE       *fp;
+    int        g,nsets;
+    t_rotgrp   *rotg;
+    const char **setname;
+    char       buf[50], buf2[75];
+    gmx_enfrotgrp_t erg;       /* Pointer to enforced rotation group data */
+    gmx_bool   bFlex;
+
+
+    if (rot->enfrot->Flags & MD_APPENDFILES)
+    {
+        fp = gmx_fio_fopen(fn,"a");
+    }
+    else
+    {
+        fp = xvgropen(fn, "Rotation angles and energy", "Time [ps]", "angles [degrees] and energies [kJ/mol]", oenv);
+        fprintf(fp, "# Output of enforced rotation data is written in intervals of %d time step%s.\n#\n", rot->nstrout, rot->nstrout > 1 ? "s":"");
+        fprintf(fp, "# The scalar tau is the torque [kJ/mol] in the direction of the rotation vector v.\n");
+        fprintf(fp, "# To obtain the vectorial torque, multiply tau with the group's rot_vec.\n");
+        fprintf(fp, "# For flexible groups, tau(t,n) from all slabs n have been summed in a single value tau(t) here.\n");
+        fprintf(fp, "# The torques tau(t,n) are found in the rottorque.log (-rt) output file\n");
+        fprintf(fp, "#\n");
+        
+        for (g=0; g<rot->ngrp; g++)
+        {
+            rotg = &rot->grp[g];
+            erg=rotg->enfrotgrp;
+            bFlex = ISFLEX(rotg);
+
+            fprintf(fp, "# Rotation group %d, potential type '%s':\n"      , g, erotg_names[rotg->eType]);
+            fprintf(fp, "# rot_massw%d          %s\n"                      , g, yesno_names[rotg->bMassW]);
+            fprintf(fp, "# rot_vec%d            %12.5e %12.5e %12.5e\n"    , g, rotg->vec[XX], rotg->vec[YY], rotg->vec[ZZ]);
+            fprintf(fp, "# rot_rate%d           %12.5e degrees/ps\n"       , g, rotg->rate);
+            fprintf(fp, "# rot_k%d              %12.5e kJ/(mol*nm^2)\n"    , g, rotg->k);
+            if ( rotg->eType==erotgISO || rotg->eType==erotgPM || rotg->eType==erotgRM || rotg->eType==erotgRM2)
+                fprintf(fp, "# rot_pivot%d          %12.5e %12.5e %12.5e  nm\n", g, rotg->pivot[XX], rotg->pivot[YY], rotg->pivot[ZZ]);
+
+            if (bFlex)
+            {
+                fprintf(fp, "# rot_slab_distance%d   %f nm\n", g, rotg->slab_dist);
+                fprintf(fp, "# rot_min_gaussian%d   %12.5e\n", g, rotg->min_gaussian);
+            }
+
+            /* Output the centers of the rotation groups for the pivot-free potentials */
+            if ((rotg->eType==erotgISOPF) || (rotg->eType==erotgPMPF) || (rotg->eType==erotgRMPF) || (rotg->eType==erotgRM2PF
+                || (rotg->eType==erotgFLEXT) || (rotg->eType==erotgFLEX2T)) )
+            {
+                fprintf(fp, "# ref. grp. %d center  %12.5e %12.5e %12.5e\n", g,
+                            erg->xc_ref_center[XX], erg->xc_ref_center[YY], erg->xc_ref_center[ZZ]);
+
+                fprintf(fp, "# grp. %d init.center  %12.5e %12.5e %12.5e\n", g,
+                            erg->xc_center[XX], erg->xc_center[YY], erg->xc_center[ZZ]);
+            }
+
+            if ( (rotg->eType == erotgRM2) || (rotg->eType==erotgFLEX2) || (rotg->eType==erotgFLEX2T) )
+            {
+                fprintf(fp, "# rot_eps%d            %12.5e nm^2\n", g, rotg->eps);
+            }
+        }
+        
+        fprintf(fp, "#\n# Legend for the following data columns:\n");
+        fprintf(fp, "#     ");
+        print_aligned_short(fp, "t");
+        nsets = 0;
+        snew(setname, 4*rot->ngrp);
+        
+        for (g=0; g<rot->ngrp; g++)
+        {
+            rotg = &rot->grp[g];
+            sprintf(buf, "theta_ref%d", g);
+            print_aligned(fp, buf);
+            sprintf(buf2, "%s [degrees]", buf);
+            setname[nsets] = strdup(buf2);
+            nsets++;
+        }
+        for (g=0; g<rot->ngrp; g++)
+        {
+            rotg = &rot->grp[g];
+            bFlex = ISFLEX(rotg);
+
+            /* For flexible axis rotation we use RMSD fitting to determine the
+             * actual angle of the rotation group */
+            if (bFlex)
+                sprintf(buf, "theta-fit%d", g);
+            else
+                sprintf(buf, "theta-av%d", g);
+            print_aligned(fp, buf);
+            sprintf(buf2, "%s [degrees]", buf);
+            setname[nsets] = strdup(buf2);
+            nsets++;
+
+            sprintf(buf, "tau%d", g);
+            print_aligned(fp, buf);
+            sprintf(buf2, "%s [kJ/mol]", buf);
+            setname[nsets] = strdup(buf2);
+            nsets++;
+
+            sprintf(buf, "energy%d", g);
+            print_aligned(fp, buf);
+            sprintf(buf2, "%s [kJ/mol]", buf);
+            setname[nsets] = strdup(buf2);
+            nsets++;
+        }
+        fprintf(fp, "\n#\n");
+        
+        if (nsets > 1)
+            xvgr_legend(fp, nsets, setname, oenv);
+        sfree(setname);
+        
+        fflush(fp);
+    }
+    
+    return fp;
+}
+
+
+/* Call on master only */
+static FILE *open_angles_out(const char *fn, t_rot *rot, const output_env_t oenv)
+{
+    int      g;
+    FILE     *fp;
+    t_rotgrp *rotg;
+
+
+    if (rot->enfrot->Flags & MD_APPENDFILES)
+    {
+        fp = gmx_fio_fopen(fn,"a");
+    }
+    else
+    {
+        /* Open output file and write some information about it's structure: */
+        fp = open_output_file(fn, rot->nstsout, "rotation group angles");
+        fprintf(fp, "# All angles given in degrees, time in ps.\n");
+        for (g=0; g<rot->ngrp; g++)
+        {
+            rotg = &rot->grp[g];
+            if (ISFLEX(rotg))
+            {
+                fprintf(fp, "# Rotation group %d (%s), slab distance %f nm, fit type %s.\n",
+                        g, erotg_names[rotg->eType], rotg->slab_dist, erotg_fitnames[rotg->eFittype]);
+            }
+        }
+        fprintf(fp, "# Legend for the following data columns:\n");
+        fprintf(fp, "#     ");
+        print_aligned_short(fp, "t");
+        print_aligned_short(fp, "grp");
+        print_aligned(fp, "theta_ref");
+        print_aligned_short(fp, "slab");
+        print_aligned_short(fp, "atoms");
+        print_aligned(fp, "theta_fit");
+        print_aligned_short(fp, "slab");
+        print_aligned_short(fp, "atoms");
+        print_aligned(fp, "theta_fit");
+        fprintf(fp, " ...\n");
+        fflush(fp);
+    }
+
+    return fp;
+}
+
+
+/* Open torque output file and write some information about it's structure.
+ * Call on master only */
+static FILE *open_torque_out(const char *fn, t_rot *rot, const output_env_t oenv)
+{
+    FILE      *fp;
+    int       g;
+    t_rotgrp  *rotg;
+
+
+    if (rot->enfrot->Flags & MD_APPENDFILES)
+    {
+        fp = gmx_fio_fopen(fn,"a");
+    }
+    else
+    {
+        fp = open_output_file(fn, rot->nstsout,"torques");
+
+        for (g=0; g<rot->ngrp; g++)
+        {
+            rotg = &rot->grp[g];
+            if (ISFLEX(rotg))
+            {
+                fprintf(fp, "# Rotation group %d (%s), slab distance %f nm.\n", g, erotg_names[rotg->eType], rotg->slab_dist);
+                fprintf(fp, "# The scalar tau is the torque [kJ/mol] in the direction of the rotation vector.\n");
+                fprintf(fp, "# To obtain the vectorial torque, multiply tau with\n");
+                fprintf(fp, "# rot_vec%d            %10.3e %10.3e %10.3e\n", g, rotg->vec[XX], rotg->vec[YY], rotg->vec[ZZ]);
+                fprintf(fp, "#\n");
+            }
+        }
+        fprintf(fp, "# Legend for the following data columns: (tau=torque for that slab):\n");
+        fprintf(fp, "#     ");
+        print_aligned_short(fp, "t");
+        print_aligned_short(fp, "grp");
+        print_aligned_short(fp, "slab");
+        print_aligned(fp, "tau");
+        print_aligned_short(fp, "slab");
+        print_aligned(fp, "tau");
+        fprintf(fp, " ...\n");
+        fflush(fp);
+    }
+
+    return fp;
+}
+
+
+static void swap_val(double* vec, int i, int j)
+{
+    double tmp = vec[j];
+    
+    
+    vec[j]=vec[i];
+    vec[i]=tmp;
+}
+
+
+static void swap_col(double **mat, int i, int j)
+{
+    double tmp[3] = {mat[0][j], mat[1][j], mat[2][j]};
+    
+    
+    mat[0][j]=mat[0][i];
+    mat[1][j]=mat[1][i];
+    mat[2][j]=mat[2][i];
+    
+    mat[0][i]=tmp[0];
+    mat[1][i]=tmp[1];
+    mat[2][i]=tmp[2];
+} 
+
+
+/* Eigenvectors are stored in columns of eigen_vec */
+static void diagonalize_symmetric(
+        double **matrix,
+        double **eigen_vec,
+        double eigenval[3])
+{
+    int n_rot;
+    
+    
+    jacobi(matrix,3,eigenval,eigen_vec,&n_rot);
+    
+    /* sort in ascending order */
+    if (eigenval[0] > eigenval[1])
+    {
+        swap_val(eigenval, 0, 1);
+        swap_col(eigen_vec, 0, 1);
+    } 
+    if (eigenval[1] > eigenval[2])
+    {
+        swap_val(eigenval, 1, 2);
+        swap_col(eigen_vec, 1, 2);
+    }
+    if (eigenval[0] > eigenval[1])
+    {
+        swap_val(eigenval, 0, 1);
+        swap_col(eigen_vec, 0, 1);
+    }
+}
+
+
+static void align_with_z(
+        rvec* s,           /* Structure to align */
+        int natoms,
+        rvec axis)
+{
+    int    i, j, k;
+    rvec   zet = {0.0, 0.0, 1.0};
+    rvec   rot_axis={0.0, 0.0, 0.0};
+    rvec   *rotated_str=NULL;
+    real   ooanorm;
+    real   angle;
+    matrix rotmat;
+    
+    
+    snew(rotated_str, natoms);
+
+    /* Normalize the axis */
+    ooanorm = 1.0/norm(axis);
+    svmul(ooanorm, axis, axis);
+    
+    /* Calculate the angle for the fitting procedure */
+    cprod(axis, zet, rot_axis);
+    angle = acos(axis[2]);
+    if (angle < 0.0)
+        angle += M_PI;
+    
+    /* Calculate the rotation matrix */
+    calc_rotmat(rot_axis, angle*180.0/M_PI, rotmat);
+    
+    /* Apply the rotation matrix to s */
+    for (i=0; i<natoms; i++)
+    {    
+        for(j=0; j<3; j++)
+        {
+            for(k=0; k<3; k++)
+            {
+                rotated_str[i][j] += rotmat[j][k]*s[i][k];
+            }
+        }
+    }
+    
+    /* Rewrite the rotated structure to s */
+    for(i=0; i<natoms; i++)
+    {
+        for(j=0; j<3; j++)
+        {
+            s[i][j]=rotated_str[i][j];
+        }
+    }
+    
+    sfree(rotated_str);
+} 
+
+
+static void calc_correl_matrix(rvec* Xstr, rvec* Ystr, double** Rmat, int natoms)
+{    
+    int i, j, k;
+    
+    for (i=0; i<3; i++)
+        for (j=0; j<3; j++)
+            Rmat[i][j] = 0.0;
+    
+    for (i=0; i<3; i++) 
+        for (j=0; j<3; j++) 
+            for (k=0; k<natoms; k++) 
+                Rmat[i][j] += Ystr[k][i] * Xstr[k][j];
+}
+
+
+static void weigh_coords(rvec* str, real* weight, int natoms)
+{
+    int i, j;
+    
+    
+    for(i=0; i<natoms; i++)
+    {
+        for(j=0; j<3; j++)
+            str[i][j] *= sqrt(weight[i]);
+    }  
+}
+
+
+static real opt_angle_analytic(
+        rvec* ref_s,
+        rvec* act_s,
+        real* weight, 
+        int natoms,
+        rvec ref_com,
+        rvec act_com,
+        rvec axis)
+{    
+    int    i, j, k;
+    rvec   *ref_s_1=NULL;
+    rvec   *act_s_1=NULL;
+    rvec   shift;
+    double **Rmat, **RtR, **eigvec;
+    double eigval[3];
+    double V[3][3], WS[3][3];
+    double rot_matrix[3][3];
+    double opt_angle;
+    
+    
+    /* Do not change the original coordinates */ 
+    snew(ref_s_1, natoms);
+    snew(act_s_1, natoms);
+    for(i=0; i<natoms; i++)
+    {
+        copy_rvec(ref_s[i], ref_s_1[i]);
+        copy_rvec(act_s[i], act_s_1[i]);
+    }
+    
+    /* Translate the structures to the origin */
+    shift[XX] = -ref_com[XX];
+    shift[YY] = -ref_com[YY];
+    shift[ZZ] = -ref_com[ZZ];
+    translate_x(ref_s_1, natoms, shift);
+    
+    shift[XX] = -act_com[XX];
+    shift[YY] = -act_com[YY];
+    shift[ZZ] = -act_com[ZZ];
+    translate_x(act_s_1, natoms, shift);
+    
+    /* Align rotation axis with z */
+    align_with_z(ref_s_1, natoms, axis);
+    align_with_z(act_s_1, natoms, axis);
+    
+    /* Correlation matrix */
+    Rmat = allocate_square_matrix(3);
+    
+    for (i=0; i<natoms; i++)
+    {
+        ref_s_1[i][2]=0.0;
+        act_s_1[i][2]=0.0;
+    }
+    
+    /* Weight positions with sqrt(weight) */
+    if (NULL != weight)
+    {
+        weigh_coords(ref_s_1, weight, natoms);
+        weigh_coords(act_s_1, weight, natoms);
+    }
+    
+    /* Calculate correlation matrices R=YXt (X=ref_s; Y=act_s) */
+    calc_correl_matrix(ref_s_1, act_s_1, Rmat, natoms);
+    
+    /* Calculate RtR */
+    RtR = allocate_square_matrix(3);
+    for (i=0; i<3; i++)
+    {
+        for (j=0; j<3; j++)
+        {
+            for (k=0; k<3; k++)
+            {
+                RtR[i][j] += Rmat[k][i] * Rmat[k][j];
+            }
+        }
+    }
+    /* Diagonalize RtR */
+    snew(eigvec,3);
+    for (i=0; i<3; i++)
+        snew(eigvec[i],3);
+    
+    diagonalize_symmetric(RtR, eigvec, eigval);
+    swap_col(eigvec,0,1);
+    swap_col(eigvec,1,2);
+    swap_val(eigval,0,1);
+    swap_val(eigval,1,2);
+    
+    /* Calculate V */
+    for(i=0; i<3; i++)
+    {
+        for(j=0; j<3; j++)
+        {
+            V[i][j]  = 0.0;
+            WS[i][j] = 0.0;
+        }
+    }
+    
+    for (i=0; i<2; i++)
+        for (j=0; j<2; j++)
+            WS[i][j] = eigvec[i][j] / sqrt(eigval[j]);
+    
+    for (i=0; i<3; i++)
+    {
+        for (j=0; j<3; j++)
+        {
+            for (k=0; k<3; k++)
+            {
+                V[i][j] += Rmat[i][k]*WS[k][j];
+            }
+        }
+    }
+    free_square_matrix(Rmat, 3);
+    
+    /* Calculate optimal rotation matrix */
+    for (i=0; i<3; i++)
+        for (j=0; j<3; j++)
+            rot_matrix[i][j] = 0.0;
+    
+    for (i=0; i<3; i++)
+    {
+        for(j=0; j<3; j++)
+        {
+            for(k=0; k<3; k++){
+                rot_matrix[i][j] += eigvec[i][k]*V[j][k];
+            }
+        }
+    }
+    rot_matrix[2][2] = 1.0;
+        
+    /* In some cases abs(rot_matrix[0][0]) can be slighly larger
+     * than unity due to numerical inacurracies. To be able to calculate
+     * the acos function, we put these values back in range. */
+    if (rot_matrix[0][0] > 1.0)
+    {
+        rot_matrix[0][0] = 1.0;
+    }
+    else if (rot_matrix[0][0] < -1.0)
+    {
+        rot_matrix[0][0] = -1.0;
+    }
+
+    /* Determine the optimal rotation angle: */
+    opt_angle = (-1.0)*acos(rot_matrix[0][0])*180.0/M_PI;
+    if (rot_matrix[0][1] < 0.0)
+        opt_angle = (-1.0)*opt_angle;
+        
+    /* Give back some memory */
+    free_square_matrix(RtR, 3);
+    sfree(ref_s_1);
+    sfree(act_s_1);
+    for (i=0; i<3; i++)
+        sfree(eigvec[i]);
+    sfree(eigvec);
+    
+    return (real) opt_angle;
+}
+
+
+/* Determine angle of the group by RMSD fit to the reference */
+/* Not parallelized, call this routine only on the master */
+static real flex_fit_angle(t_rotgrp *rotg)
+{
+    int         i;
+    rvec        *fitcoords=NULL;
+    rvec        center;         /* Center of positions passed to the fit routine */
+    real        fitangle;       /* Angle of the rotation group derived by fitting */
+    rvec        coord;
+    real        scal;
+    gmx_enfrotgrp_t erg;        /* Pointer to enforced rotation group data */
+
+    
+    erg=rotg->enfrotgrp;
+
+    /* Get the center of the rotation group.
+     * Note, again, erg->xc has been sorted in do_flexible */
+    get_center(erg->xc, erg->mc_sorted, rotg->nat, center);
+
+    /* === Determine the optimal fit angle for the rotation group === */
+    if (rotg->eFittype == erotgFitNORM)
+    {
+        /* Normalize every position to it's reference length */
+        for (i=0; i<rotg->nat; i++)
+        {
+            /* Put the center of the positions into the origin */
+            rvec_sub(erg->xc[i], center, coord);
+            /* Determine the scaling factor for the length: */
+            scal = erg->xc_ref_length[erg->xc_sortind[i]] / norm(coord);
+            /* Get position, multiply with the scaling factor and save  */
+            svmul(scal, coord, erg->xc_norm[i]);
+        }
+        fitcoords = erg->xc_norm;
+    }
+    else
+    {
+        fitcoords = erg->xc;
+    }
+    /* From the point of view of the current positions, the reference has rotated
+     * backwards. Since we output the angle relative to the fixed reference,
+     * we need the minus sign. */
+    fitangle = -opt_angle_analytic(erg->xc_ref_sorted, fitcoords, erg->mc_sorted,
+                                   rotg->nat, erg->xc_ref_center, center, rotg->vec);
+
+    return fitangle;
+}
+
+
+/* Determine actual angle of each slab by RMSD fit to the reference */
+/* Not parallelized, call this routine only on the master */
+static void flex_fit_angle_perslab(
+        int  g,
+        t_rotgrp *rotg,
+        double t,
+        real degangle,
+        FILE *fp)
+{
+    int         i,l,n,islab,ind;
+    rvec        curr_x, ref_x;
+    rvec        act_center;  /* Center of actual positions that are passed to the fit routine */
+    rvec        ref_center;  /* Same for the reference positions */
+    real        fitangle;    /* Angle of a slab derived from an RMSD fit to
+                              * the reference structure at t=0  */
+    t_gmx_slabdata *sd;
+    gmx_enfrotgrp_t erg;     /* Pointer to enforced rotation group data */
+    real        OOm_av;      /* 1/average_mass of a rotation group atom */
+    real        m_rel;       /* Relative mass of a rotation group atom  */
+
+
+    erg=rotg->enfrotgrp;
+
+    /* Average mass of a rotation group atom: */
+    OOm_av = erg->invmass*rotg->nat;
+
+    /**********************************/
+    /* First collect the data we need */
+    /**********************************/
+
+    /* Collect the data for the individual slabs */
+    for (n = erg->slab_first; n <= erg->slab_last; n++)
+    {
+        islab = n - erg->slab_first; /* slab index */
+        sd = &(rotg->enfrotgrp->slab_data[islab]);
+        sd->nat = erg->lastatom[islab]-erg->firstatom[islab]+1;
+        ind = 0;
+
+        /* Loop over the relevant atoms in the slab */
+        for (l=erg->firstatom[islab]; l<=erg->lastatom[islab]; l++)
+        {
+            /* Current position of this atom: x[ii][XX/YY/ZZ] */
+            copy_rvec(erg->xc[l], curr_x);
+
+            /* The (unrotated) reference position of this atom is copied to ref_x.
+             * Beware, the xc coords have been sorted in do_flexible */
+            copy_rvec(erg->xc_ref_sorted[l], ref_x);
+
+            /* Save data for doing angular RMSD fit later */
+            /* Save the current atom position */
+            copy_rvec(curr_x, sd->x[ind]);
+            /* Save the corresponding reference position */
+            copy_rvec(ref_x , sd->ref[ind]);
+
+            /* Maybe also mass-weighting was requested. If yes, additionally
+             * multiply the weights with the relative mass of the atom. If not,
+             * multiply with unity. */
+            m_rel = erg->mc_sorted[l]*OOm_av;
+
+            /* Save the weight for this atom in this slab */
+            sd->weight[ind] = gaussian_weight(curr_x, rotg, n) * m_rel;
+
+            /* Next atom in this slab */
+            ind++;
+        }
+    }
+
+    /******************************/
+    /* Now do the fit calculation */
+    /******************************/
+
+    fprintf(fp, "%12.3e%6d%12.3f", t, g, degangle);
+
+    /* === Now do RMSD fitting for each slab === */
+    /* We require at least SLAB_MIN_ATOMS in a slab, such that the fit makes sense. */
+#define SLAB_MIN_ATOMS 4
+
+    for (n = erg->slab_first; n <= erg->slab_last; n++)
+    {
+        islab = n - erg->slab_first; /* slab index */
+        sd = &(rotg->enfrotgrp->slab_data[islab]);
+        if (sd->nat >= SLAB_MIN_ATOMS)
+        {
+            /* Get the center of the slabs reference and current positions */
+            get_center(sd->ref, sd->weight, sd->nat, ref_center);
+            get_center(sd->x  , sd->weight, sd->nat, act_center);
+            if (rotg->eFittype == erotgFitNORM)
+            {
+                /* Normalize every position to it's reference length
+                 * prior to performing the fit */
+                for (i=0; i<sd->nat;i++) /* Center */
+                {
+                    rvec_dec(sd->ref[i], ref_center);
+                    rvec_dec(sd->x[i]  , act_center);
+                    /* Normalize x_i such that it gets the same length as ref_i */
+                    svmul( norm(sd->ref[i])/norm(sd->x[i]), sd->x[i], sd->x[i] );
+                }
+                /* We already subtracted the centers */
+                clear_rvec(ref_center);
+                clear_rvec(act_center);
+            }
+            fitangle = -opt_angle_analytic(sd->ref, sd->x, sd->weight, sd->nat,
+                                           ref_center, act_center, rotg->vec);
+            fprintf(fp, "%6d%6d%12.3f", n, sd->nat, fitangle);
+        }
+    }
+    fprintf(fp     , "\n");
+
+#undef SLAB_MIN_ATOMS
+}
+
+
+/* Shift x with is */
+static inline void shift_single_coord(matrix box, rvec x, const ivec is)
+{
+    int tx,ty,tz;
+
+
+    tx=is[XX];
+    ty=is[YY];
+    tz=is[ZZ];
+
+    if(TRICLINIC(box))
+    {
+        x[XX] += tx*box[XX][XX]+ty*box[YY][XX]+tz*box[ZZ][XX];
+        x[YY] += ty*box[YY][YY]+tz*box[ZZ][YY];
+        x[ZZ] += tz*box[ZZ][ZZ];
+    } else
+    {
+        x[XX] += tx*box[XX][XX];
+        x[YY] += ty*box[YY][YY];
+        x[ZZ] += tz*box[ZZ][ZZ];
+    }
+}
+
+
+/* Determine the 'home' slab of this atom which is the
+ * slab with the highest Gaussian weight of all */
+#define round(a) (int)(a+0.5)
+static inline int get_homeslab(
+        rvec curr_x,   /* The position for which the home slab shall be determined */ 
+        rvec rotvec,   /* The rotation vector */
+        real slabdist) /* The slab distance */
+{
+    real dist;
+    
+    
+    /* The distance of the atom to the coordinate center (where the
+     * slab with index 0) is */
+    dist = iprod(rotvec, curr_x);
+    
+    return round(dist / slabdist); 
+}
+
+
+/* For a local atom determine the relevant slabs, i.e. slabs in
+ * which the gaussian is larger than min_gaussian
+ */
+static int get_single_atom_gaussians(
+        rvec      curr_x,
+        t_commrec *cr,
+        t_rotgrp  *rotg)
+{
+   int slab, homeslab;
+   real g;
+   int count = 0;
+   gmx_enfrotgrp_t erg;       /* Pointer to enforced rotation group data */
+
+   
+   erg=rotg->enfrotgrp;
+   
+   /* Determine the 'home' slab of this atom: */
+   homeslab = get_homeslab(curr_x, rotg->vec, rotg->slab_dist);
+
+   /* First determine the weight in the atoms home slab: */
+   g = gaussian_weight(curr_x, rotg, homeslab);
+   
+   erg->gn_atom[count] = g;
+   erg->gn_slabind[count] = homeslab;
+   count++;
+   
+   
+   /* Determine the max slab */
+   slab = homeslab;
+   while (g > rotg->min_gaussian)
+   {
+       slab++;
+       g = gaussian_weight(curr_x, rotg, slab);
+       erg->gn_slabind[count]=slab;
+       erg->gn_atom[count]=g;
+       count++;
+   }
+   count--;
+   
+   /* Determine the max slab */
+   slab = homeslab;
+   do
+   {
+       slab--;
+       g = gaussian_weight(curr_x, rotg, slab);       
+       erg->gn_slabind[count]=slab;
+       erg->gn_atom[count]=g;
+       count++;
+   }
+   while (g > rotg->min_gaussian);
+   count--;
+   
+   return count;
+}
+
+
+static void flex2_precalc_inner_sum(t_rotgrp *rotg, t_commrec *cr)
+{
+    int  i,n,islab;
+    rvec  xi;                /* positions in the i-sum                        */
+    rvec  xcn, ycn;          /* the current and the reference slab centers    */
+    real gaussian_xi;
+    rvec yi0;
+    rvec  rin;               /* Helper variables                              */
+    real  fac,fac2;
+    rvec innersumvec;
+    real OOpsii,OOpsiistar;
+    real sin_rin;          /* s_ii.r_ii */
+    rvec s_in,tmpvec,tmpvec2;
+    real mi,wi;            /* Mass-weighting of the positions                 */
+    real N_M;              /* N/M                                             */
+    gmx_enfrotgrp_t erg;    /* Pointer to enforced rotation group data */
+
+
+    erg=rotg->enfrotgrp;
+    N_M = rotg->nat * erg->invmass;
+
+    /* Loop over all slabs that contain something */
+    for (n=erg->slab_first; n <= erg->slab_last; n++)
+    {
+        islab = n - erg->slab_first; /* slab index */
+
+        /* The current center of this slab is saved in xcn: */
+        copy_rvec(erg->slab_center[islab], xcn);
+        /* ... and the reference center in ycn: */
+        copy_rvec(erg->slab_center_ref[islab+erg->slab_buffer], ycn);
+
+        /*** D. Calculate the whole inner sum used for second and third sum */
+        /* For slab n, we need to loop over all atoms i again. Since we sorted
+         * the atoms with respect to the rotation vector, we know that it is sufficient
+         * to calculate from firstatom to lastatom only. All other contributions will
+         * be very small. */
+        clear_rvec(innersumvec);
+        for (i = erg->firstatom[islab]; i <= erg->lastatom[islab]; i++)
+        {
+            /* Coordinate xi of this atom */
+            copy_rvec(erg->xc[i],xi);
+
+            /* The i-weights */
+            gaussian_xi = gaussian_weight(xi,rotg,n);
+            mi = erg->mc_sorted[i];  /* need the sorted mass here */
+            wi = N_M*mi;
+
+            /* Calculate rin */
+            copy_rvec(erg->xc_ref_sorted[i],yi0); /* Reference position yi0   */
+            rvec_sub(yi0, ycn, tmpvec2);          /* tmpvec2 = yi0 - ycn      */
+            mvmul(erg->rotmat, tmpvec2, rin);     /* rin = Omega.(yi0 - ycn)  */
+
+            /* Calculate psi_i* and sin */
+            rvec_sub(xi, xcn, tmpvec2);           /* tmpvec2 = xi - xcn       */
+            cprod(rotg->vec, tmpvec2, tmpvec);    /* tmpvec = v x (xi - xcn)  */
+            OOpsiistar = norm2(tmpvec)+rotg->eps; /* OOpsii* = 1/psii* = |v x (xi-xcn)|^2 + eps */
+            OOpsii = norm(tmpvec);                /* OOpsii = 1 / psii = |v x (xi - xcn)| */
+
+                                       /*         v x (xi - xcn)          */
+            unitv(tmpvec, s_in);       /*  sin = ----------------         */
+                                       /*        |v x (xi - xcn)|         */
+
+            sin_rin=iprod(s_in,rin);   /* sin_rin = sin . rin             */
+
+            /* Now the whole sum */
+            fac = OOpsii/OOpsiistar;
+            svmul(fac, rin, tmpvec);
+            fac2 = fac*fac*OOpsii;
+            svmul(fac2*sin_rin, s_in, tmpvec2);
+            rvec_dec(tmpvec, tmpvec2);
+
+            svmul(wi*gaussian_xi*sin_rin, tmpvec, tmpvec2);
+
+            rvec_inc(innersumvec,tmpvec2);
+        } /* now we have the inner sum, used both for sum2 and sum3 */
+
+        /* Save it to be used in do_flex2_lowlevel */
+        copy_rvec(innersumvec, erg->slab_innersumvec[islab]);
+    } /* END of loop over slabs */
+}
+
+
+static void flex_precalc_inner_sum(t_rotgrp *rotg, t_commrec *cr)
+{
+    int   i,n,islab;
+    rvec  xi;                /* position                                      */
+    rvec  xcn, ycn;          /* the current and the reference slab centers    */
+    rvec  qin,rin;           /* q_i^n and r_i^n                               */
+    real  bin;
+    rvec  tmpvec;
+    rvec  innersumvec;       /* Inner part of sum_n2                          */
+    real  gaussian_xi;       /* Gaussian weight gn(xi)                        */
+    real  mi,wi;             /* Mass-weighting of the positions               */
+    real  N_M;               /* N/M                                           */
+
+    gmx_enfrotgrp_t erg;    /* Pointer to enforced rotation group data */
+
+
+    erg=rotg->enfrotgrp;
+    N_M = rotg->nat * erg->invmass;
+
+    /* Loop over all slabs that contain something */
+    for (n=erg->slab_first; n <= erg->slab_last; n++)
+    {
+        islab = n - erg->slab_first; /* slab index */
+
+        /* The current center of this slab is saved in xcn: */
+        copy_rvec(erg->slab_center[islab], xcn);
+        /* ... and the reference center in ycn: */
+        copy_rvec(erg->slab_center_ref[islab+erg->slab_buffer], ycn);
+
+        /* For slab n, we need to loop over all atoms i again. Since we sorted
+         * the atoms with respect to the rotation vector, we know that it is sufficient
+         * to calculate from firstatom to lastatom only. All other contributions will
+         * be very small. */
+        clear_rvec(innersumvec);
+        for (i=erg->firstatom[islab]; i<=erg->lastatom[islab]; i++)
+        {
+            /* Coordinate xi of this atom */
+            copy_rvec(erg->xc[i],xi);
+
+            /* The i-weights */
+            gaussian_xi = gaussian_weight(xi,rotg,n);
+            mi = erg->mc_sorted[i];  /* need the sorted mass here */
+            wi = N_M*mi;
+
+            /* Calculate rin and qin */
+            rvec_sub(erg->xc_ref_sorted[i], ycn, tmpvec); /* tmpvec = yi0-ycn */
+            mvmul(erg->rotmat, tmpvec, rin);      /* rin = Omega.(yi0 - ycn)  */
+            cprod(rotg->vec, rin, tmpvec);    /* tmpvec = v x Omega*(yi0-ycn) */
+
+                                             /*        v x Omega*(yi0-ycn)    */
+            unitv(tmpvec, qin);              /* qin = ---------------------   */
+                                             /*       |v x Omega*(yi0-ycn)|   */
+
+            /* Calculate bin */
+            rvec_sub(xi, xcn, tmpvec);            /* tmpvec = xi-xcn          */
+            bin = iprod(qin, tmpvec);             /* bin  = qin*(xi-xcn)      */
+
+            svmul(wi*gaussian_xi*bin, qin, tmpvec);
+
+            /* Add this contribution to the inner sum: */
+            rvec_add(innersumvec, tmpvec, innersumvec);
+        } /* now we have the inner sum vector S^n for this slab */
+        /* Save it to be used in do_flex_lowlevel */
+        copy_rvec(innersumvec, erg->slab_innersumvec[islab]);
+    }
+}
+
+
+static real do_flex2_lowlevel(
+        t_rotgrp  *rotg,
+        real      sigma,    /* The Gaussian width sigma */
+        rvec      x[],
+        gmx_bool  bCalcTorque,
+        matrix    box,
+        t_commrec *cr)
+{
+    int  count,ic,ii,j,m,n,islab,iigrp;
+    rvec  xj;                /* position in the i-sum                         */
+    rvec  yj0;               /* the reference position in the j-sum           */
+    rvec  xcn, ycn;          /* the current and the reference slab centers    */
+    real V;                  /* This node's part of the rotation pot. energy  */
+    real gaussian_xj;        /* Gaussian weight                               */
+    real beta;
+
+    real  numerator;
+    rvec  rjn;               /* Helper variables                              */
+    real  fac,fac2;
+
+    real OOpsij,OOpsijstar;
+    real OOsigma2;           /* 1/(sigma^2)                                   */
+    real sjn_rjn;
+    real betasigpsi;
+    rvec sjn,tmpvec,tmpvec2;
+    rvec sum1vec_part,sum1vec,sum2vec_part,sum2vec,sum3vec,sum4vec,innersumvec;
+    real sum3,sum4;
+    gmx_enfrotgrp_t erg;     /* Pointer to enforced rotation group data       */
+    real mj,wj;              /* Mass-weighting of the positions               */
+    real N_M;                /* N/M                                           */
+    real Wjn;                /* g_n(x_j) m_j / Mjn                            */
+
+    /* To calculate the torque per slab */
+    rvec slab_force;         /* Single force from slab n on one atom          */
+    rvec slab_sum1vec_part;
+    real slab_sum3part,slab_sum4part;
+    rvec slab_sum1vec, slab_sum2vec, slab_sum3vec, slab_sum4vec;
+
+
+    erg=rotg->enfrotgrp;
+
+    /* Pre-calculate the inner sums, so that we do not have to calculate
+     * them again for every atom */
+    flex2_precalc_inner_sum(rotg, cr);
+
+    /********************************************************/
+    /* Main loop over all local atoms of the rotation group */
+    /********************************************************/
+    N_M = rotg->nat * erg->invmass;
+    V = 0.0;
+    OOsigma2 = 1.0 / (sigma*sigma);
+    for (j=0; j<erg->nat_loc; j++)
+    {
+        /* Local index of a rotation group atom  */
+        ii = erg->ind_loc[j];
+        /* Position of this atom in the collective array */
+        iigrp = erg->xc_ref_ind[j];
+        /* Mass-weighting */
+        mj = erg->mc[iigrp];  /* need the unsorted mass here */
+        wj = N_M*mj;
+        
+        /* Current position of this atom: x[ii][XX/YY/ZZ]
+         * Note that erg->xc_center contains the center of mass in case the flex2-t
+         * potential was chosen. For the flex2 potential erg->xc_center must be
+         * zero. */
+        rvec_sub(x[ii], erg->xc_center, xj);
+
+        /* Shift this atom such that it is near its reference */
+        shift_single_coord(box, xj, erg->xc_shifts[iigrp]);
+
+        /* Determine the slabs to loop over, i.e. the ones with contributions
+         * larger than min_gaussian */
+        count = get_single_atom_gaussians(xj, cr, rotg);
+        
+        clear_rvec(sum1vec_part);
+        clear_rvec(sum2vec_part);
+        sum3 = 0.0;
+        sum4 = 0.0;
+        /* Loop over the relevant slabs for this atom */
+        for (ic=0; ic < count; ic++)  
+        {
+            n = erg->gn_slabind[ic];
+            
+            /* Get the precomputed Gaussian value of curr_slab for curr_x */
+            gaussian_xj = erg->gn_atom[ic];
+
+            islab = n - erg->slab_first; /* slab index */
+            
+            /* The (unrotated) reference position of this atom is copied to yj0: */
+            copy_rvec(rotg->x_ref[iigrp], yj0);
+
+            beta = calc_beta(xj, rotg,n);
+
+            /* The current center of this slab is saved in xcn: */
+            copy_rvec(erg->slab_center[islab], xcn);
+            /* ... and the reference center in ycn: */
+            copy_rvec(erg->slab_center_ref[islab+erg->slab_buffer], ycn);
+            
+            rvec_sub(yj0, ycn, tmpvec2);          /* tmpvec2 = yj0 - ycn      */
+
+            /* Rotate: */
+            mvmul(erg->rotmat, tmpvec2, rjn);     /* rjn = Omega.(yj0 - ycn)  */
+            
+            /* Subtract the slab center from xj */
+            rvec_sub(xj, xcn, tmpvec2);           /* tmpvec2 = xj - xcn       */
+
+            /* Calculate sjn */
+            cprod(rotg->vec, tmpvec2, tmpvec);    /* tmpvec = v x (xj - xcn)  */
+
+            OOpsijstar = norm2(tmpvec)+rotg->eps; /* OOpsij* = 1/psij* = |v x (xj-xcn)|^2 + eps */
+
+            numerator = sqr(iprod(tmpvec, rjn));
+            
+            /*********************************/
+            /* Add to the rotation potential */
+            /*********************************/
+            V += 0.5*rotg->k*wj*gaussian_xj*numerator/OOpsijstar;
+
+
+            /*************************************/
+            /* Now calculate the force on atom j */
+            /*************************************/
+
+            OOpsij = norm(tmpvec);    /* OOpsij = 1 / psij = |v x (xj - xcn)| */
+
+                                           /*         v x (xj - xcn)          */
+            unitv(tmpvec, sjn);            /*  sjn = ----------------         */
+                                           /*        |v x (xj - xcn)|         */
+
+            sjn_rjn=iprod(sjn,rjn);        /* sjn_rjn = sjn . rjn             */
+
+
+            /*** A. Calculate the first of the four sum terms: ****************/
+            fac = OOpsij/OOpsijstar;
+            svmul(fac, rjn, tmpvec);
+            fac2 = fac*fac*OOpsij;
+            svmul(fac2*sjn_rjn, sjn, tmpvec2);
+            rvec_dec(tmpvec, tmpvec2);
+            fac2 = wj*gaussian_xj; /* also needed for sum4 */
+            svmul(fac2*sjn_rjn, tmpvec, slab_sum1vec_part);
+            /********************/
+            /*** Add to sum1: ***/
+            /********************/
+            rvec_inc(sum1vec_part, slab_sum1vec_part); /* sum1 still needs to vector multiplied with v */
+
+            /*** B. Calculate the forth of the four sum terms: ****************/
+            betasigpsi = beta*OOsigma2*OOpsij; /* this is also needed for sum3 */
+            /********************/
+            /*** Add to sum4: ***/
+            /********************/
+            slab_sum4part = fac2*betasigpsi*fac*sjn_rjn*sjn_rjn; /* Note that fac is still valid from above */
+            sum4 += slab_sum4part;
+
+            /*** C. Calculate Wjn for second and third sum */
+            /* Note that we can safely divide by slab_weights since we check in
+             * get_slab_centers that it is non-zero. */
+            Wjn = gaussian_xj*mj/erg->slab_weights[islab];
+
+            /* We already have precalculated the inner sum for slab n */
+            copy_rvec(erg->slab_innersumvec[islab], innersumvec);
+
+            /* Weigh the inner sum vector with Wjn */
+            svmul(Wjn, innersumvec, innersumvec);
+
+            /*** E. Calculate the second of the four sum terms: */
+            /********************/
+            /*** Add to sum2: ***/
+            /********************/
+            rvec_inc(sum2vec_part, innersumvec); /* sum2 still needs to be vector crossproduct'ed with v */
+            
+            /*** F. Calculate the third of the four sum terms: */
+            slab_sum3part = betasigpsi * iprod(sjn, innersumvec);
+            sum3 += slab_sum3part; /* still needs to be multiplied with v */
+
+            /*** G. Calculate the torque on the local slab's axis: */
+            if (bCalcTorque)
+            {
+                /* Sum1 */
+                cprod(slab_sum1vec_part, rotg->vec, slab_sum1vec);
+                /* Sum2 */
+                cprod(innersumvec, rotg->vec, slab_sum2vec);
+                /* Sum3 */
+                svmul(slab_sum3part, rotg->vec, slab_sum3vec);
+                /* Sum4 */
+                svmul(slab_sum4part, rotg->vec, slab_sum4vec);
+
+                /* The force on atom ii from slab n only: */
+                for (m=0; m<DIM; m++)
+                    slab_force[m] = rotg->k * (-slab_sum1vec[m] + slab_sum2vec[m] - slab_sum3vec[m] + 0.5*slab_sum4vec[m]);
+
+                erg->slab_torque_v[islab] += torque(rotg->vec, slab_force, xj, xcn);
+            }
+        } /* END of loop over slabs */
+
+        /* Construct the four individual parts of the vector sum: */
+        cprod(sum1vec_part, rotg->vec, sum1vec);      /* sum1vec =   { } x v  */
+        cprod(sum2vec_part, rotg->vec, sum2vec);      /* sum2vec =   { } x v  */
+        svmul(sum3, rotg->vec, sum3vec);              /* sum3vec =   { } . v  */
+        svmul(sum4, rotg->vec, sum4vec);              /* sum4vec =   { } . v  */
+
+        /* Store the additional force so that it can be added to the force
+         * array after the normal forces have been evaluated */
+        for (m=0; m<DIM; m++)
+            erg->f_rot_loc[j][m] = rotg->k * (-sum1vec[m] + sum2vec[m] - sum3vec[m] + 0.5*sum4vec[m]);
+
+#ifdef SUM_PARTS
+        fprintf(stderr, "sum1: %15.8f %15.8f %15.8f\n",    -rotg->k*sum1vec[XX],    -rotg->k*sum1vec[YY],    -rotg->k*sum1vec[ZZ]);
+        fprintf(stderr, "sum2: %15.8f %15.8f %15.8f\n",     rotg->k*sum2vec[XX],     rotg->k*sum2vec[YY],     rotg->k*sum2vec[ZZ]);
+        fprintf(stderr, "sum3: %15.8f %15.8f %15.8f\n",    -rotg->k*sum3vec[XX],    -rotg->k*sum3vec[YY],    -rotg->k*sum3vec[ZZ]);
+        fprintf(stderr, "sum4: %15.8f %15.8f %15.8f\n", 0.5*rotg->k*sum4vec[XX], 0.5*rotg->k*sum4vec[YY], 0.5*rotg->k*sum4vec[ZZ]);
+#endif
+
+        PRINT_FORCE_J
+
+    } /* END of loop over local atoms */
+
+    return V;
+}
+
+
+static real do_flex_lowlevel(
+        t_rotgrp *rotg,
+        real      sigma,     /* The Gaussian width sigma                      */
+        rvec      x[],
+        gmx_bool  bCalcTorque,
+        matrix    box,
+        t_commrec *cr)
+{
+    int   count,ic,ii,j,m,n,islab,iigrp;
+    rvec  xj,yj0;            /* current and reference position                */
+    rvec  xcn, ycn;          /* the current and the reference slab centers    */
+    rvec  xj_xcn;            /* xj - xcn                                      */
+    rvec  qjn;               /* q_i^n                                         */
+    rvec  sum_n1,sum_n2;     /* Two contributions to the rotation force       */
+    rvec  innersumvec;       /* Inner part of sum_n2                          */
+    rvec  s_n;
+    rvec  force_n;           /* Single force from slab n on one atom          */
+    rvec  force_n1,force_n2; /* First and second part of force_n              */
+    rvec  tmpvec,tmpvec2,tmp_f;   /* Helper variables                         */
+    real  V;                 /* The rotation potential energy                 */
+    real  OOsigma2;          /* 1/(sigma^2)                                   */
+    real  beta;              /* beta_n(xj)                                    */
+    real  bjn;               /* b_j^n                                         */
+    real  gaussian_xj;       /* Gaussian weight gn(xj)                        */
+    real  betan_xj_sigma2;
+    real  mj,wj;             /* Mass-weighting of the positions               */
+    real  N_M;               /* N/M                                           */
+    gmx_enfrotgrp_t erg;     /* Pointer to enforced rotation group data       */
+
+    
+    erg=rotg->enfrotgrp;
+
+    /* Pre-calculate the inner sums, so that we do not have to calculate
+     * them again for every atom */
+    flex_precalc_inner_sum(rotg, cr);
+
+    /********************************************************/
+    /* Main loop over all local atoms of the rotation group */
+    /********************************************************/
+    OOsigma2 = 1.0/(sigma*sigma);
+    N_M = rotg->nat * erg->invmass;
+    V = 0.0;
+    for (j=0; j<erg->nat_loc; j++)
+    {
+        /* Local index of a rotation group atom  */
+        ii = erg->ind_loc[j];
+        /* Position of this atom in the collective array */
+        iigrp = erg->xc_ref_ind[j];
+        /* Mass-weighting */
+        mj = erg->mc[iigrp];  /* need the unsorted mass here */
+        wj = N_M*mj;
+        
+        /* Current position of this atom: x[ii][XX/YY/ZZ]
+         * Note that erg->xc_center contains the center of mass in case the flex-t
+         * potential was chosen. For the flex potential erg->xc_center must be
+         * zero. */
+        rvec_sub(x[ii], erg->xc_center, xj);
+        
+        /* Shift this atom such that it is near its reference */
+        shift_single_coord(box, xj, erg->xc_shifts[iigrp]);
+
+        /* Determine the slabs to loop over, i.e. the ones with contributions
+         * larger than min_gaussian */
+        count = get_single_atom_gaussians(xj, cr, rotg);
+
+        clear_rvec(sum_n1);
+        clear_rvec(sum_n2);
+
+        /* Loop over the relevant slabs for this atom */
+        for (ic=0; ic < count; ic++)  
+        {
+            n = erg->gn_slabind[ic];
+                
+            /* Get the precomputed Gaussian for xj in slab n */
+            gaussian_xj = erg->gn_atom[ic];
+
+            islab = n - erg->slab_first; /* slab index */
+            
+            /* The (unrotated) reference position of this atom is saved in yj0: */
+            copy_rvec(rotg->x_ref[iigrp], yj0);
+
+            beta = calc_beta(xj, rotg, n);
+
+            /* The current center of this slab is saved in xcn: */
+            copy_rvec(erg->slab_center[islab], xcn);
+            /* ... and the reference center in ycn: */
+            copy_rvec(erg->slab_center_ref[islab+erg->slab_buffer], ycn);
+            
+            rvec_sub(yj0, ycn, tmpvec); /* tmpvec = yj0 - ycn */
+
+            /* Rotate: */
+            mvmul(erg->rotmat, tmpvec, tmpvec2); /* tmpvec2 = Omega.(yj0-ycn) */
+            
+            /* Subtract the slab center from xj */
+            rvec_sub(xj, xcn, xj_xcn);           /* xj_xcn = xj - xcn         */
+            
+            /* Calculate qjn */
+            cprod(rotg->vec, tmpvec2, tmpvec); /* tmpvec = v x Omega.(xj-xcn) */
+
+                                 /*         v x Omega.(xj-xcn)    */
+            unitv(tmpvec,qjn);   /*  qjn = --------------------   */
+                                 /*        |v x Omega.(xj-xcn)|   */
+
+            bjn = iprod(qjn, xj_xcn);   /* bjn = qjn * (xj - xcn) */
+            
+            /*********************************/
+            /* Add to the rotation potential */
+            /*********************************/
+            V += 0.5*rotg->k*wj*gaussian_xj*sqr(bjn);
+            
+            /****************************************************************/
+            /* sum_n1 will typically be the main contribution to the force: */
+            /****************************************************************/
+            betan_xj_sigma2 = beta*OOsigma2;  /*  beta_n(xj)/sigma^2  */
+
+            /* The next lines calculate
+             *  qjn - (bjn*beta(xj)/(2sigma^2))v  */
+            svmul(bjn*0.5*betan_xj_sigma2, rotg->vec, tmpvec2);
+            rvec_sub(qjn,tmpvec2,tmpvec);
+
+            /* Multiply with gn(xj)*bjn: */
+            svmul(gaussian_xj*bjn,tmpvec,tmpvec2);
+
+            /* Sum over n: */
+            rvec_inc(sum_n1,tmpvec2);
+            
+            /* We already have precalculated the Sn term for slab n */
+            copy_rvec(erg->slab_innersumvec[islab], s_n);
+                                                                          /*          beta_n(xj)              */
+            svmul(betan_xj_sigma2*iprod(s_n, xj_xcn), rotg->vec, tmpvec); /* tmpvec = ---------- s_n (xj-xcn) */
+                                                                          /*            sigma^2               */
+
+            rvec_sub(s_n, tmpvec, innersumvec);
+            
+            /* We can safely divide by slab_weights since we check in get_slab_centers
+             * that it is non-zero. */
+            svmul(gaussian_xj/erg->slab_weights[islab], innersumvec, innersumvec);
+
+            rvec_add(sum_n2, innersumvec, sum_n2);
+            
+            GMX_MPE_LOG(ev_inner_loop_finish);
+
+            /* Calculate the torque: */
+            if (bCalcTorque)
+            {
+                /* The force on atom ii from slab n only: */
+                svmul(-rotg->k*wj, tmpvec2    , force_n1); /* part 1 */
+                svmul( rotg->k*mj, innersumvec, force_n2); /* part 2 */
+                rvec_add(force_n1, force_n2, force_n);
+                erg->slab_torque_v[islab] += torque(rotg->vec, force_n, xj, xcn);
+            }
+        } /* END of loop over slabs */
+
+        /* Put both contributions together: */
+        svmul(wj, sum_n1, sum_n1);
+        svmul(mj, sum_n2, sum_n2);
+        rvec_sub(sum_n2,sum_n1,tmp_f); /* F = -grad V */
+
+        /* Store the additional force so that it can be added to the force
+         * array after the normal forces have been evaluated */
+        for(m=0; m<DIM; m++)
+            erg->f_rot_loc[j][m] = rotg->k*tmp_f[m];
+
+        PRINT_FORCE_J
+
+    } /* END of loop over local atoms */
+
+    return V;
+}
+
+#ifdef PRINT_COORDS
+static void print_coordinates(t_commrec *cr, t_rotgrp *rotg, rvec x[], matrix box, int step)
+{
+    int i;
+    static FILE *fp;
+    static char buf[STRLEN];
+    static gmx_bool bFirst=1;
+
+
+    if (bFirst)
+    {
+        sprintf(buf, "coords%d.txt", cr->nodeid);
+        fp = fopen(buf, "w");
+        bFirst = 0;
+    }
+
+    fprintf(fp, "\nStep %d\n", step);
+    fprintf(fp, "box: %f %f %f %f %f %f %f %f %f\n",
+            box[XX][XX], box[XX][YY], box[XX][ZZ],
+            box[YY][XX], box[YY][YY], box[YY][ZZ],
+            box[ZZ][XX], box[ZZ][ZZ], box[ZZ][ZZ]);
+    for (i=0; i<rotg->nat; i++)
+    {
+        fprintf(fp, "%4d  %f %f %f\n", i,
+                erg->xc[i][XX], erg->xc[i][YY], erg->xc[i][ZZ]);
+    }
+    fflush(fp);
+
+}
+#endif
+
+
+static int projection_compare(const void *a, const void *b)
+{
+    sort_along_vec_t *xca, *xcb;
+    
+    
+    xca = (sort_along_vec_t *)a;
+    xcb = (sort_along_vec_t *)b;
+    
+    if (xca->xcproj < xcb->xcproj)
+        return -1;
+    else if (xca->xcproj > xcb->xcproj)
+        return 1;
+    else
+        return 0;
+}
+
+
+static void sort_collective_coordinates(
+        t_rotgrp *rotg,         /* Rotation group */
+        sort_along_vec_t *data) /* Buffer for sorting the positions */
+{
+    int i;
+    gmx_enfrotgrp_t erg;       /* Pointer to enforced rotation group data */
+
+    
+    erg=rotg->enfrotgrp;
+    
+    /* The projection of the position vector on the rotation vector is
+     * the relevant value for sorting. Fill the 'data' structure */
+    for (i=0; i<rotg->nat; i++)
+    {
+        data[i].xcproj = iprod(erg->xc[i], rotg->vec);  /* sort criterium */
+        data[i].m      = erg->mc[i];
+        data[i].ind    = i;
+        copy_rvec(erg->xc[i]    , data[i].x    );
+        copy_rvec(rotg->x_ref[i], data[i].x_ref);
+    }
+    /* Sort the 'data' structure */
+    gmx_qsort(data, rotg->nat, sizeof(sort_along_vec_t), projection_compare);
+    
+    /* Copy back the sorted values */
+    for (i=0; i<rotg->nat; i++)
+    {
+        copy_rvec(data[i].x    , erg->xc[i]           );
+        copy_rvec(data[i].x_ref, erg->xc_ref_sorted[i]);
+        erg->mc_sorted[i]  = data[i].m;
+        erg->xc_sortind[i] = data[i].ind;
+    }
+}
+
+
+/* For each slab, get the first and the last index of the sorted atom
+ * indices */
+static void get_firstlast_atom_per_slab(t_rotgrp *rotg, t_commrec *cr)
+{
+    int i,islab,n;
+    real beta;
+    gmx_enfrotgrp_t erg;     /* Pointer to enforced rotation group data */
+
+    
+    erg=rotg->enfrotgrp;
+
+    GMX_MPE_LOG(ev_get_firstlast_start);
+    
+    /* Find the first atom that needs to enter the calculation for each slab */
+    n = erg->slab_first;  /* slab */
+    i = 0; /* start with the first atom */
+    do
+    {
+        /* Find the first atom that significantly contributes to this slab */
+        do /* move forward in position until a large enough beta is found */
+        {
+            beta = calc_beta(erg->xc[i], rotg, n);
+            i++;
+        } while ((beta < -erg->max_beta) && (i < rotg->nat));
+        i--;
+        islab = n - erg->slab_first;  /* slab index */
+        erg->firstatom[islab] = i;
+        /* Proceed to the next slab */
+        n++;
+    } while (n <= erg->slab_last);
+    
+    /* Find the last atom for each slab */
+     n = erg->slab_last; /* start with last slab */
+     i = rotg->nat-1;  /* start with the last atom */
+     do
+     {
+         do /* move backward in position until a large enough beta is found */
+         {
+             beta = calc_beta(erg->xc[i], rotg, n);
+             i--;
+         } while ((beta > erg->max_beta) && (i > -1));
+         i++;
+         islab = n - erg->slab_first;  /* slab index */
+         erg->lastatom[islab] = i;
+         /* Proceed to the next slab */
+         n--;
+     } while (n >= erg->slab_first);
+    
+     GMX_MPE_LOG(ev_get_firstlast_finish);
+}
+
+
+/* Determine the very first and very last slab that needs to be considered 
+ * For the first slab that needs to be considered, we have to find the smallest
+ * n that obeys:
+ * 
+ * x_first * v - n*Delta_x <= beta_max
+ * 
+ * slab index n, slab distance Delta_x, rotation vector v. For the last slab we 
+ * have to find the largest n that obeys
+ * 
+ * x_last * v - n*Delta_x >= -beta_max
+ *  
+ */
+static inline int get_first_slab(
+        t_rotgrp *rotg,     /* The rotation group (inputrec data) */
+        real     max_beta,  /* The max_beta value, instead of min_gaussian */
+        rvec     firstatom) /* First atom after sorting along the rotation vector v */
+{
+    /* Find the first slab for the first atom */   
+    return ceil((iprod(firstatom, rotg->vec) - max_beta)/rotg->slab_dist);
+}
+
+
+static inline int get_last_slab(
+        t_rotgrp *rotg,     /* The rotation group (inputrec data) */
+        real     max_beta,  /* The max_beta value, instead of min_gaussian */
+        rvec     lastatom)  /* Last atom along v */
+{
+    /* Find the last slab for the last atom */
+    return floor((iprod(lastatom, rotg->vec) + max_beta)/rotg->slab_dist);    
+}
+
+
+static void get_firstlast_slab_check(
+        t_rotgrp        *rotg,     /* The rotation group (inputrec data) */
+        t_gmx_enfrotgrp *erg,      /* The rotation group (data only accessible in this file) */
+        rvec            firstatom, /* First atom after sorting along the rotation vector v */
+        rvec            lastatom,  /* Last atom along v */
+        int             g,         /* The rotation group number */
+        t_commrec       *cr)
+{
+    erg->slab_first = get_first_slab(rotg, erg->max_beta, firstatom);
+    erg->slab_last  = get_last_slab(rotg, erg->max_beta, lastatom);
+
+    /* Check whether we have reference data to compare against */
+    if (erg->slab_first < erg->slab_first_ref)
+        gmx_fatal(FARGS, "%s No reference data for first slab (n=%d), unable to proceed.",
+                  RotStr, erg->slab_first);
+    
+    /* Check whether we have reference data to compare against */
+    if (erg->slab_last > erg->slab_last_ref)
+        gmx_fatal(FARGS, "%s No reference data for last slab (n=%d), unable to proceed.",
+                  RotStr, erg->slab_last);
+}
+
+
+/* Enforced rotation with a flexible axis */
+static void do_flexible(
+        t_commrec *cr,
+        gmx_enfrot_t enfrot,    /* Other rotation data                        */
+        t_rotgrp  *rotg,        /* The rotation group                         */
+        int       g,            /* Group number                               */
+        rvec      x[],          /* The local positions                        */
+        matrix    box,
+        double    t,            /* Time in picoseconds                        */
+        gmx_large_int_t step,   /* The time step                              */
+        gmx_bool  bOutstepRot,  /* Output to main rotation output file        */
+        gmx_bool  bOutstepSlab) /* Output per-slab data                       */
+{
+    int          l,nslabs;
+    real         sigma;       /* The Gaussian width sigma */
+    gmx_enfrotgrp_t erg;      /* Pointer to enforced rotation group data */
+
+    
+    erg=rotg->enfrotgrp;
+
+    /* Define the sigma value */
+    sigma = 0.7*rotg->slab_dist;
+    
+    /* Sort the collective coordinates erg->xc along the rotation vector. This is
+     * an optimization for the inner loop. */
+    sort_collective_coordinates(rotg, enfrot->data);
+    
+    /* Determine the first relevant slab for the first atom and the last
+     * relevant slab for the last atom */
+    get_firstlast_slab_check(rotg, erg, erg->xc[0], erg->xc[rotg->nat-1], g, cr);
+    
+    /* Determine for each slab depending on the min_gaussian cutoff criterium,
+     * a first and a last atom index inbetween stuff needs to be calculated */
+    get_firstlast_atom_per_slab(rotg, cr);
+
+    /* Determine the gaussian-weighted center of positions for all slabs */
+    get_slab_centers(rotg,erg->xc,erg->mc_sorted,cr,g,t,enfrot->out_slabs,bOutstepSlab,FALSE);
+        
+    /* Clear the torque per slab from last time step: */
+    nslabs = erg->slab_last - erg->slab_first + 1;
+    for (l=0; l<nslabs; l++)
+        erg->slab_torque_v[l] = 0.0;
+    
+    /* Call the rotational forces kernel */
+    GMX_MPE_LOG(ev_flexll_start);
+    if (rotg->eType == erotgFLEX || rotg->eType == erotgFLEXT)
+        erg->V = do_flex_lowlevel(rotg, sigma, x, bOutstepRot, box, cr);
+    else if (rotg->eType == erotgFLEX2 || rotg->eType == erotgFLEX2T)
+        erg->V = do_flex2_lowlevel(rotg, sigma, x, bOutstepRot, box, cr);
+    else
+        gmx_fatal(FARGS, "Unknown flexible rotation type");
+    GMX_MPE_LOG(ev_flexll_finish);
+    
+    /* Determine angle by RMSD fit to the reference - Let's hope this */
+    /* only happens once in a while, since this is not parallelized! */
+    if (MASTER(cr))
+    {
+        if (bOutstepRot)
+        {
+            /* Fit angle of the whole rotation group */
+            erg->angle_v = flex_fit_angle(rotg);
+        }
+        if (bOutstepSlab)
+        {
+            /* Fit angle of each slab */
+            flex_fit_angle_perslab(g, rotg, t, erg->degangle, enfrot->out_angles);
+        }
+    }
+
+    /* Lump together the torques from all slabs: */
+    erg->torque_v = 0.0;
+    for (l=0; l<nslabs; l++)
+         erg->torque_v += erg->slab_torque_v[l];
+}
+
+
+/* Calculate the angle between reference and actual rotation group atom,
+ * both projected into a plane perpendicular to the rotation vector: */
+static void angle(t_rotgrp *rotg,
+        rvec x_act,
+        rvec x_ref,
+        real *alpha,
+        real *weight)  /* atoms near the rotation axis should count less than atoms far away */
+{
+    rvec xp, xrp;  /* current and reference positions projected on a plane perpendicular to pg->vec */
+    rvec dum;
+
+
+    /* Project x_ref and x into a plane through the origin perpendicular to rot_vec: */
+    /* Project x_ref: xrp = x_ref - (vec * x_ref) * vec */
+    svmul(iprod(rotg->vec, x_ref), rotg->vec, dum);
+    rvec_sub(x_ref, dum, xrp);
+    /* Project x_act: */
+    svmul(iprod(rotg->vec, x_act), rotg->vec, dum);
+    rvec_sub(x_act, dum, xp);
+
+    /* Retrieve information about which vector precedes. gmx_angle always
+     * returns a positive angle. */
+    cprod(xp, xrp, dum); /* if reference precedes, this is pointing into the same direction as vec */
+
+    if (iprod(rotg->vec, dum) >= 0)
+        *alpha = -gmx_angle(xrp, xp);
+    else
+        *alpha = +gmx_angle(xrp, xp);
+    
+    /* Also return the weight */
+    *weight = norm(xp);
+}
+
+
+/* Project first vector onto a plane perpendicular to the second vector 
+ * dr = dr - (dr.v)v
+ * Note that v must be of unit length.
+ */
+static inline void project_onto_plane(rvec dr, const rvec v)
+{
+    rvec tmp;
+    
+    
+    svmul(iprod(dr,v),v,tmp);  /* tmp = (dr.v)v */
+    rvec_dec(dr, tmp);         /* dr = dr - (dr.v)v */
+}
+
+
+/* Fixed rotation: The rotation reference group rotates around an axis */
+/* The atoms of the actual rotation group are attached with imaginary  */
+/* springs to the reference atoms.                                     */
+static void do_fixed(
+        t_commrec *cr,
+        t_rotgrp  *rotg,        /* The rotation group          */
+        rvec      x[],          /* The positions               */
+        matrix    box,          /* The simulation box          */
+        double    t,            /* Time in picoseconds         */
+        gmx_large_int_t step,   /* The time step               */
+        gmx_bool  bTorque)
+{
+    int       j,m;
+    rvec      dr;
+    rvec      tmp_f;           /* Force */
+    real      alpha;           /* a single angle between an actual and a reference position */
+    real      weight;          /* single weight for a single angle */
+    gmx_enfrotgrp_t erg;       /* Pointer to enforced rotation group data */
+    rvec      tmpvec;
+
+    /* for mass weighting: */
+    real      wi;              /* Mass-weighting of the positions */
+    real      N_M;             /* N/M */
+    real      k_wi;            /* k times wi */
+
+    gmx_bool  bProject;
+
+    
+    erg=rotg->enfrotgrp;
+    bProject = (rotg->eType==erotgPM) || (rotg->eType==erotgPMPF);
+
+    N_M = rotg->nat * erg->invmass;
+
+    /* Each process calculates the forces on its local atoms */
+    for (j=0; j<erg->nat_loc; j++)
+    {
+        /* Calculate (x_i-x_c) resp. (x_i-u) */
+        rvec_sub(erg->x_loc_pbc[j], erg->xc_center, tmpvec);
+
+        /* Calculate Omega*(y_i-y_c)-(x_i-x_c) */
+        rvec_sub(erg->xr_loc[j], tmpvec, dr);
+        
+        if (bProject)
+            project_onto_plane(dr, rotg->vec);
+            
+        /* Mass-weighting */
+        wi = N_M*erg->m_loc[j];
+
+        /* Store the additional force so that it can be added to the force
+         * array after the normal forces have been evaluated */
+        k_wi = rotg->k*wi;
+        for (m=0; m<DIM; m++)
+        {
+            tmp_f[m]             = k_wi*dr[m];
+            erg->f_rot_loc[j][m] = tmp_f[m];
+            erg->V              += 0.5*k_wi*sqr(dr[m]);
+        }
+        
+        if (bTorque)
+        {
+            /* Add to the torque of this rotation group */
+            erg->torque_v += torque(rotg->vec, tmp_f, erg->x_loc_pbc[j], erg->xc_center);
+            
+            /* Calculate the angle between reference and actual rotation group atom. */
+            angle(rotg, tmpvec, erg->xr_loc[j], &alpha, &weight);  /* angle in rad, weighted */
+            erg->angle_v  += alpha * weight;
+            erg->weight_v += weight;
+        }
+        /* If you want enforced rotation to contribute to the virial,
+         * activate the following lines:
+            if (MASTER(cr))
+            {
+               Add the rotation contribution to the virial
+              for(j=0; j<DIM; j++)
+                for(m=0;m<DIM;m++)
+                  vir[j][m] += 0.5*f[ii][j]*dr[m];
+            }
+         */
+
+        PRINT_FORCE_J
+
+    } /* end of loop over local rotation group atoms */
+}
+
+
+/* Calculate the radial motion potential and forces */
+static void do_radial_motion(
+        t_commrec *cr,
+        t_rotgrp  *rotg,        /* The rotation group          */
+        rvec      x[],          /* The positions               */
+        matrix    box,          /* The simulation box          */
+        double    t,            /* Time in picoseconds         */
+        gmx_large_int_t step,   /* The time step               */
+        gmx_bool  bTorque)
+{
+    int       j;
+    rvec      tmp_f;           /* Force */
+    real      alpha;           /* a single angle between an actual and a reference position */
+    real      weight;          /* single weight for a single angle */
+    gmx_enfrotgrp_t erg;       /* Pointer to enforced rotation group data */
+    rvec      xj_u;            /* xj - u */
+    rvec      tmpvec;
+    real      fac,fac2,sum=0.0;
+    rvec      pj;
+
+    /* For mass weighting: */
+    real      wj;              /* Mass-weighting of the positions */
+    real      N_M;             /* N/M */
+
+
+    erg=rotg->enfrotgrp;
+
+    N_M = rotg->nat * erg->invmass;
+
+    /* Each process calculates the forces on its local atoms */
+    for (j=0; j<erg->nat_loc; j++)
+    {
+        /* Calculate (xj-u) */
+        rvec_sub(erg->x_loc_pbc[j], erg->xc_center, xj_u);  /* xj_u = xj-u */
+
+        /* Calculate Omega.(yj-u) */
+        cprod(rotg->vec, erg->xr_loc[j], tmpvec);  /* tmpvec = v x Omega.(yj-u) */
+
+                              /*         v x Omega.(yj-u)     */
+        unitv(tmpvec, pj);    /*  pj = --------------------   */
+                              /*       | v x Omega.(yj-u) |   */
+
+        fac = iprod(pj, xj_u);  /* fac = pj.(xj-u) */
+        fac2 = fac*fac;
+
+        /* Mass-weighting */
+        wj = N_M*erg->m_loc[j];
+
+        /* Store the additional force so that it can be added to the force
+         * array after the normal forces have been evaluated */
+        svmul(-rotg->k*wj*fac, pj, tmp_f);
+        copy_rvec(tmp_f, erg->f_rot_loc[j]);
+        sum += wj*fac2;
+        if (bTorque)
+        {
+            /* Add to the torque of this rotation group */
+            erg->torque_v += torque(rotg->vec, tmp_f, erg->x_loc_pbc[j], erg->xc_center);
+
+            /* Calculate the angle between reference and actual rotation group atom. */
+            angle(rotg, xj_u, erg->xr_loc[j], &alpha, &weight);  /* angle in rad, weighted */
+            erg->angle_v  += alpha * weight;
+            erg->weight_v += weight;
+        }
+
+        PRINT_FORCE_J
+
+    } /* end of loop over local rotation group atoms */
+    erg->V = 0.5*rotg->k*sum;
+}
+
+
+/* Calculate the radial motion pivot-free potential and forces */
+static void do_radial_motion_pf(
+        t_commrec *cr,
+        t_rotgrp  *rotg,        /* The rotation group          */
+        rvec      x[],          /* The positions               */
+        matrix    box,          /* The simulation box          */
+        double    t,            /* Time in picoseconds         */
+        gmx_large_int_t step,   /* The time step               */
+        gmx_bool  bTorque)
+{
+    int       i,ii,iigrp,j;
+    rvec      xj;              /* Current position */
+    rvec      xj_xc;           /* xj  - xc  */
+    rvec      yj0_yc0;         /* yj0 - yc0 */
+    rvec      tmp_f;           /* Force */
+    real      alpha;           /* a single angle between an actual and a reference position */
+    real      weight;          /* single weight for a single angle */
+    gmx_enfrotgrp_t erg;       /* Pointer to enforced rotation group data */
+    rvec      tmpvec, tmpvec2;
+    rvec      innersumvec;     /* Precalculation of the inner sum */
+    rvec      innersumveckM;
+    real      fac,fac2,V=0.0;
+    rvec      qi,qj;
+
+    /* For mass weighting: */
+    real      mj,wi,wj;        /* Mass-weighting of the positions */
+    real      N_M;             /* N/M */
+
+
+    erg=rotg->enfrotgrp;
+
+    N_M = rotg->nat * erg->invmass;
+
+    /* Get the current center of the rotation group: */
+    get_center(erg->xc, erg->mc, rotg->nat, erg->xc_center);
+
+    /* Precalculate Sum_i [ wi qi.(xi-xc) qi ] which is needed for every single j */
+    clear_rvec(innersumvec);
+    for (i=0; i < rotg->nat; i++)
+    {
+        /* Mass-weighting */
+        wi = N_M*erg->mc[i];
+
+        /* Calculate qi. Note that xc_ref_center has already been subtracted from
+         * x_ref in init_rot_group.*/
+        mvmul(erg->rotmat, rotg->x_ref[i], tmpvec);  /* tmpvec  = Omega.(yi0-yc0) */
+
+        cprod(rotg->vec, tmpvec, tmpvec2);          /* tmpvec2 = v x Omega.(yi0-yc0) */
+
+                              /*         v x Omega.(yi0-yc0)     */
+        unitv(tmpvec2, qi);   /*  qi = -----------------------   */
+                              /*       | v x Omega.(yi0-yc0) |   */
+
+        rvec_sub(erg->xc[i], erg->xc_center, tmpvec);  /* tmpvec = xi-xc */
+
+        svmul(wi*iprod(qi, tmpvec), qi, tmpvec2);
+
+        rvec_inc(innersumvec, tmpvec2);
+    }
+    svmul(rotg->k*erg->invmass, innersumvec, innersumveckM);
+
+    /* Each process calculates the forces on its local atoms */
+    for (j=0; j<erg->nat_loc; j++)
+    {
+        /* Local index of a rotation group atom  */
+        ii = erg->ind_loc[j];
+        /* Position of this atom in the collective array */
+        iigrp = erg->xc_ref_ind[j];
+        /* Mass-weighting */
+        mj = erg->mc[iigrp];  /* need the unsorted mass here */
+        wj = N_M*mj;
+
+        /* Current position of this atom: x[ii][XX/YY/ZZ] */
+        copy_rvec(x[ii], xj);
+
+        /* Shift this atom such that it is near its reference */
+        shift_single_coord(box, xj, erg->xc_shifts[iigrp]);
+
+        /* The (unrotated) reference position is yj0. yc0 has already
+         * been subtracted in init_rot_group */
+        copy_rvec(rotg->x_ref[iigrp], yj0_yc0);   /* yj0_yc0 = yj0 - yc0      */
+
+        /* Calculate Omega.(yj0-yc0) */
+        mvmul(erg->rotmat, yj0_yc0, tmpvec2);     /* tmpvec2 = Omega.(yj0 - yc0)  */
+
+        cprod(rotg->vec, tmpvec2, tmpvec);  /* tmpvec = v x Omega.(yj0-yc0) */
+
+                              /*         v x Omega.(yj0-yc0)     */
+        unitv(tmpvec, qj);    /*  qj = -----------------------   */
+                              /*       | v x Omega.(yj0-yc0) |   */
+
+        /* Calculate (xj-xc) */
+        rvec_sub(xj, erg->xc_center, xj_xc);  /* xj_xc = xj-xc */
+
+        fac = iprod(qj, xj_xc);  /* fac = qj.(xj-xc) */
+        fac2 = fac*fac;
+
+        /* Store the additional force so that it can be added to the force
+         * array after the normal forces have been evaluated */
+        svmul(-rotg->k*wj*fac, qj, tmp_f); /* part 1 of force */
+        svmul(mj, innersumveckM, tmpvec);  /* part 2 of force */
+        rvec_inc(tmp_f, tmpvec);
+        copy_rvec(tmp_f, erg->f_rot_loc[j]);
+        V += wj*fac2;
+        if (bTorque)
+        {
+            /* Add to the torque of this rotation group */
+            erg->torque_v += torque(rotg->vec, tmp_f, xj, erg->xc_center);
+
+            /* Calculate the angle between reference and actual rotation group atom. */
+            angle(rotg, xj_xc, yj0_yc0, &alpha, &weight);  /* angle in rad, weighted */
+            erg->angle_v  += alpha * weight;
+            erg->weight_v += weight;
+        }
+
+        PRINT_FORCE_J
+
+    } /* end of loop over local rotation group atoms */
+    erg->V = 0.5*rotg->k*V;
+}
+
+
+/* Precalculate the inner sum for the radial motion 2 forces */
+static void radial_motion2_precalc_inner_sum(t_rotgrp  *rotg, rvec innersumvec)
+{
+    int       i;
+    gmx_enfrotgrp_t erg;       /* Pointer to enforced rotation group data */
+    rvec      xi_xc;           /* xj - xc */
+    rvec      tmpvec,tmpvec2;
+    real      fac,fac2;
+    rvec      ri,si;
+    real      siri;
+    rvec      v_xi_xc;          /* v x (xj - u) */
+    real      psii,psiistar;
+    real      wi;              /* Mass-weighting of the positions */
+    real      N_M;             /* N/M */
+    rvec      sumvec;
+
+    erg=rotg->enfrotgrp;
+    N_M = rotg->nat * erg->invmass;
+
+    /* Loop over the collective set of positions */
+    clear_rvec(sumvec);
+    for (i=0; i<rotg->nat; i++)
+    {
+        /* Mass-weighting */
+        wi = N_M*erg->mc[i];
+
+        rvec_sub(erg->xc[i], erg->xc_center, xi_xc); /* xi_xc = xi-xc         */
+
+        /* Calculate ri. Note that xc_ref_center has already been subtracted from
+         * x_ref in init_rot_group.*/
+        mvmul(erg->rotmat, rotg->x_ref[i], ri);      /* ri  = Omega.(yi0-yc0) */
+
+        cprod(rotg->vec, xi_xc, v_xi_xc);            /* v_xi_xc = v x (xi-u)  */
+
+        fac = norm2(v_xi_xc);
+                                          /*                      1           */
+        psiistar = 1.0/(fac + rotg->eps); /* psiistar = --------------------- */
+                                          /*            |v x (xi-xc)|^2 + eps */
+
+        psii = gmx_invsqrt(fac);          /*                 1                */
+                                          /*  psii    = -------------         */
+                                          /*            |v x (xi-xc)|         */
+
+        svmul(psii, v_xi_xc, si);          /*  si = psii * (v x (xi-xc) )     */
+
+        fac = iprod(v_xi_xc, ri);                   /* fac = (v x (xi-xc)).ri */
+        fac2 = fac*fac;
+
+        siri = iprod(si, ri);                       /* siri = si.ri           */
+
+        svmul(psiistar/psii, ri, tmpvec);
+        svmul(psiistar*psiistar/(psii*psii*psii) * siri, si, tmpvec2);
+        rvec_dec(tmpvec, tmpvec2);
+        cprod(tmpvec, rotg->vec, tmpvec2);
+
+        svmul(wi*siri, tmpvec2, tmpvec);
+
+        rvec_inc(sumvec, tmpvec);
+    }
+    svmul(rotg->k*erg->invmass, sumvec, innersumvec);
+}
+
+
+/* Calculate the radial motion 2 potential and forces */
+static void do_radial_motion2(
+        t_commrec *cr,
+        t_rotgrp  *rotg,        /* The rotation group          */
+        rvec      x[],          /* The positions               */
+        matrix    box,          /* The simulation box          */
+        double    t,            /* Time in picoseconds         */
+        gmx_large_int_t step,   /* The time step               */
+        gmx_bool  bTorque)
+{
+    int       ii,iigrp,j;
+    rvec      xj;              /* Position */
+    real      alpha;           /* a single angle between an actual and a reference position */
+    real      weight;          /* single weight for a single angle */
+    gmx_enfrotgrp_t erg;       /* Pointer to enforced rotation group data */
+    rvec      xj_u;            /* xj - u */
+    rvec      tmpvec,tmpvec2;
+    real      fac,fac2,Vpart=0.0;
+    rvec      rj,sj;
+    real      sjrj;
+    rvec      v_xj_u;          /* v x (xj - u) */
+    real      psij,psijstar;
+    real      mj,wj;           /* For mass-weighting of the positions */
+    real      N_M;             /* N/M */
+    gmx_bool  bPF;
+    rvec      innersumvec;
+
+
+    erg=rotg->enfrotgrp;
+
+    bPF = rotg->eType==erotgRM2PF;
+    clear_rvec(innersumvec);
+    if (bPF)
+    {
+        /* For the pivot-free variant we have to use the current center of
+         * mass of the rotation group instead of the pivot u */
+        get_center(erg->xc, erg->mc, rotg->nat, erg->xc_center);
+
+        /* Also, we precalculate the second term of the forces that is identical
+         * (up to the weight factor mj) for all forces */
+        radial_motion2_precalc_inner_sum(rotg,innersumvec);
+    }
+
+    N_M = rotg->nat * erg->invmass;
+
+    /* Each process calculates the forces on its local atoms */
+    for (j=0; j<erg->nat_loc; j++)
+    {
+        if (bPF)
+        {
+            /* Local index of a rotation group atom  */
+            ii = erg->ind_loc[j];
+            /* Position of this atom in the collective array */
+            iigrp = erg->xc_ref_ind[j];
+            /* Mass-weighting */
+            mj = erg->mc[iigrp];
+
+            /* Current position of this atom: x[ii] */
+            copy_rvec(x[ii], xj);
+
+            /* Shift this atom such that it is near its reference */
+            shift_single_coord(box, xj, erg->xc_shifts[iigrp]);
+
+            /* The (unrotated) reference position is yj0. yc0 has already
+             * been subtracted in init_rot_group */
+            copy_rvec(rotg->x_ref[iigrp], tmpvec);     /* tmpvec = yj0 - yc0  */
+
+            /* Calculate Omega.(yj0-yc0) */
+            mvmul(erg->rotmat, tmpvec, rj);          /* rj = Omega.(yj0-yc0)  */
+        }
+        else
+        {
+            mj = erg->m_loc[j];
+            copy_rvec(erg->x_loc_pbc[j], xj);
+            copy_rvec(erg->xr_loc[j], rj);           /* rj = Omega.(yj0-u)    */
+        }
+        /* Mass-weighting */
+        wj = N_M*mj;
+
+        /* Calculate (xj-u) resp. (xj-xc) */
+        rvec_sub(xj, erg->xc_center, xj_u);          /* xj_u = xj-u           */
+
+        cprod(rotg->vec, xj_u, v_xj_u);              /* v_xj_u = v x (xj-u)   */
+
+        fac = norm2(v_xj_u);
+                                          /*                      1           */
+        psijstar = 1.0/(fac + rotg->eps); /*  psistar = --------------------  */
+                                          /*            |v x (xj-u)|^2 + eps  */
+
+        psij = gmx_invsqrt(fac);          /*                 1                */
+                                          /*  psij    = ------------          */
+                                          /*            |v x (xj-u)|          */
+
+        svmul(psij, v_xj_u, sj);          /*  sj = psij * (v x (xj-u) )       */
+
+        fac = iprod(v_xj_u, rj);                     /* fac = (v x (xj-u)).rj */
+        fac2 = fac*fac;
+
+        sjrj = iprod(sj, rj);                        /* sjrj = sj.rj          */
+
+        svmul(psijstar/psij, rj, tmpvec);
+        svmul(psijstar*psijstar/(psij*psij*psij) * sjrj, sj, tmpvec2);
+        rvec_dec(tmpvec, tmpvec2);
+        cprod(tmpvec, rotg->vec, tmpvec2);
+
+        /* Store the additional force so that it can be added to the force
+         * array after the normal forces have been evaluated */
+        svmul(-rotg->k*wj*sjrj, tmpvec2, tmpvec);
+        svmul(mj, innersumvec, tmpvec2);  /* This is != 0 only for the pivot-free variant */
+
+        rvec_add(tmpvec2, tmpvec, erg->f_rot_loc[j]);
+        Vpart += wj*psijstar*fac2;
+        if (bTorque)
+        {
+            /* Add to the torque of this rotation group */
+            erg->torque_v += torque(rotg->vec, erg->f_rot_loc[j], xj, erg->xc_center);
+
+            /* Calculate the angle between reference and actual rotation group atom. */
+            angle(rotg, xj_u, rj, &alpha, &weight);  /* angle in rad, weighted */
+            erg->angle_v  += alpha * weight;
+            erg->weight_v += weight;
+        }
+
+        PRINT_FORCE_J
+
+    } /* end of loop over local rotation group atoms */
+    erg->V = 0.5*rotg->k*Vpart;
+}
+
+
+/* Determine the smallest and largest position vector (with respect to the 
+ * rotation vector) for the reference group */
+static void get_firstlast_atom_ref(
+        t_rotgrp  *rotg, 
+        int       *firstindex, 
+        int       *lastindex)
+{
+    gmx_enfrotgrp_t erg;       /* Pointer to enforced rotation group data */
+    int i;
+    real xcproj;               /* The projection of a reference position on the 
+                                  rotation vector */
+    real minproj, maxproj;     /* Smallest and largest projection on v */
+    
+
+    
+    erg=rotg->enfrotgrp;
+
+    /* Start with some value */
+    minproj = iprod(rotg->x_ref[0], rotg->vec);
+    maxproj = minproj;
+    
+    /* This is just to ensure that it still works if all the atoms of the 
+     * reference structure are situated in a plane perpendicular to the rotation 
+     * vector */
+    *firstindex = 0;
+    *lastindex  = rotg->nat-1;
+    
+    /* Loop over all atoms of the reference group, 
+     * project them on the rotation vector to find the extremes */
+    for (i=0; i<rotg->nat; i++)
+    {
+        xcproj = iprod(rotg->x_ref[i], rotg->vec);
+        if (xcproj < minproj)
+        {
+            minproj = xcproj;
+            *firstindex = i;
+        }
+        if (xcproj > maxproj)
+        {
+            maxproj = xcproj;
+            *lastindex = i;
+        }
+    }
+}
+
+
+/* Allocate memory for the slabs */
+static void allocate_slabs(
+        t_rotgrp  *rotg, 
+        FILE      *fplog, 
+        int       g, 
+        gmx_bool  bVerbose,
+        t_commrec *cr)
+{
+    gmx_enfrotgrp_t erg;      /* Pointer to enforced rotation group data */
+    int i, nslabs;
+    
+    
+    erg=rotg->enfrotgrp;
+    
+    /* More slabs than are defined for the reference are never needed */
+    nslabs = erg->slab_last_ref - erg->slab_first_ref + 1;
+    
+    /* Remember how many we allocated */
+    erg->nslabs_alloc = nslabs;
+
+    if (MASTER(cr) && bVerbose)
+        fprintf(fplog, "%s allocating memory to store data for %d slabs (rotation group %d).\n",
+                RotStr, nslabs,g);
+    snew(erg->slab_center     , nslabs);
+    snew(erg->slab_center_ref , nslabs);
+    snew(erg->slab_weights    , nslabs);
+    snew(erg->slab_torque_v   , nslabs);
+    snew(erg->slab_data       , nslabs);
+    snew(erg->gn_atom         , nslabs);
+    snew(erg->gn_slabind      , nslabs);
+    snew(erg->slab_innersumvec, nslabs);
+    for (i=0; i<nslabs; i++)
+    {
+        snew(erg->slab_data[i].x     , rotg->nat);
+        snew(erg->slab_data[i].ref   , rotg->nat);
+        snew(erg->slab_data[i].weight, rotg->nat);
+    }
+    snew(erg->xc_ref_sorted, rotg->nat);
+    snew(erg->xc_sortind   , rotg->nat);
+    snew(erg->firstatom    , nslabs);
+    snew(erg->lastatom     , nslabs);
+}
+
+
+/* From the extreme coordinates of the reference group, determine the first 
+ * and last slab of the reference. We can never have more slabs in the real
+ * simulation than calculated here for the reference.
+ */
+static void get_firstlast_slab_ref(t_rotgrp *rotg, real mc[], int ref_firstindex, int ref_lastindex)
+{
+    gmx_enfrotgrp_t erg;      /* Pointer to enforced rotation group data */
+    int first,last,firststart;
+    rvec dummy;
+
+    
+    erg=rotg->enfrotgrp;
+    first = get_first_slab(rotg, erg->max_beta, rotg->x_ref[ref_firstindex]);
+    last  = get_last_slab( rotg, erg->max_beta, rotg->x_ref[ref_lastindex ]);
+    firststart = first;
+
+    while (get_slab_weight(first, rotg, rotg->x_ref, mc, &dummy) > WEIGHT_MIN)
+    {
+        first--;
+    }
+    erg->slab_first_ref = first+1;
+    while (get_slab_weight(last, rotg, rotg->x_ref, mc, &dummy) > WEIGHT_MIN)
+    {
+        last++;
+    }
+    erg->slab_last_ref  = last-1;
+    
+    erg->slab_buffer = firststart - erg->slab_first_ref;
+}
+
+
+
+static void init_rot_group(FILE *fplog,t_commrec *cr,int g,t_rotgrp *rotg,
+        rvec *x,gmx_mtop_t *mtop,gmx_bool bVerbose,FILE *out_slabs, gmx_bool bOutputCenters)
+{
+    int i,ii;
+    rvec        coord,*xdum;
+    gmx_bool    bFlex,bColl;
+    t_atom      *atom;
+    gmx_enfrotgrp_t erg;      /* Pointer to enforced rotation group data */
+    int         ref_firstindex, ref_lastindex;
+    real        mass,totalmass;
+    
+
+    /* Do we have a flexible axis? */
+    bFlex = ISFLEX(rotg);
+    /* Do we use a global set of coordinates? */
+    bColl = ISCOLL(rotg);
+
+    erg=rotg->enfrotgrp;
+    
+    /* Allocate space for collective coordinates if needed */
+    if (bColl)
+    {
+        snew(erg->xc        , rotg->nat);
+        snew(erg->xc_shifts , rotg->nat);
+        snew(erg->xc_eshifts, rotg->nat);
+
+        /* Save the original (whole) set of positions such that later the
+         * molecule can always be made whole again */
+        snew(erg->xc_old    , rotg->nat);        
+        if (MASTER(cr))
+        {
+            for (i=0; i<rotg->nat; i++)
+            {
+                ii = rotg->ind[i];
+                copy_rvec(x[ii], erg->xc_old[i]);
+            }
+        }
+#ifdef GMX_MPI
+        if (PAR(cr))
+            gmx_bcast(rotg->nat*sizeof(erg->xc_old[0]),erg->xc_old, cr);
+#endif
+
+        if (rotg->eFittype == erotgFitNORM)
+        {
+            snew(erg->xc_ref_length, rotg->nat); /* in case fit type NORM is chosen */
+            snew(erg->xc_norm      , rotg->nat);
+        }
+    }
+    else
+    {
+        snew(erg->xr_loc   , rotg->nat);
+        snew(erg->x_loc_pbc, rotg->nat);
+    }
+    
+    snew(erg->f_rot_loc , rotg->nat);
+    snew(erg->xc_ref_ind, rotg->nat);
+    
+    /* xc_ref_ind needs to be set to identity in the serial case */
+    if (!PAR(cr))
+        for (i=0; i<rotg->nat; i++)
+            erg->xc_ref_ind[i] = i;
+
+    /* Copy the masses so that the center can be determined. For all types of
+     * enforced rotation, we store the masses in the erg->mc array. */
+    snew(erg->mc, rotg->nat);
+    if (bFlex)
+        snew(erg->mc_sorted, rotg->nat);
+    if (!bColl)
+        snew(erg->m_loc, rotg->nat);
+    totalmass=0.0;
+    for (i=0; i<rotg->nat; i++)
+    {
+        if (rotg->bMassW)
+        {
+            gmx_mtop_atomnr_to_atom(mtop,rotg->ind[i],&atom);
+            mass=atom->m;
+        }
+        else
+        {
+            mass=1.0;
+        }
+        erg->mc[i] = mass;
+        totalmass += mass;
+    }
+    erg->invmass = 1.0/totalmass;
+    
+    /* Set xc_ref_center for any rotation potential */
+    if ((rotg->eType==erotgISO) || (rotg->eType==erotgPM) || (rotg->eType==erotgRM) || (rotg->eType==erotgRM2))
+    {
+        /* Set the pivot point for the fixed, stationary-axis potentials. This
+         * won't change during the simulation */
+        copy_rvec(rotg->pivot, erg->xc_ref_center);
+        copy_rvec(rotg->pivot, erg->xc_center    );
+    }
+    else
+    {
+        /* Center of the reference positions */
+        get_center(rotg->x_ref, erg->mc, rotg->nat, erg->xc_ref_center);
+
+        /* Center of the actual positions */
+        if (MASTER(cr))
+        {
+            snew(xdum, rotg->nat);
+            for (i=0; i<rotg->nat; i++)
+            {
+                ii = rotg->ind[i];
+                copy_rvec(x[ii], xdum[i]);
+            }
+            get_center(xdum, erg->mc, rotg->nat, erg->xc_center);
+            sfree(xdum);
+        }
+#ifdef GMX_MPI
+        if (PAR(cr))
+            gmx_bcast(sizeof(erg->xc_center), erg->xc_center, cr);
+#endif
+    }
+
+    if ( (rotg->eType != erotgFLEX) && (rotg->eType != erotgFLEX2) )
+    {
+        /* Put the reference positions into origin: */
+        for (i=0; i<rotg->nat; i++)
+            rvec_dec(rotg->x_ref[i], erg->xc_ref_center);
+    }
+
+    /* Enforced rotation with flexible axis */
+    if (bFlex)
+    {
+        /* Calculate maximum beta value from minimum gaussian (performance opt.) */
+        erg->max_beta = calc_beta_max(rotg->min_gaussian, rotg->slab_dist);
+
+        /* Determine the smallest and largest coordinate with respect to the rotation vector */
+        get_firstlast_atom_ref(rotg, &ref_firstindex, &ref_lastindex);
+        
+        /* From the extreme coordinates of the reference group, determine the first 
+         * and last slab of the reference. */
+        get_firstlast_slab_ref(rotg, erg->mc, ref_firstindex, ref_lastindex);
+                
+        /* Allocate memory for the slabs */
+        allocate_slabs(rotg, fplog, g, bVerbose, cr);
+
+        /* Flexible rotation: determine the reference centers for the rest of the simulation */
+        erg->slab_first = erg->slab_first_ref;
+        erg->slab_last = erg->slab_last_ref;
+        get_slab_centers(rotg,rotg->x_ref,erg->mc,cr,g,-1,out_slabs,bOutputCenters,TRUE);
+
+        /* Length of each x_rotref vector from center (needed if fit routine NORM is chosen): */
+        if (rotg->eFittype == erotgFitNORM)
+        {
+            for (i=0; i<rotg->nat; i++)
+            {
+                rvec_sub(rotg->x_ref[i], erg->xc_ref_center, coord);
+                erg->xc_ref_length[i] = norm(coord);
+            }
+        }
+    }
+}
+
+
+extern void dd_make_local_rotation_groups(gmx_domdec_t *dd,t_rot *rot)
+{
+    gmx_ga2la_t ga2la;
+    int g;
+    t_rotgrp *rotg;
+    gmx_enfrotgrp_t erg;      /* Pointer to enforced rotation group data */
+    
+    ga2la = dd->ga2la;
+
+    for(g=0; g<rot->ngrp; g++)
+    {
+        rotg = &rot->grp[g];
+        erg  = rotg->enfrotgrp;
+
+
+        dd_make_local_group_indices(ga2la,rotg->nat,rotg->ind,
+                &erg->nat_loc,&erg->ind_loc,&erg->nalloc_loc,erg->xc_ref_ind);
+    }
+}
+
+
+extern void init_rot(FILE *fplog,t_inputrec *ir,int nfile,const t_filenm fnm[],
+        t_commrec *cr, rvec *x, matrix box, gmx_mtop_t *mtop, const output_env_t oenv,
+        gmx_bool bVerbose, unsigned long Flags)
+{
+    t_rot    *rot;
+    t_rotgrp *rotg;
+    int      g;
+    int      nat_max=0;     /* Size of biggest rotation group */
+    gmx_enfrot_t er;        /* Pointer to the enforced rotation buffer variables */    
+    gmx_enfrotgrp_t erg;    /* Pointer to enforced rotation group data */
+    rvec     *x_pbc=NULL;   /* Space for the pbc-correct atom positions */
+
+
+    if ( (PAR(cr)) && !DOMAINDECOMP(cr) )
+        gmx_fatal(FARGS, "Enforced rotation is only implemented for domain decomposition!");
+
+    if ( MASTER(cr) && bVerbose)
+        fprintf(stdout, "%s Initializing ...\n", RotStr);
+
+
+    rot = ir->rot;
+    snew(rot->enfrot, 1);
+    er = rot->enfrot;
+    er->Flags = Flags;
+
+    /* When appending, skip first output to avoid duplicate entries in the data files */
+    if (er->Flags & MD_APPENDFILES)
+        er->bOut = FALSE;
+    else
+        er->bOut = TRUE;
+    
+    /* Output every step for reruns */
+    if (er->Flags & MD_RERUN)
+    {
+        if (fplog)
+            fprintf(fplog, "%s rerun - will write rotation output every available step.\n", RotStr);
+        rot->nstrout = 1;
+        rot->nstsout = 1;
+    }
+
+    er->out_slabs = NULL;
+    if ( MASTER(cr) && HaveFlexibleGroups(rot) )
+        er->out_slabs = open_slab_out(opt2fn("-rs",nfile,fnm), rot, oenv);
+
+    if (MASTER(cr))
+    {
+        /* Remove pbc, make molecule whole.
+         * When ir->bContinuation=TRUE this has already been done, but ok. */
+        snew(x_pbc,mtop->natoms);
+        m_rveccopy(mtop->natoms,x,x_pbc);
+        do_pbc_first_mtop(NULL,ir->ePBC,box,mtop,x_pbc);
+    }
+
+    for (g=0; g<rot->ngrp; g++)
+    {
+        rotg = &rot->grp[g];
+
+        if (fplog)
+            fprintf(fplog,"%s group %d type '%s'\n", RotStr, g, erotg_names[rotg->eType]);
+        
+        if (rotg->nat > 0)
+        {
+            /* Allocate space for the rotation group's data: */
+            snew(rotg->enfrotgrp, 1);
+            erg  = rotg->enfrotgrp;
+
+            nat_max=max(nat_max, rotg->nat);
+            
+            if (PAR(cr))
+            {
+                erg->nat_loc    = 0;
+                erg->nalloc_loc = 0;
+                erg->ind_loc    = NULL;
+            }
+            else
+            {
+                erg->nat_loc = rotg->nat;
+                erg->ind_loc = rotg->ind;
+            }
+            init_rot_group(fplog,cr,g,rotg,x_pbc,mtop,bVerbose,er->out_slabs,
+                           !(er->Flags & MD_APPENDFILES) ); /* Do not output the reference centers
+                                                             * again if we are appending */
+        }
+    }
+    
+    /* Allocate space for enforced rotation buffer variables */
+    er->bufsize = nat_max;
+    snew(er->data, nat_max);
+    snew(er->xbuf, nat_max);
+    snew(er->mbuf, nat_max);
+
+    /* Buffers for MPI reducing torques, angles, weights (for each group), and V */
+    er->mpi_bufsize = 4*rot->ngrp; /* To start with */
+    snew(er->mpi_inbuf , er->mpi_bufsize);
+    snew(er->mpi_outbuf, er->mpi_bufsize);
+
+    /* Only do I/O on the MASTER */
+    er->out_angles  = NULL;
+    er->out_rot     = NULL;
+    er->out_torque  = NULL;
+    if (MASTER(cr))
+    {
+        er->out_rot = open_rot_out(opt2fn("-ro",nfile,fnm), rot, oenv);
+        if ( HaveFlexibleGroups(rot) )
+        {
+            if (rot->nstrout > 0)
+                er->out_angles  = open_angles_out(opt2fn("-ra",nfile,fnm), rot, oenv);
+            if (rot->nstsout > 0)
+                er->out_torque  = open_torque_out(opt2fn("-rt",nfile,fnm), rot, oenv);
+        }
+        sfree(x_pbc);
+    }
+}
+
+
+extern void finish_rot(FILE *fplog,t_rot *rot)
+{
+    gmx_enfrot_t er;        /* Pointer to the enforced rotation buffer variables */    
+
+    
+    er=rot->enfrot;
+    if (er->out_rot)
+        gmx_fio_fclose(er->out_rot);
+    if (er->out_slabs)
+        gmx_fio_fclose(er->out_slabs);
+    if (er->out_angles)
+        gmx_fio_fclose(er->out_angles);
+    if (er->out_torque)
+        gmx_fio_fclose(er->out_torque);
+}
+
+
+/* Rotate the local reference positions and store them in
+ * erg->xr_loc[0...(nat_loc-1)]
+ *
+ * Note that we already subtracted u or y_c from the reference positions
+ * in init_rot_group().
+ */
+static void rotate_local_reference(t_rotgrp *rotg)
+{
+    gmx_enfrotgrp_t erg;
+    int i,ii;
+
+    
+    erg=rotg->enfrotgrp;
+    
+    for (i=0; i<erg->nat_loc; i++)
+    {
+        /* Index of this rotation group atom with respect to the whole rotation group */
+        ii = erg->xc_ref_ind[i];
+        /* Rotate */
+        mvmul(erg->rotmat, rotg->x_ref[ii], erg->xr_loc[i]);
+    }
+}
+
+
+/* Select the PBC representation for each local x position and store that
+ * for later usage. We assume the right PBC image of an x is the one nearest to
+ * its rotated reference */
+static void choose_pbc_image(rvec x[], t_rotgrp *rotg, matrix box, int npbcdim)
+{
+    int d,i,ii,m;
+    gmx_enfrotgrp_t erg;       /* Pointer to enforced rotation group data */
+    rvec xref,xcurr,dx;
+    ivec shift;
+
+
+    erg=rotg->enfrotgrp;
+    
+    for (i=0; i<erg->nat_loc; i++)
+    {
+        clear_ivec(shift);
+        
+        /* Index of a rotation group atom  */
+        ii = erg->ind_loc[i];
+
+        /* Get the reference position. The pivot was already
+         * subtracted in init_rot_group() from the reference positions. Also,
+         * the reference positions have already been rotated in
+         * rotate_local_reference() */
+        copy_rvec(erg->xr_loc[i], xref);
+        
+        /* Subtract the (old) center from the current positions
+         * (just to determine the shifts!) */
+        rvec_sub(x[ii], erg->xc_center, xcurr);
+        
+        /* Shortest PBC distance between the atom and its reference */
+        rvec_sub(xcurr, xref, dx);
+        
+        /* Determine the shift for this atom */
+        for(m=npbcdim-1; m>=0; m--)
+        {
+            while (dx[m] < -0.5*box[m][m])
+            {
+                for(d=0; d<DIM; d++)
+                    dx[d] += box[m][d];
+                shift[m]++;
+            }
+            while (dx[m] >= 0.5*box[m][m])
+            {
+                for(d=0; d<DIM; d++)
+                    dx[d] -= box[m][d];
+                shift[m]--;
+            }
+        }
+        
+        /* Apply the shift to the current atom */
+        copy_rvec(x[ii], erg->x_loc_pbc[i]);
+        shift_single_coord(box, erg->x_loc_pbc[i], shift); 
+    }
+}
+
+
+extern void do_rotation(
+        t_commrec *cr,
+        t_inputrec *ir,
+        matrix box,
+        rvec x[],
+        real t,
+        gmx_large_int_t step,
+        gmx_wallcycle_t wcycle,
+        gmx_bool bNS)
+{
+    int      g,i,ii;
+    t_rot    *rot;
+    t_rotgrp *rotg;
+    gmx_bool outstep_slab, outstep_rot;
+    gmx_bool bFlex,bColl;
+    float    cycles_rot;
+    gmx_enfrot_t er;     /* Pointer to the enforced rotation buffer variables */
+    gmx_enfrotgrp_t erg; /* Pointer to enforced rotation group data           */
+    rvec     transvec;
+#ifdef TAKETIME
+    double t0;
+#endif
+    
+    
+    rot=ir->rot;
+    er=rot->enfrot;
+    
+    /* When to output in main rotation output file */
+    outstep_rot  = do_per_step(step, rot->nstrout) && er->bOut;
+    /* When to output per-slab data */
+    outstep_slab = do_per_step(step, rot->nstsout) && er->bOut;
+
+    /* Output time into rotation output file */
+    if (outstep_rot && MASTER(cr))
+        fprintf(er->out_rot, "%12.3e",t);
+
+    /**************************************************************************/
+    /* First do ALL the communication! */
+    for(g=0; g<rot->ngrp; g++)
+    {
+        rotg = &rot->grp[g];
+        erg=rotg->enfrotgrp;
+
+        /* Do we have a flexible axis? */
+        bFlex = ISFLEX(rotg);
+        /* Do we use a collective (global) set of coordinates? */
+        bColl = ISCOLL(rotg);
+
+        /* Calculate the rotation matrix for this angle: */
+        erg->degangle = rotg->rate * t;
+        calc_rotmat(rotg->vec,erg->degangle,erg->rotmat);
+
+        if (bColl)
+        {
+            /* Transfer the rotation group's positions such that every node has
+             * all of them. Every node contributes its local positions x and stores
+             * it in the collective erg->xc array. */
+            communicate_group_positions(cr,erg->xc, erg->xc_shifts, erg->xc_eshifts, bNS,
+                    x, rotg->nat, erg->nat_loc, erg->ind_loc, erg->xc_ref_ind, erg->xc_old, box);
+        }
+        else
+        {
+            /* Fill the local masses array;
+             * this array changes in DD/neighborsearching steps */
+            if (bNS)
+            {
+                for (i=0; i<erg->nat_loc; i++)
+                {
+                    /* Index of local atom w.r.t. the collective rotation group */
+                    ii = erg->xc_ref_ind[i];
+                    erg->m_loc[i] = erg->mc[ii];
+                }
+            }
+
+            /* Calculate Omega*(y_i-y_c) for the local positions */
+            rotate_local_reference(rotg);
+
+            /* Choose the nearest PBC images of the group atoms with respect
+             * to the rotated reference positions */
+            choose_pbc_image(x, rotg, box, 3);
+
+            /* Get the center of the rotation group */
+            if ( (rotg->eType==erotgISOPF) || (rotg->eType==erotgPMPF) )
+                get_center_comm(cr, erg->x_loc_pbc, erg->m_loc, erg->nat_loc, rotg->nat, erg->xc_center);
+        }
+
+    } /* End of loop over rotation groups */
+
+    /**************************************************************************/
+    /* Done communicating, we can start to count cycles now ... */
+    wallcycle_start(wcycle, ewcROT);
+    GMX_MPE_LOG(ev_rotcycles_start);
+
+#ifdef TAKETIME
+    t0 = MPI_Wtime();
+#endif
+
+    for(g=0; g<rot->ngrp; g++)
+    {
+        rotg = &rot->grp[g];
+        erg=rotg->enfrotgrp;
+
+        bFlex = ISFLEX(rotg);
+        bColl = ISCOLL(rotg);
+
+        if (outstep_rot && MASTER(cr))
+            fprintf(er->out_rot, "%12.4f", erg->degangle);
+
+        /* Clear values from last time step */
+        erg->V        = 0.0;
+        erg->torque_v = 0.0;
+        erg->angle_v  = 0.0;
+        erg->weight_v = 0.0;
+
+        switch(rotg->eType)
+        {
+            case erotgISO:
+            case erotgISOPF:
+            case erotgPM:
+            case erotgPMPF:
+                do_fixed(cr,rotg,x,box,t,step,outstep_rot);
+                break;
+            case erotgRM:
+                do_radial_motion(cr,rotg,x,box,t,step,outstep_rot);
+                break;
+            case erotgRMPF:
+                do_radial_motion_pf(cr,rotg,x,box,t,step,outstep_rot);
+                break;
+            case erotgRM2:
+            case erotgRM2PF:
+                do_radial_motion2(cr,rotg,x,box,t,step,outstep_rot);
+                break;
+            case erotgFLEXT:
+            case erotgFLEX2T:
+                /* Subtract the center of the rotation group from the collective positions array
+                 * Also store the center in erg->xc_center since it needs to be subtracted
+                 * in the low level routines from the local coordinates as well */
+                get_center(erg->xc, erg->mc, rotg->nat, erg->xc_center);
+                svmul(-1.0, erg->xc_center, transvec);
+                translate_x(erg->xc, rotg->nat, transvec);
+                do_flexible(cr,er,rotg,g,x,box,t,step,outstep_rot,outstep_slab);
+                break;
+            case erotgFLEX:
+            case erotgFLEX2:
+                /* Do NOT subtract the center of mass in the low level routines! */
+                clear_rvec(erg->xc_center);
+                do_flexible(cr,er,rotg,g,x,box,t,step,outstep_rot,outstep_slab);
+                break;
+            default:
+                gmx_fatal(FARGS, "No such rotation potential.");
+                break;
+        }
+    }
+
+#ifdef TAKETIME
+    if (MASTER(cr))
+        fprintf(stderr, "%s calculation (step %d) took %g seconds.\n", RotStr, step, MPI_Wtime()-t0);
+#endif
+
+    /* Stop the cycle counter and add to the force cycles for load balancing */
+    cycles_rot = wallcycle_stop(wcycle,ewcROT);
+    if (DOMAINDECOMP(cr) && wcycle)
+        dd_cycles_add(cr->dd,cycles_rot,ddCyclF);
+    GMX_MPE_LOG(ev_rotcycles_finish);
+}
similarity index 100%
rename from src/mdlib/qmmm.c
rename to src/gromacs/mdlib/qmmm.c
diff --git a/src/gromacs/mdlib/sim_util.c b/src/gromacs/mdlib/sim_util.c
new file mode 100644 (file)
index 0000000..5184758
--- /dev/null
@@ -0,0 +1,1550 @@
+/* -*- 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
+ * 
+ *                        VERSION 3.2.0
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * 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.
+
+ * 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:
+ * GROwing Monsters And Cloning Shrimps
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef GMX_CRAY_XT3
+#include<catamount/dclock.h>
+#endif
+
+
+#include <stdio.h>
+#include <time.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#include <math.h>
+#include "typedefs.h"
+#include "string2.h"
+#include "gmxfio.h"
+#include "smalloc.h"
+#include "names.h"
+#include "confio.h"
+#include "mvdata.h"
+#include "txtdump.h"
+#include "pbc.h"
+#include "chargegroup.h"
+#include "vec.h"
+#include "time.h"
+#include "nrnb.h"
+#include "mshift.h"
+#include "mdrun.h"
+#include "update.h"
+#include "physics.h"
+#include "main.h"
+#include "mdatoms.h"
+#include "force.h"
+#include "bondf.h"
+#include "pme.h"
+#include "pppm.h"
+#include "disre.h"
+#include "orires.h"
+#include "network.h"
+#include "calcmu.h"
+#include "constr.h"
+#include "xvgr.h"
+#include "trnio.h"
+#include "xtcio.h"
+#include "copyrite.h"
+#include "pull_rotation.h"
+#include "mpelogging.h"
+#include "domdec.h"
+#include "partdec.h"
+#include "gmx_wallcycle.h"
+#include "genborn.h"
+
+#ifdef GMX_LIB_MPI
+#include <mpi.h>
+#endif
+#ifdef GMX_THREADS
+#include "tmpi.h"
+#endif
+
+#include "qmmm.h"
+
+#if 0
+typedef struct gmx_timeprint {
+    
+} t_gmx_timeprint;
+#endif
+
+/* Portable version of ctime_r implemented in src/gmxlib/string2.c, but we do not want it declared in public installed headers */
+char *
+gmx_ctime_r(const time_t *clock,char *buf, int n);
+
+
+double
+gmx_gettime()
+{
+#ifdef HAVE_GETTIMEOFDAY
+       struct timeval t;
+       struct timezone tz = { 0,0 };
+       double seconds;
+       
+       gettimeofday(&t,&tz);
+       
+       seconds = (double) t.tv_sec + 1e-6*(double)t.tv_usec;
+       
+       return seconds;
+#else
+       double  seconds;
+       
+       seconds = time(NULL);
+       
+       return seconds;
+#endif
+}
+
+
+#define difftime(end,start) ((double)(end)-(double)(start))
+
+void print_time(FILE *out,gmx_runtime_t *runtime,gmx_large_int_t step,   
+                t_inputrec *ir, t_commrec *cr)
+{
+    time_t finish;
+    char   timebuf[STRLEN];
+    double dt;
+    char buf[48];
+    
+#ifndef GMX_THREADS
+    if (!PAR(cr))
+#endif
+    {
+        fprintf(out,"\r");
+    }
+    fprintf(out,"step %s",gmx_step_str(step,buf));
+    if ((step >= ir->nstlist))
+    {
+        if ((ir->nstlist == 0) || ((step % ir->nstlist) == 0))
+        {
+            /* We have done a full cycle let's update time_per_step */
+            runtime->last = gmx_gettime();
+            dt = difftime(runtime->last,runtime->real);
+            runtime->time_per_step = dt/(step - ir->init_step + 1);
+        }
+        dt = (ir->nsteps + ir->init_step - step)*runtime->time_per_step;
+        
+        if (ir->nsteps >= 0)
+        {
+            if (dt >= 300)
+            {    
+                finish = (time_t) (runtime->last + dt);
+                gmx_ctime_r(&finish,timebuf,STRLEN);
+                sprintf(buf,"%s",timebuf);
+                buf[strlen(buf)-1]='\0';
+                fprintf(out,", will finish %s",buf);
+            }
+            else
+                fprintf(out,", remaining runtime: %5d s          ",(int)dt);
+        }
+        else
+        {
+            fprintf(out," performance: %.1f ns/day    ",
+                    ir->delta_t/1000*24*60*60/runtime->time_per_step);
+        }
+    }
+#ifndef GMX_THREADS
+    if (PAR(cr))
+    {
+        fprintf(out,"\n");
+    }
+#endif
+
+    fflush(out);
+}
+
+#ifdef NO_CLOCK 
+#define clock() -1
+#endif
+
+static double set_proctime(gmx_runtime_t *runtime)
+{
+    double diff;
+#ifdef GMX_CRAY_XT3
+    double prev;
+
+    prev = runtime->proc;
+    runtime->proc = dclock();
+    
+    diff = runtime->proc - prev;
+#else
+    clock_t prev;
+
+    prev = runtime->proc;
+    runtime->proc = clock();
+
+    diff = (double)(runtime->proc - prev)/(double)CLOCKS_PER_SEC;
+#endif
+    if (diff < 0)
+    {
+        /* The counter has probably looped, ignore this data */
+        diff = 0;
+    }
+
+    return diff;
+}
+
+void runtime_start(gmx_runtime_t *runtime)
+{
+    runtime->real = gmx_gettime();
+    runtime->proc          = 0;
+    set_proctime(runtime);
+    runtime->realtime      = 0;
+    runtime->proctime      = 0;
+    runtime->last          = 0;
+    runtime->time_per_step = 0;
+}
+
+void runtime_end(gmx_runtime_t *runtime)
+{
+    double now;
+    
+    now = gmx_gettime();
+    
+    runtime->proctime += set_proctime(runtime);
+    runtime->realtime  = now - runtime->real;
+    runtime->real      = now;
+}
+
+void runtime_upd_proc(gmx_runtime_t *runtime)
+{
+    runtime->proctime += set_proctime(runtime);
+}
+
+void print_date_and_time(FILE *fplog,int nodeid,const char *title,
+                         const gmx_runtime_t *runtime)
+{
+    int i;
+    char timebuf[STRLEN];
+    char time_string[STRLEN];
+    time_t tmptime;
+
+    if (fplog)
+    {
+        if (runtime != NULL)
+        {
+            tmptime = (time_t) runtime->real;
+            gmx_ctime_r(&tmptime,timebuf,STRLEN);
+        }
+        else
+        {
+            tmptime = (time_t) gmx_gettime();
+            gmx_ctime_r(&tmptime,timebuf,STRLEN);
+        }
+        for(i=0; timebuf[i]>=' '; i++)
+        {
+            time_string[i]=timebuf[i];
+        }
+        time_string[i]='\0';
+
+        fprintf(fplog,"%s on node %d %s\n",title,nodeid,time_string);
+    }
+}
+
+static void sum_forces(int start,int end,rvec f[],rvec flr[])
+{
+  int i;
+  
+  if (gmx_debug_at) {
+    pr_rvecs(debug,0,"fsr",f+start,end-start);
+    pr_rvecs(debug,0,"flr",flr+start,end-start);
+  }
+  for(i=start; (i<end); i++)
+    rvec_inc(f[i],flr[i]);
+}
+
+/* 
+ * calc_f_el calculates forces due to an electric field.
+ *
+ * force is kJ mol^-1 nm^-1 = e * kJ mol^-1 nm^-1 / e 
+ *
+ * Et[] contains the parameters for the time dependent 
+ * part of the field (not yet used). 
+ * Ex[] contains the parameters for
+ * the spatial dependent part of the field. You can have cool periodic
+ * fields in principle, but only a constant field is supported
+ * now. 
+ * The function should return the energy due to the electric field
+ * (if any) but for now returns 0.
+ *
+ * WARNING:
+ * There can be problems with the virial.
+ * Since the field is not self-consistent this is unavoidable.
+ * For neutral molecules the virial is correct within this approximation.
+ * For neutral systems with many charged molecules the error is small.
+ * But for systems with a net charge or a few charged molecules
+ * the error can be significant when the field is high.
+ * Solution: implement a self-consitent electric field into PME.
+ */
+static void calc_f_el(FILE *fp,int  start,int homenr,
+                      real charge[],rvec x[],rvec f[],
+                      t_cosines Ex[],t_cosines Et[],double t)
+{
+    rvec Ext;
+    real t0;
+    int  i,m;
+    
+    for(m=0; (m<DIM); m++)
+    {
+        if (Et[m].n > 0)
+        {
+            if (Et[m].n == 3)
+            {
+                t0 = Et[m].a[1];
+                Ext[m] = cos(Et[m].a[0]*(t-t0))*exp(-sqr(t-t0)/(2.0*sqr(Et[m].a[2])));
+            }
+            else
+            {
+                Ext[m] = cos(Et[m].a[0]*t);
+            }
+        }
+        else
+        {
+            Ext[m] = 1.0;
+        }
+        if (Ex[m].n > 0)
+        {
+            /* Convert the field strength from V/nm to MD-units */
+            Ext[m] *= Ex[m].a[0]*FIELDFAC;
+            for(i=start; (i<start+homenr); i++)
+                f[i][m] += charge[i]*Ext[m];
+        }
+        else
+        {
+            Ext[m] = 0;
+        }
+    }
+    if (fp != NULL)
+    {
+        fprintf(fp,"%10g  %10g  %10g  %10g #FIELD\n",t,
+                Ext[XX]/FIELDFAC,Ext[YY]/FIELDFAC,Ext[ZZ]/FIELDFAC);
+    }
+}
+
+static void calc_virial(FILE *fplog,int start,int homenr,rvec x[],rvec f[],
+                       tensor vir_part,t_graph *graph,matrix box,
+                       t_nrnb *nrnb,const t_forcerec *fr,int ePBC)
+{
+  int i,j;
+  tensor virtest;
+
+  /* The short-range virial from surrounding boxes */
+  clear_mat(vir_part);
+  calc_vir(fplog,SHIFTS,fr->shift_vec,fr->fshift,vir_part,ePBC==epbcSCREW,box);
+  inc_nrnb(nrnb,eNR_VIRIAL,SHIFTS);
+  
+  /* Calculate partial virial, for local atoms only, based on short range. 
+   * Total virial is computed in global_stat, called from do_md 
+   */
+  f_calc_vir(fplog,start,start+homenr,x,f,vir_part,graph,box);
+  inc_nrnb(nrnb,eNR_VIRIAL,homenr);
+
+  /* Add position restraint contribution */
+  for(i=0; i<DIM; i++) {
+    vir_part[i][i] += fr->vir_diag_posres[i];
+  }
+
+  /* Add wall contribution */
+  for(i=0; i<DIM; i++) {
+    vir_part[i][ZZ] += fr->vir_wall_z[i];
+  }
+
+  if (debug)
+    pr_rvecs(debug,0,"vir_part",vir_part,DIM);
+}
+
+static void print_large_forces(FILE *fp,t_mdatoms *md,t_commrec *cr,
+                              gmx_large_int_t step,real pforce,rvec *x,rvec *f)
+{
+  int  i;
+  real pf2,fn2;
+  char buf[STEPSTRSIZE];
+
+  pf2 = sqr(pforce);
+  for(i=md->start; i<md->start+md->homenr; i++) {
+    fn2 = norm2(f[i]);
+    /* We also catch NAN, if the compiler does not optimize this away. */
+    if (fn2 >= pf2 || fn2 != fn2) {
+      fprintf(fp,"step %s  atom %6d  x %8.3f %8.3f %8.3f  force %12.5e\n",
+             gmx_step_str(step,buf),
+             ddglatnr(cr->dd,i),x[i][XX],x[i][YY],x[i][ZZ],sqrt(fn2));
+    }
+  }
+}
+
+void do_force(FILE *fplog,t_commrec *cr,
+              t_inputrec *inputrec,
+              gmx_large_int_t step,t_nrnb *nrnb,gmx_wallcycle_t wcycle,
+              gmx_localtop_t *top,
+              gmx_mtop_t *mtop,
+              gmx_groups_t *groups,
+              matrix box,rvec x[],history_t *hist,
+              rvec f[],
+              tensor vir_force,
+              t_mdatoms *mdatoms,
+              gmx_enerdata_t *enerd,t_fcdata *fcd,
+              real lambda,t_graph *graph,
+              t_forcerec *fr,gmx_vsite_t *vsite,rvec mu_tot,
+              double t,FILE *field,gmx_edsam_t ed,
+              gmx_bool bBornRadii,
+              int flags)
+{
+    int    cg0,cg1,i,j;
+    int    start,homenr;
+    double mu[2*DIM]; 
+    gmx_bool   bSepDVDL,bStateChanged,bNS,bFillGrid,bCalcCGCM,bBS;
+    gmx_bool   bDoLongRange,bDoForces,bSepLRF;
+    matrix boxs;
+    real   e,v,dvdl;
+    t_pbc  pbc;
+    float  cycles_ppdpme,cycles_pme,cycles_seppme,cycles_force;
+  
+    start  = mdatoms->start;
+    homenr = mdatoms->homenr;
+
+    bSepDVDL = (fr->bSepDVDL && do_per_step(step,inputrec->nstlog));
+
+    clear_mat(vir_force);
+
+    if (PARTDECOMP(cr))
+    {
+        pd_cg_range(cr,&cg0,&cg1);
+    }
+    else
+    {
+        cg0 = 0;
+        if (DOMAINDECOMP(cr))
+        {
+            cg1 = cr->dd->ncg_tot;
+        }
+        else
+        {
+            cg1 = top->cgs.nr;
+        }
+        if (fr->n_tpi > 0)
+        {
+            cg1--;
+        }
+    }
+
+    bStateChanged = (flags & GMX_FORCE_STATECHANGED);
+    bNS           = (flags & GMX_FORCE_NS) && (fr->bAllvsAll==FALSE); 
+    bFillGrid     = (bNS && bStateChanged);
+    bCalcCGCM     = (bFillGrid && !DOMAINDECOMP(cr));
+    bDoLongRange  = (fr->bTwinRange && bNS && (flags & GMX_FORCE_DOLR));
+    bDoForces     = (flags & GMX_FORCE_FORCES);
+    bSepLRF       = (bDoLongRange && bDoForces && (flags & GMX_FORCE_SEPLRF));
+
+    if (bStateChanged)
+    {
+        update_forcerec(fplog,fr,box);
+        
+        /* Calculate total (local) dipole moment in a temporary common array. 
+         * This makes it possible to sum them over nodes faster.
+         */
+        calc_mu(start,homenr,
+                x,mdatoms->chargeA,mdatoms->chargeB,mdatoms->nChargePerturbed,
+                mu,mu+DIM);
+    }
+  
+  if (fr->ePBC != epbcNONE) { 
+    /* Compute shift vectors every step,
+     * because of pressure coupling or box deformation!
+     */
+    if ((flags & GMX_FORCE_DYNAMICBOX) && bStateChanged)
+      calc_shifts(box,fr->shift_vec);
+    
+    if (bCalcCGCM) { 
+      put_charge_groups_in_box(fplog,cg0,cg1,fr->ePBC,box,
+                              &(top->cgs),x,fr->cg_cm);
+      inc_nrnb(nrnb,eNR_CGCM,homenr);
+      inc_nrnb(nrnb,eNR_RESETX,cg1-cg0);
+    } 
+    else if (EI_ENERGY_MINIMIZATION(inputrec->eI) && graph) {
+      unshift_self(graph,box,x);
+    }
+  } 
+  else if (bCalcCGCM) {
+    calc_cgcm(fplog,cg0,cg1,&(top->cgs),x,fr->cg_cm);
+    inc_nrnb(nrnb,eNR_CGCM,homenr);
+  }
+  
+  if (bCalcCGCM) {
+    if (PAR(cr)) {
+      move_cgcm(fplog,cr,fr->cg_cm);
+    }
+    if (gmx_debug_at)
+      pr_rvecs(debug,0,"cgcm",fr->cg_cm,top->cgs.nr);
+  }
+
+#ifdef GMX_MPI
+  if (!(cr->duty & DUTY_PME)) {
+    /* Send particle coordinates to the pme nodes.
+     * Since this is only implemented for domain decomposition
+     * and domain decomposition does not use the graph,
+     * we do not need to worry about shifting.
+     */    
+
+    wallcycle_start(wcycle,ewcPP_PMESENDX);
+    GMX_MPE_LOG(ev_send_coordinates_start);
+
+    bBS = (inputrec->nwall == 2);
+    if (bBS) {
+      copy_mat(box,boxs);
+      svmul(inputrec->wall_ewald_zfac,boxs[ZZ],boxs[ZZ]);
+    }
+
+    gmx_pme_send_x(cr,bBS ? boxs : box,x,
+                   mdatoms->nChargePerturbed,lambda,
+                   ( flags & GMX_FORCE_VIRIAL),step);
+
+    GMX_MPE_LOG(ev_send_coordinates_finish);
+    wallcycle_stop(wcycle,ewcPP_PMESENDX);
+  }
+#endif /* GMX_MPI */
+
+    /* Communicate coordinates and sum dipole if necessary */
+    if (PAR(cr))
+    {
+        wallcycle_start(wcycle,ewcMOVEX);
+        if (DOMAINDECOMP(cr))
+        {
+            dd_move_x(cr->dd,box,x);
+        }
+        else
+        {
+            move_x(fplog,cr,GMX_LEFT,GMX_RIGHT,x,nrnb);
+        }
+        /* When we don't need the total dipole we sum it in global_stat */
+        if (bStateChanged && NEED_MUTOT(*inputrec))
+        {
+            gmx_sumd(2*DIM,mu,cr);
+        }
+        wallcycle_stop(wcycle,ewcMOVEX);
+    }
+    if (bStateChanged)
+    {
+        for(i=0; i<2; i++)
+        {
+            for(j=0;j<DIM;j++)
+            {
+                fr->mu_tot[i][j] = mu[i*DIM + j];
+            }
+        }
+    }
+    if (fr->efep == efepNO)
+    {
+        copy_rvec(fr->mu_tot[0],mu_tot);
+    }
+    else
+    {
+        for(j=0; j<DIM; j++)
+        {
+            mu_tot[j] =
+                (1.0 - lambda)*fr->mu_tot[0][j] + lambda*fr->mu_tot[1][j];
+        }
+    }
+
+    /* Reset energies */
+    reset_enerdata(&(inputrec->opts),fr,bNS,enerd,MASTER(cr));
+    clear_rvecs(SHIFTS,fr->fshift);
+
+    if (bNS)
+    {
+        wallcycle_start(wcycle,ewcNS);
+        
+        if (graph && bStateChanged)
+        {
+            /* Calculate intramolecular shift vectors to make molecules whole */
+            mk_mshift(fplog,graph,fr->ePBC,box,x);
+        }
+
+        /* Reset long range forces if necessary */
+        if (fr->bTwinRange)
+        {
+            /* Reset the (long-range) forces if necessary */
+            clear_rvecs(fr->natoms_force_constr,bSepLRF ? fr->f_twin : f);
+        }
+
+        /* Do the actual neighbour searching and if twin range electrostatics
+         * also do the calculation of long range forces and energies.
+         */
+        dvdl = 0; 
+        ns(fplog,fr,x,box,
+           groups,&(inputrec->opts),top,mdatoms,
+           cr,nrnb,lambda,&dvdl,&enerd->grpp,bFillGrid,
+           bDoLongRange,bDoForces,bSepLRF ? fr->f_twin : f);
+        if (bSepDVDL)
+        {
+            fprintf(fplog,sepdvdlformat,"LR non-bonded",0.0,dvdl);
+        }
+        enerd->dvdl_lin += dvdl;
+        
+        wallcycle_stop(wcycle,ewcNS);
+    }
+       
+    if (inputrec->implicit_solvent && bNS) 
+    {
+        make_gb_nblist(cr,inputrec->gb_algorithm,inputrec->rlist,
+                       x,box,fr,&top->idef,graph,fr->born);
+    }
+       
+    if (DOMAINDECOMP(cr))
+    {
+        if (!(cr->duty & DUTY_PME))
+        {
+            wallcycle_start(wcycle,ewcPPDURINGPME);
+            dd_force_flop_start(cr->dd,nrnb);
+        }
+    }
+    
+    if (inputrec->bRot)
+    {
+        /* Enforced rotation has its own cycle counter that starts after the collective
+         * coordinates have been communicated. It is added to ddCyclF */
+        do_rotation(cr,inputrec,box,x,t,step,wcycle,bNS);
+    }
+
+    /* Start the force cycle counter.
+     * This counter is stopped in do_forcelow_level.
+     * No parallel communication should occur while this counter is running,
+     * since that will interfere with the dynamic load balancing.
+     */
+    wallcycle_start(wcycle,ewcFORCE);
+    GMX_MPE_LOG(ev_forcecycles_start);
+
+    if (bDoForces)
+    {
+        /* Reset forces for which the virial is calculated separately:
+         * PME/Ewald forces if necessary */
+        if (fr->bF_NoVirSum) 
+        {
+            if (flags & GMX_FORCE_VIRIAL)
+            {
+                fr->f_novirsum = fr->f_novirsum_alloc;
+                GMX_BARRIER(cr->mpi_comm_mygroup);
+                if (fr->bDomDec)
+                {
+                    clear_rvecs(fr->f_novirsum_n,fr->f_novirsum);
+                }
+                else
+                {
+                    clear_rvecs(homenr,fr->f_novirsum+start);
+                }
+                GMX_BARRIER(cr->mpi_comm_mygroup);
+            }
+            else
+            {
+                /* We are not calculating the pressure so we do not need
+                 * a separate array for forces that do not contribute
+                 * to the pressure.
+                 */
+                fr->f_novirsum = f;
+            }
+        }
+
+        if (bSepLRF)
+        {
+            /* Add the long range forces to the short range forces */
+            for(i=0; i<fr->natoms_force_constr; i++)
+            {
+                copy_rvec(fr->f_twin[i],f[i]);
+            }
+        }
+        else if (!(fr->bTwinRange && bNS))
+        {
+            /* Clear the short-range forces */
+            clear_rvecs(fr->natoms_force_constr,f);
+        }
+
+        clear_rvec(fr->vir_diag_posres);
+
+        GMX_BARRIER(cr->mpi_comm_mygroup);
+    }
+    if (inputrec->ePull == epullCONSTRAINT)
+    {
+        clear_pull_forces(inputrec->pull);
+    }
+
+    /* update QMMMrec, if necessary */
+    if(fr->bQMMM)
+    {
+        update_QMMMrec(cr,fr,x,mdatoms,box,top);
+    }
+
+    if ((flags & GMX_FORCE_BONDED) && top->idef.il[F_POSRES].nr > 0)
+    {
+        /* Position restraints always require full pbc */
+        set_pbc(&pbc,inputrec->ePBC,box);
+        v = posres(top->idef.il[F_POSRES].nr,top->idef.il[F_POSRES].iatoms,
+                   top->idef.iparams_posres,
+                   (const rvec*)x,fr->f_novirsum,fr->vir_diag_posres,
+                   inputrec->ePBC==epbcNONE ? NULL : &pbc,lambda,&dvdl,
+                   fr->rc_scaling,fr->ePBC,fr->posres_com,fr->posres_comB);
+        if (bSepDVDL)
+        {
+            fprintf(fplog,sepdvdlformat,
+                    interaction_function[F_POSRES].longname,v,dvdl);
+        }
+        enerd->term[F_POSRES] += v;
+        /* This linear lambda dependence assumption is only correct
+         * when only k depends on lambda,
+         * not when the reference position depends on lambda.
+         * grompp checks for this.
+         */
+        enerd->dvdl_lin += dvdl;
+        inc_nrnb(nrnb,eNR_POSRES,top->idef.il[F_POSRES].nr/2);
+    }
+
+    /* Compute the bonded and non-bonded energies and optionally forces */    
+    do_force_lowlevel(fplog,step,fr,inputrec,&(top->idef),
+                      cr,nrnb,wcycle,mdatoms,&(inputrec->opts),
+                      x,hist,f,enerd,fcd,mtop,top,fr->born,
+                      &(top->atomtypes),bBornRadii,box,
+                      lambda,graph,&(top->excls),fr->mu_tot,
+                      flags,&cycles_pme);
+    
+    cycles_force = wallcycle_stop(wcycle,ewcFORCE);
+    GMX_BARRIER(cr->mpi_comm_mygroup);
+    
+    if (ed)
+    {
+        do_flood(fplog,cr,x,f,ed,box,step);
+    }
+       
+    if (DOMAINDECOMP(cr))
+    {
+        dd_force_flop_stop(cr->dd,nrnb);
+        if (wcycle)
+        {
+            dd_cycles_add(cr->dd,cycles_force-cycles_pme,ddCyclF);
+        }
+    }
+    
+    if (bDoForces)
+    {
+        if (IR_ELEC_FIELD(*inputrec))
+        {
+            /* Compute forces due to electric field */
+            calc_f_el(MASTER(cr) ? field : NULL,
+                      start,homenr,mdatoms->chargeA,x,fr->f_novirsum,
+                      inputrec->ex,inputrec->et,t);
+        }
+        
+        /* Communicate the forces */
+        if (PAR(cr))
+        {
+            wallcycle_start(wcycle,ewcMOVEF);
+            if (DOMAINDECOMP(cr))
+            {
+                dd_move_f(cr->dd,f,fr->fshift);
+                /* Do we need to communicate the separate force array
+                 * for terms that do not contribute to the single sum virial?
+                 * Position restraints and electric fields do not introduce
+                 * inter-cg forces, only full electrostatics methods do.
+                 * When we do not calculate the virial, fr->f_novirsum = f,
+                 * so we have already communicated these forces.
+                 */
+                if (EEL_FULL(fr->eeltype) && cr->dd->n_intercg_excl &&
+                    (flags & GMX_FORCE_VIRIAL))
+                {
+                    dd_move_f(cr->dd,fr->f_novirsum,NULL);
+                }
+                if (bSepLRF)
+                {
+                    /* We should not update the shift forces here,
+                     * since f_twin is already included in f.
+                     */
+                    dd_move_f(cr->dd,fr->f_twin,NULL);
+                }
+            }
+            else
+            {
+                pd_move_f(cr,f,nrnb);
+                if (bSepLRF)
+                {
+                    pd_move_f(cr,fr->f_twin,nrnb);
+                }
+            }
+            wallcycle_stop(wcycle,ewcMOVEF);
+        }
+
+        /* If we have NoVirSum forces, but we do not calculate the virial,
+         * we sum fr->f_novirum=f later.
+         */
+        if (vsite && !(fr->bF_NoVirSum && !(flags & GMX_FORCE_VIRIAL)))
+        {
+            wallcycle_start(wcycle,ewcVSITESPREAD);
+            spread_vsite_f(fplog,vsite,x,f,fr->fshift,nrnb,
+                           &top->idef,fr->ePBC,fr->bMolPBC,graph,box,cr);
+            wallcycle_stop(wcycle,ewcVSITESPREAD);
+
+            if (bSepLRF)
+            {
+                wallcycle_start(wcycle,ewcVSITESPREAD);
+                spread_vsite_f(fplog,vsite,x,fr->f_twin,NULL,
+                               nrnb,
+                               &top->idef,fr->ePBC,fr->bMolPBC,graph,box,cr);
+                wallcycle_stop(wcycle,ewcVSITESPREAD);
+            }
+        }
+        
+        if (flags & GMX_FORCE_VIRIAL)
+        {
+            /* Calculation of the virial must be done after vsites! */
+            calc_virial(fplog,mdatoms->start,mdatoms->homenr,x,f,
+                        vir_force,graph,box,nrnb,fr,inputrec->ePBC);
+        }
+    }
+
+    if (inputrec->ePull == epullUMBRELLA || inputrec->ePull == epullCONST_F)
+    {
+        /* Calculate the center of mass forces, this requires communication,
+         * which is why pull_potential is called close to other communication.
+         * The virial contribution is calculated directly,
+         * which is why we call pull_potential after calc_virial.
+         */
+        set_pbc(&pbc,inputrec->ePBC,box);
+        dvdl = 0; 
+        enerd->term[F_COM_PULL] =
+            pull_potential(inputrec->ePull,inputrec->pull,mdatoms,&pbc,
+                           cr,t,lambda,x,f,vir_force,&dvdl);
+        if (bSepDVDL)
+        {
+            fprintf(fplog,sepdvdlformat,"Com pull",enerd->term[F_COM_PULL],dvdl);
+        }
+        enerd->dvdl_lin += dvdl;
+    }
+    else
+        enerd->term[F_COM_PULL] = 0.0;
+    
+    /* Add the forces from enforced rotation potentials (if any) */
+    if (inputrec->bRot)
+        enerd->term[F_COM_PULL] += add_rot_forces(inputrec->rot, f, cr, step, t);
+    
+
+    if (PAR(cr) && !(cr->duty & DUTY_PME))
+    {
+        cycles_ppdpme = wallcycle_stop(wcycle,ewcPPDURINGPME);
+        dd_cycles_add(cr->dd,cycles_ppdpme,ddCyclPPduringPME);
+
+        /* In case of node-splitting, the PP nodes receive the long-range 
+         * forces, virial and energy from the PME nodes here.
+         */    
+        wallcycle_start(wcycle,ewcPP_PMEWAITRECVF);
+        dvdl = 0;
+        gmx_pme_receive_f(cr,fr->f_novirsum,fr->vir_el_recip,&e,&dvdl,
+                          &cycles_seppme);
+        if (bSepDVDL)
+        {
+            fprintf(fplog,sepdvdlformat,"PME mesh",e,dvdl);
+        }
+        enerd->term[F_COUL_RECIP] += e;
+        enerd->dvdl_lin += dvdl;
+        if (wcycle)
+        {
+            dd_cycles_add(cr->dd,cycles_seppme,ddCyclPME);
+        }
+        wallcycle_stop(wcycle,ewcPP_PMEWAITRECVF);
+    }
+
+    if (bDoForces && fr->bF_NoVirSum)
+    {
+        if (vsite)
+        {
+            /* Spread the mesh force on virtual sites to the other particles... 
+             * This is parallellized. MPI communication is performed
+             * if the constructing atoms aren't local.
+             */
+            wallcycle_start(wcycle,ewcVSITESPREAD);
+            spread_vsite_f(fplog,vsite,x,fr->f_novirsum,NULL,nrnb,
+                           &top->idef,fr->ePBC,fr->bMolPBC,graph,box,cr);
+            wallcycle_stop(wcycle,ewcVSITESPREAD);
+        }
+        if (flags & GMX_FORCE_VIRIAL)
+        {
+            /* Now add the forces, this is local */
+            if (fr->bDomDec)
+            {
+                sum_forces(0,fr->f_novirsum_n,f,fr->f_novirsum);
+            }
+            else
+            {
+                sum_forces(start,start+homenr,f,fr->f_novirsum);
+            }
+            if (EEL_FULL(fr->eeltype))
+            {
+                /* Add the mesh contribution to the virial */
+                m_add(vir_force,fr->vir_el_recip,vir_force);
+            }
+            if (debug)
+            {
+                pr_rvecs(debug,0,"vir_force",vir_force,DIM);
+            }
+        }
+    }
+    
+    /* Sum the potential energy terms from group contributions */
+    sum_epot(&(inputrec->opts),enerd);
+    
+    if (fr->print_force >= 0 && bDoForces)
+    {
+        print_large_forces(stderr,mdatoms,cr,step,fr->print_force,x,f);
+    }
+}
+
+void do_constrain_first(FILE *fplog,gmx_constr_t constr,
+                        t_inputrec *ir,t_mdatoms *md,
+                        t_state *state,rvec *f,
+                        t_graph *graph,t_commrec *cr,t_nrnb *nrnb,
+                        t_forcerec *fr, gmx_localtop_t *top, tensor shake_vir)
+{
+    int    i,m,start,end;
+    gmx_large_int_t step;
+    double mass,tmass,vcm[4];
+    real   dt=ir->delta_t;
+    real   dvdlambda;
+    rvec   *savex;
+    
+    snew(savex,state->natoms);
+
+    start = md->start;
+    end   = md->homenr + start;
+    
+    if (debug)
+        fprintf(debug,"vcm: start=%d, homenr=%d, end=%d\n",
+                start,md->homenr,end);
+    /* Do a first constrain to reset particles... */
+    step = ir->init_step;
+    if (fplog)
+    {
+        char buf[STEPSTRSIZE];
+        fprintf(fplog,"\nConstraining the starting coordinates (step %s)\n",
+                gmx_step_str(step,buf));
+    }
+    dvdlambda = 0;
+    
+    /* constrain the current position */
+    constrain(NULL,TRUE,FALSE,constr,&(top->idef),
+              ir,NULL,cr,step,0,md,
+              state->x,state->x,NULL,
+              state->box,state->lambda,&dvdlambda,
+              NULL,NULL,nrnb,econqCoord,ir->epc==epcMTTK,state->veta,state->veta);
+    if (EI_VV(ir->eI)) 
+    {
+        /* constrain the inital velocity, and save it */
+        /* also may be useful if we need the ekin from the halfstep for velocity verlet */
+        /* might not yet treat veta correctly */
+        constrain(NULL,TRUE,FALSE,constr,&(top->idef),
+                  ir,NULL,cr,step,0,md,
+                  state->x,state->v,state->v,
+                  state->box,state->lambda,&dvdlambda,
+                  NULL,NULL,nrnb,econqVeloc,ir->epc==epcMTTK,state->veta,state->veta);
+    }
+    /* constrain the inital velocities at t-dt/2 */
+    if (EI_STATE_VELOCITY(ir->eI) && ir->eI!=eiVV)
+    {
+        for(i=start; (i<end); i++) 
+        {
+            for(m=0; (m<DIM); m++) 
+            {
+                /* Reverse the velocity */
+                state->v[i][m] = -state->v[i][m];
+                /* Store the position at t-dt in buf */
+                savex[i][m] = state->x[i][m] + dt*state->v[i][m];
+            }
+        }
+    /* Shake the positions at t=-dt with the positions at t=0                        
+     * as reference coordinates.                                                     
+         */
+        if (fplog)
+        {
+            char buf[STEPSTRSIZE];
+            fprintf(fplog,"\nConstraining the coordinates at t0-dt (step %s)\n",
+                    gmx_step_str(step,buf));
+        }
+        dvdlambda = 0;
+        constrain(NULL,TRUE,FALSE,constr,&(top->idef),
+                  ir,NULL,cr,step,-1,md,
+                  state->x,savex,NULL,
+                  state->box,state->lambda,&dvdlambda,
+                  state->v,NULL,nrnb,econqCoord,ir->epc==epcMTTK,state->veta,state->veta);
+        
+        for(i=start; i<end; i++) {
+            for(m=0; m<DIM; m++) {
+                /* Re-reverse the velocities */
+                state->v[i][m] = -state->v[i][m];
+            }
+        }
+    }
+    
+    for(m=0; (m<4); m++)
+        vcm[m] = 0;
+    for(i=start; i<end; i++) {
+        mass = md->massT[i];
+        for(m=0; m<DIM; m++) {
+            vcm[m] += state->v[i][m]*mass;
+        }
+        vcm[3] += mass;
+    }
+    
+    if (ir->nstcomm != 0 || debug) {
+        /* Compute the global sum of vcm */
+        if (debug)
+            fprintf(debug,"vcm: %8.3f  %8.3f  %8.3f,"
+                    " total mass = %12.5e\n",vcm[XX],vcm[YY],vcm[ZZ],vcm[3]);
+        if (PAR(cr))
+            gmx_sumd(4,vcm,cr);
+        tmass = vcm[3];
+        for(m=0; (m<DIM); m++)
+            vcm[m] /= tmass;
+        if (debug) 
+            fprintf(debug,"vcm: %8.3f  %8.3f  %8.3f,"
+                    " total mass = %12.5e\n",vcm[XX],vcm[YY],vcm[ZZ],tmass);
+        if (ir->nstcomm != 0) {
+            /* Now we have the velocity of center of mass, let's remove it */
+            for(i=start; (i<end); i++) {
+                for(m=0; (m<DIM); m++)
+                    state->v[i][m] -= vcm[m];
+            }
+
+        }
+    }
+    sfree(savex);
+}
+
+void calc_enervirdiff(FILE *fplog,int eDispCorr,t_forcerec *fr)
+{
+  double eners[2],virs[2],enersum,virsum,y0,f,g,h;
+  double r0,r1,r,rc3,rc9,ea,eb,ec,pa,pb,pc,pd;
+  double invscale,invscale2,invscale3;
+  int    ri0,ri1,ri,i,offstart,offset;
+  real   scale,*vdwtab; 
+
+  fr->enershiftsix = 0;
+  fr->enershifttwelve = 0;
+  fr->enerdiffsix = 0;
+  fr->enerdifftwelve = 0;
+  fr->virdiffsix = 0;
+  fr->virdifftwelve = 0;
+
+  if (eDispCorr != edispcNO) {
+    for(i=0; i<2; i++) {
+      eners[i] = 0;
+      virs[i]  = 0;
+    }
+    if ((fr->vdwtype == evdwSWITCH) || (fr->vdwtype == evdwSHIFT)) {
+      if (fr->rvdw_switch == 0)
+       gmx_fatal(FARGS,
+                 "With dispersion correction rvdw-switch can not be zero "
+                 "for vdw-type = %s",evdw_names[fr->vdwtype]);
+
+      scale  = fr->nblists[0].tab.scale;
+      vdwtab = fr->nblists[0].vdwtab;
+
+      /* Round the cut-offs to exact table values for precision */
+      ri0 = floor(fr->rvdw_switch*scale);
+      ri1 = ceil(fr->rvdw*scale);
+      r0  = ri0/scale;
+      r1  = ri1/scale;
+      rc3 = r0*r0*r0;
+      rc9  = rc3*rc3*rc3;
+
+      if (fr->vdwtype == evdwSHIFT) {
+       /* Determine the constant energy shift below rvdw_switch */
+       fr->enershiftsix    = (real)(-1.0/(rc3*rc3)) - vdwtab[8*ri0];
+       fr->enershifttwelve = (real)( 1.0/(rc9*rc3)) - vdwtab[8*ri0 + 4];
+      }
+      /* Add the constant part from 0 to rvdw_switch.
+       * This integration from 0 to rvdw_switch overcounts the number
+       * of interactions by 1, as it also counts the self interaction.
+       * We will correct for this later.
+       */
+      eners[0] += 4.0*M_PI*fr->enershiftsix*rc3/3.0;
+      eners[1] += 4.0*M_PI*fr->enershifttwelve*rc3/3.0;
+      
+      invscale = 1.0/(scale);  
+      invscale2 = invscale*invscale;
+      invscale3 = invscale*invscale2;
+
+      /* following summation derived from cubic spline definition,
+       Numerical Recipies in C, second edition, p. 113-116.  Exact
+       for the cubic spline.  We first calculate the negative of
+       the energy from rvdw to rvdw_switch, assuming that g(r)=1,
+       and then add the more standard, abrupt cutoff correction to
+       that result, yielding the long-range correction for a
+       switched function.  We perform both the pressure and energy
+       loops at the same time for simplicity, as the computational
+       cost is low. */
+      
+      for (i=0;i<2;i++) {
+        enersum = 0.0; virsum = 0.0;
+        if (i==0)
+         offstart = 0;
+       else
+         offstart = 4;
+       for (ri=ri0; ri<ri1; ri++) {
+          r = ri*invscale;
+          ea = invscale3;
+          eb = 2.0*invscale2*r;
+          ec = invscale*r*r;
+          
+          pa = invscale3;
+          pb = 3.0*invscale2*r;
+          pc = 3.0*invscale*r*r;
+          pd = r*r*r;
+          
+          /* this "8" is from the packing in the vdwtab array - perhaps
+           should be #define'ed? */
+          offset = 8*ri + offstart;
+          y0 = vdwtab[offset];
+          f = vdwtab[offset+1];
+          g = vdwtab[offset+2];
+          h = vdwtab[offset+3];
+         
+          enersum += y0*(ea/3 + eb/2 + ec) + f*(ea/4 + eb/3 + ec/2)+
+            g*(ea/5 + eb/4 + ec/3) + h*(ea/6 + eb/5 + ec/4);  
+          virsum  +=  f*(pa/4 + pb/3 + pc/2 + pd) + 
+            2*g*(pa/5 + pb/4 + pc/3 + pd/2) + 3*h*(pa/6 + pb/5 + pc/4 + pd/3);
+         
+        }
+        enersum *= 4.0*M_PI;
+        virsum  *= 4.0*M_PI; 
+        eners[i] -= enersum;
+        virs[i]  -= virsum;
+      }
+
+      /* now add the correction for rvdw_switch to infinity */
+      eners[0] += -4.0*M_PI/(3.0*rc3);
+      eners[1] +=  4.0*M_PI/(9.0*rc9);
+      virs[0]  +=  8.0*M_PI/rc3;
+      virs[1]  += -16.0*M_PI/(3.0*rc9);
+    } 
+    else if ((fr->vdwtype == evdwCUT) || (fr->vdwtype == evdwUSER)) {
+      if (fr->vdwtype == evdwUSER && fplog)
+       fprintf(fplog,
+               "WARNING: using dispersion correction with user tables\n");
+      rc3  = fr->rvdw*fr->rvdw*fr->rvdw;
+      rc9  = rc3*rc3*rc3;
+      eners[0] += -4.0*M_PI/(3.0*rc3);
+      eners[1] +=  4.0*M_PI/(9.0*rc9);
+      virs[0]  +=  8.0*M_PI/rc3;
+      virs[1]  += -16.0*M_PI/(3.0*rc9);
+    } else {
+      gmx_fatal(FARGS,
+               "Dispersion correction is not implemented for vdw-type = %s",
+               evdw_names[fr->vdwtype]);
+    }
+    fr->enerdiffsix    = eners[0];
+    fr->enerdifftwelve = eners[1];
+    /* The 0.5 is due to the Gromacs definition of the virial */
+    fr->virdiffsix     = 0.5*virs[0];
+    fr->virdifftwelve  = 0.5*virs[1];
+  }
+}
+
+void calc_dispcorr(FILE *fplog,t_inputrec *ir,t_forcerec *fr,
+                   gmx_large_int_t step,int natoms,
+                   matrix box,real lambda,tensor pres,tensor virial,
+                   real *prescorr, real *enercorr, real *dvdlcorr)
+{
+    gmx_bool bCorrAll,bCorrPres;
+    real dvdlambda,invvol,dens,ninter,avcsix,avctwelve,enerdiff,svir=0,spres=0;
+    int  m;
+    
+    *prescorr = 0;
+    *enercorr = 0;
+    *dvdlcorr = 0;
+    
+    clear_mat(virial);
+    clear_mat(pres);
+    
+    if (ir->eDispCorr != edispcNO) {
+        bCorrAll  = (ir->eDispCorr == edispcAllEner ||
+                     ir->eDispCorr == edispcAllEnerPres);
+        bCorrPres = (ir->eDispCorr == edispcEnerPres ||
+                     ir->eDispCorr == edispcAllEnerPres);
+        
+        invvol = 1/det(box);
+        if (fr->n_tpi) 
+        {
+            /* Only correct for the interactions with the inserted molecule */
+            dens = (natoms - fr->n_tpi)*invvol;
+            ninter = fr->n_tpi;
+        } 
+        else 
+        {
+            dens = natoms*invvol;
+            ninter = 0.5*natoms;
+        }
+        
+        if (ir->efep == efepNO) 
+        {
+            avcsix    = fr->avcsix[0];
+            avctwelve = fr->avctwelve[0];
+        } 
+        else 
+        {
+            avcsix    = (1 - lambda)*fr->avcsix[0]    + lambda*fr->avcsix[1];
+            avctwelve = (1 - lambda)*fr->avctwelve[0] + lambda*fr->avctwelve[1];
+        }
+        
+        enerdiff = ninter*(dens*fr->enerdiffsix - fr->enershiftsix);
+        *enercorr += avcsix*enerdiff;
+        dvdlambda = 0.0;
+        if (ir->efep != efepNO) 
+        {
+            dvdlambda += (fr->avcsix[1] - fr->avcsix[0])*enerdiff;
+        }
+        if (bCorrAll) 
+        {
+            enerdiff = ninter*(dens*fr->enerdifftwelve - fr->enershifttwelve);
+            *enercorr += avctwelve*enerdiff;
+            if (fr->efep != efepNO) 
+            {
+                dvdlambda += (fr->avctwelve[1] - fr->avctwelve[0])*enerdiff;
+            }
+        }
+        
+        if (bCorrPres) 
+        {
+            svir = ninter*dens*avcsix*fr->virdiffsix/3.0;
+            if (ir->eDispCorr == edispcAllEnerPres)
+            {
+                svir += ninter*dens*avctwelve*fr->virdifftwelve/3.0;
+            }
+            /* The factor 2 is because of the Gromacs virial definition */
+            spres = -2.0*invvol*svir*PRESFAC;
+            
+            for(m=0; m<DIM; m++) {
+                virial[m][m] += svir;
+                pres[m][m] += spres;
+            }
+            *prescorr += spres;
+        }
+        
+        /* Can't currently control when it prints, for now, just print when degugging */
+        if (debug)
+        {
+            if (bCorrAll) {
+                fprintf(debug,"Long Range LJ corr.: <C6> %10.4e, <C12> %10.4e\n",
+                        avcsix,avctwelve);
+            }
+            if (bCorrPres) 
+            {
+                fprintf(debug,
+                        "Long Range LJ corr.: Epot %10g, Pres: %10g, Vir: %10g\n",
+                        *enercorr,spres,svir);
+            }
+            else
+            {
+                fprintf(debug,"Long Range LJ corr.: Epot %10g\n",*enercorr);
+            }
+        }
+        
+        if (fr->bSepDVDL && do_per_step(step,ir->nstlog))
+        {
+            fprintf(fplog,sepdvdlformat,"Dispersion correction",
+                    *enercorr,dvdlambda);
+        }
+        if (fr->efep != efepNO) 
+        {
+            *dvdlcorr += dvdlambda;
+        }
+    }
+}
+
+void do_pbc_first(FILE *fplog,matrix box,t_forcerec *fr,
+                 t_graph *graph,rvec x[])
+{
+  if (fplog)
+    fprintf(fplog,"Removing pbc first time\n");
+  calc_shifts(box,fr->shift_vec);
+  if (graph) {
+    mk_mshift(fplog,graph,fr->ePBC,box,x);
+    if (gmx_debug_at)
+      p_graph(debug,"do_pbc_first 1",graph);
+    shift_self(graph,box,x);
+    /* By doing an extra mk_mshift the molecules that are broken
+     * because they were e.g. imported from another software
+     * will be made whole again. Such are the healing powers
+     * of GROMACS.
+     */
+    mk_mshift(fplog,graph,fr->ePBC,box,x);
+    if (gmx_debug_at)
+      p_graph(debug,"do_pbc_first 2",graph);
+  }
+  if (fplog)
+    fprintf(fplog,"Done rmpbc\n");
+}
+
+static void low_do_pbc_mtop(FILE *fplog,int ePBC,matrix box,
+                           gmx_mtop_t *mtop,rvec x[],
+                           gmx_bool bFirst)
+{
+  t_graph *graph;
+  int mb,as,mol;
+  gmx_molblock_t *molb;
+
+  if (bFirst && fplog)
+    fprintf(fplog,"Removing pbc first time\n");
+
+  snew(graph,1);
+  as = 0;
+  for(mb=0; mb<mtop->nmolblock; mb++) {
+    molb = &mtop->molblock[mb];
+    if (molb->natoms_mol == 1 || 
+       (!bFirst && mtop->moltype[molb->type].cgs.nr == 1)) {
+      /* Just one atom or charge group in the molecule, no PBC required */
+      as += molb->nmol*molb->natoms_mol;
+    } else {
+      /* Pass NULL iso fplog to avoid graph prints for each molecule type */
+      mk_graph_ilist(NULL,mtop->moltype[molb->type].ilist,
+                    0,molb->natoms_mol,FALSE,FALSE,graph);
+      
+      for(mol=0; mol<molb->nmol; mol++) {
+       mk_mshift(fplog,graph,ePBC,box,x+as);
+       
+       shift_self(graph,box,x+as);
+       /* The molecule is whole now.
+        * We don't need the second mk_mshift call as in do_pbc_first,
+        * since we no longer need this graph.
+        */
+       
+       as += molb->natoms_mol;
+      }
+      done_graph(graph);
+    }
+  }
+  sfree(graph);
+}
+
+void do_pbc_first_mtop(FILE *fplog,int ePBC,matrix box,
+                      gmx_mtop_t *mtop,rvec x[])
+{
+  low_do_pbc_mtop(fplog,ePBC,box,mtop,x,TRUE);
+}
+
+void do_pbc_mtop(FILE *fplog,int ePBC,matrix box,
+                gmx_mtop_t *mtop,rvec x[])
+{
+  low_do_pbc_mtop(fplog,ePBC,box,mtop,x,FALSE);
+}
+
+void finish_run(FILE *fplog,t_commrec *cr,const char *confout,
+                t_inputrec *inputrec,
+                t_nrnb nrnb[],gmx_wallcycle_t wcycle,
+                gmx_runtime_t *runtime,
+                gmx_bool bWriteStat)
+{
+  int    i,j;
+  t_nrnb *nrnb_tot=NULL;
+  real   delta_t;
+  double nbfs,mflop;
+  double cycles[ewcNR];
+
+  wallcycle_sum(cr,wcycle,cycles);
+
+  if (cr->nnodes > 1) {
+    if (SIMMASTER(cr))
+      snew(nrnb_tot,1);
+#ifdef GMX_MPI
+    MPI_Reduce(nrnb->n,nrnb_tot->n,eNRNB,MPI_DOUBLE,MPI_SUM,
+               MASTERRANK(cr),cr->mpi_comm_mysim);
+#endif  
+  } else {
+    nrnb_tot = nrnb;
+  }
+    
+  if (SIMMASTER(cr)) {
+    print_flop(fplog,nrnb_tot,&nbfs,&mflop);
+    if (cr->nnodes > 1) {
+      sfree(nrnb_tot);
+    }
+  }
+
+  if ((cr->duty & DUTY_PP) && DOMAINDECOMP(cr)) {
+    print_dd_statistics(cr,inputrec,fplog);
+  }
+
+#ifdef GMX_MPI
+    if (PARTDECOMP(cr))
+    {
+        if (MASTER(cr))
+        {
+            t_nrnb     *nrnb_all;
+            int        s;
+            MPI_Status stat;
+
+            snew(nrnb_all,cr->nnodes);
+            nrnb_all[0] = *nrnb;
+            for(s=1; s<cr->nnodes; s++)
+            {
+                MPI_Recv(nrnb_all[s].n,eNRNB,MPI_DOUBLE,s,0,
+                         cr->mpi_comm_mysim,&stat);
+            }
+            pr_load(fplog,cr,nrnb_all);
+            sfree(nrnb_all);
+        }
+        else
+        {
+            MPI_Send(nrnb->n,eNRNB,MPI_DOUBLE,MASTERRANK(cr),0,
+                     cr->mpi_comm_mysim);
+        }
+    }
+#endif  
+
+  if (SIMMASTER(cr)) {
+    wallcycle_print(fplog,cr->nnodes,cr->npmenodes,runtime->realtime,
+                    wcycle,cycles);
+
+    if (EI_DYNAMICS(inputrec->eI)) {
+      delta_t = inputrec->delta_t;
+    } else {
+      delta_t = 0;
+    }
+    
+    if (fplog) {
+        print_perf(fplog,runtime->proctime,runtime->realtime,
+                   cr->nnodes-cr->npmenodes,
+                   runtime->nsteps_done,delta_t,nbfs,mflop);
+    }
+    if (bWriteStat) {
+        print_perf(stderr,runtime->proctime,runtime->realtime,
+                   cr->nnodes-cr->npmenodes,
+                   runtime->nsteps_done,delta_t,nbfs,mflop);
+    }
+
+    /*
+    runtime=inputrec->nsteps*inputrec->delta_t;
+    if (bWriteStat) {
+      if (cr->nnodes == 1)
+       fprintf(stderr,"\n\n");
+      print_perf(stderr,nodetime,realtime,runtime,&ntot,
+                cr->nnodes-cr->npmenodes,FALSE);
+    }
+    wallcycle_print(fplog,cr->nnodes,cr->npmenodes,realtime,wcycle,cycles);
+    print_perf(fplog,nodetime,realtime,runtime,&ntot,cr->nnodes-cr->npmenodes,
+              TRUE);
+    if (PARTDECOMP(cr))
+      pr_load(fplog,cr,nrnb_all);
+    if (cr->nnodes > 1)
+      sfree(nrnb_all);
+    */
+  }
+}
+
+void init_md(FILE *fplog,
+             t_commrec *cr,t_inputrec *ir,const output_env_t oenv,
+             double *t,double *t0,
+             real *lambda,double *lam0,
+             t_nrnb *nrnb,gmx_mtop_t *mtop,
+             gmx_update_t *upd,
+             int nfile,const t_filenm fnm[],
+             gmx_mdoutf_t **outf,t_mdebin **mdebin,
+             tensor force_vir,tensor shake_vir,rvec mu_tot,
+             gmx_bool *bSimAnn,t_vcm **vcm, t_state *state, unsigned long Flags)
+{
+    int  i,j,n;
+    real tmpt,mod;
+       
+    /* Initial values */
+    *t = *t0       = ir->init_t;
+    if (ir->efep != efepNO)
+    {
+        *lam0 = ir->init_lambda;
+        *lambda = *lam0 + ir->init_step*ir->delta_lambda;
+    }
+    else
+    {
+        *lambda = *lam0   = 0.0;
+    } 
+
+    *bSimAnn=FALSE;
+    for(i=0;i<ir->opts.ngtc;i++)
+    {
+        /* set bSimAnn if any group is being annealed */
+        if(ir->opts.annealing[i]!=eannNO)
+        {
+            *bSimAnn = TRUE;
+        }
+    }
+    if (*bSimAnn)
+    {
+        update_annealing_target_temp(&(ir->opts),ir->init_t);
+    }
+    
+    if (upd)
+    {
+        *upd = init_update(fplog,ir);
+    }
+    
+    if (vcm != NULL)
+    {
+        *vcm = init_vcm(fplog,&mtop->groups,ir);
+    }
+    
+    if (EI_DYNAMICS(ir->eI) && !(Flags & MD_APPENDFILES))
+    {
+        if (ir->etc == etcBERENDSEN)
+        {
+            please_cite(fplog,"Berendsen84a");
+        }
+        if (ir->etc == etcVRESCALE)
+        {
+            please_cite(fplog,"Bussi2007a");
+        }
+    }
+    
+    init_nrnb(nrnb);
+    
+    if (nfile != -1)
+    {
+        *outf = init_mdoutf(nfile,fnm,Flags,cr,ir,oenv);
+
+        *mdebin = init_mdebin((Flags & MD_APPENDFILES) ? NULL : (*outf)->fp_ene,
+                              mtop,ir, (*outf)->fp_dhdl);
+    }
+    
+    /* Initiate variables */  
+    clear_mat(force_vir);
+    clear_mat(shake_vir);
+    clear_rvec(mu_tot);
+    
+    debug_gmx();
+}
+
similarity index 100%
rename from src/mdlib/stat.c
rename to src/gromacs/mdlib/stat.c
diff --git a/src/gromacs/mdlib/tpi.c b/src/gromacs/mdlib/tpi.c
new file mode 100644 (file)
index 0000000..2a5ae3d
--- /dev/null
@@ -0,0 +1,795 @@
+/* -*- 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
+ * 
+ *                        VERSION 3.2.0
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * 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.
+
+ * 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:
+ * GROwing Monsters And Cloning Shrimps
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <time.h>
+#include <math.h>
+#include "sysstuff.h"
+#include "string2.h"
+#include "network.h"
+#include "confio.h"
+#include "copyrite.h"
+#include "smalloc.h"
+#include "nrnb.h"
+#include "main.h"
+#include "chargegroup.h"
+#include "force.h"
+#include "macros.h"
+#include "random.h"
+#include "names.h"
+#include "gmx_fatal.h"
+#include "txtdump.h"
+#include "typedefs.h"
+#include "update.h"
+#include "random.h"
+#include "constr.h"
+#include "vec.h"
+#include "statutil.h"
+#include "tgroup.h"
+#include "mdebin.h"
+#include "vsite.h"
+#include "force.h"
+#include "mdrun.h"
+#include "domdec.h"
+#include "partdec.h"
+#include "gmx_random.h"
+#include "physics.h"
+#include "xvgr.h"
+#include "mdatoms.h"
+#include "ns.h"
+#include "gmx_wallcycle.h"
+#include "mtop_util.h"
+#include "gmxfio.h"
+#include "pme.h"
+#include "gbutil.h"
+
+#if ( defined(GMX_IA32_SSE) || defined(GMX_X86_64_SSE) || defined(GMX_X86_64_SSE2) )
+#if defined(GMX_DOUBLE)
+#include "gmx_sse2_double.h"
+#else
+#include "gmx_sse2_single.h"
+#endif
+#endif
+
+
+static void global_max(t_commrec *cr,int *n)
+{
+  int *sum,i;
+
+  snew(sum,cr->nnodes);
+  sum[cr->nodeid] = *n;
+  gmx_sumi(cr->nnodes,sum,cr);
+  for(i=0; i<cr->nnodes; i++)
+    *n = max(*n,sum[i]);
+  
+  sfree(sum);
+}
+
+static void realloc_bins(double **bin,int *nbin,int nbin_new)
+{
+  int i;
+
+  if (nbin_new != *nbin) {
+    srenew(*bin,nbin_new);
+    for(i=*nbin; i<nbin_new; i++)
+      (*bin)[i] = 0;
+    *nbin = nbin_new;
+  }
+}
+
+double do_tpi(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 *inputrec,
+              gmx_mtop_t *top_global,t_fcdata *fcd,
+              t_state *state,
+              t_mdatoms *mdatoms,
+              t_nrnb *nrnb,gmx_wallcycle_t wcycle,
+              gmx_edsam_t ed,
+              t_forcerec *fr,
+              int repl_ex_nst,int repl_ex_seed,
+              gmx_membed_t *membed,
+              real cpt_period,real max_hours,
+              const char *deviceOptions,
+              unsigned long Flags,
+              gmx_runtime_t *runtime)
+{
+  const char *TPI="Test Particle Insertion"; 
+  gmx_localtop_t *top;
+  gmx_groups_t *groups;
+  gmx_enerdata_t *enerd;
+  rvec   *f;
+  real   lambda,t,temp,beta,drmax,epot;
+  double embU,sum_embU,*sum_UgembU,V,V_all,VembU_all;
+  t_trxstatus   *status;
+  t_trxframe rerun_fr;
+  gmx_bool   bDispCorr,bCharge,bRFExcl,bNotLastFrame,bStateChanged,bNS,bOurStep;
+  tensor force_vir,shake_vir,vir,pres;
+  int    cg_tp,a_tp0,a_tp1,ngid,gid_tp,nener,e;
+  rvec   *x_mol;
+  rvec   mu_tot,x_init,dx,x_tp;
+  int    nnodes,frame,nsteps,step;
+  int    i,start,end;
+  gmx_rng_t tpi_rand;
+  FILE   *fp_tpi=NULL;
+  char   *ptr,*dump_pdb,**leg,str[STRLEN],str2[STRLEN];
+  double dbl,dump_ener;
+  gmx_bool   bCavity;
+  int    nat_cavity=0,d;
+  real   *mass_cavity=NULL,mass_tot;
+  int    nbin;
+  double invbinw,*bin,refvolshift,logV,bUlogV;
+  real dvdl,prescorr,enercorr,dvdlcorr;
+  gmx_bool bEnergyOutOfBounds;
+  const char *tpid_leg[2]={"direct","reweighted"};
+
+  /* Since there is no upper limit to the insertion energies,
+   * we need to set an upper limit for the distribution output.
+   */
+  real bU_bin_limit      = 50;
+  real bU_logV_bin_limit = bU_bin_limit + 10;
+
+  nnodes = cr->nnodes;
+
+  top = gmx_mtop_generate_local_top(top_global,inputrec);
+
+  groups = &top_global->groups;
+
+  bCavity = (inputrec->eI == eiTPIC);
+  if (bCavity) {
+    ptr = getenv("GMX_TPIC_MASSES");
+    if (ptr == NULL) {
+      nat_cavity = 1;
+    } else {
+      /* Read (multiple) masses from env var GMX_TPIC_MASSES,
+       * The center of mass of the last atoms is then used for TPIC.
+       */
+      nat_cavity = 0;
+      while (sscanf(ptr,"%lf%n",&dbl,&i) > 0) {
+       srenew(mass_cavity,nat_cavity+1);
+       mass_cavity[nat_cavity] = dbl;
+       fprintf(fplog,"mass[%d] = %f\n",
+               nat_cavity+1,mass_cavity[nat_cavity]);
+       nat_cavity++;
+       ptr += i;
+      }
+      if (nat_cavity == 0)
+       gmx_fatal(FARGS,"Found %d masses in GMX_TPIC_MASSES",nat_cavity);
+    }
+  }
+
+  /*
+  init_em(fplog,TPI,inputrec,&lambda,nrnb,mu_tot,
+  state->box,fr,mdatoms,top,cr,nfile,fnm,NULL,NULL);*/
+  /* We never need full pbc for TPI */
+  fr->ePBC = epbcXYZ;
+  /* Determine the temperature for the Boltzmann weighting */
+  temp = inputrec->opts.ref_t[0];
+  if (fplog) {
+    for(i=1; (i<inputrec->opts.ngtc); i++) {
+      if (inputrec->opts.ref_t[i] != temp) {
+       fprintf(fplog,"\nWARNING: The temperatures of the different temperature coupling groups are not identical\n\n");
+       fprintf(stderr,"\nWARNING: The temperatures of the different temperature coupling groups are not identical\n\n");
+      }
+    }
+    fprintf(fplog,
+           "\n  The temperature for test particle insertion is %.3f K\n\n",
+           temp);
+  }
+  beta = 1.0/(BOLTZ*temp);
+
+  /* Number of insertions per frame */
+  nsteps = inputrec->nsteps; 
+
+  /* Use the same neighborlist with more insertions points
+   * in a sphere of radius drmax around the initial point
+   */
+  /* This should be a proper mdp parameter */
+  drmax = inputrec->rtpi;
+
+  /* An environment variable can be set to dump all configurations
+   * to pdb with an insertion energy <= this value.
+   */
+  dump_pdb = getenv("GMX_TPI_DUMP");
+  dump_ener = 0;
+  if (dump_pdb)
+    sscanf(dump_pdb,"%lf",&dump_ener);
+
+  atoms2md(top_global,inputrec,0,NULL,0,top_global->natoms,mdatoms);
+  update_mdatoms(mdatoms,inputrec->init_lambda);
+
+  snew(enerd,1);
+  init_enerdata(groups->grps[egcENER].nr,inputrec->n_flambda,enerd);
+  snew(f,top_global->natoms);
+
+  /* Print to log file  */
+  runtime_start(runtime);
+  print_date_and_time(fplog,cr->nodeid,
+                      "Started Test Particle Insertion",runtime); 
+  wallcycle_start(wcycle,ewcRUN);
+
+  /* The last charge group is the group to be inserted */
+  cg_tp = top->cgs.nr - 1;
+  a_tp0 = top->cgs.index[cg_tp];
+  a_tp1 = top->cgs.index[cg_tp+1];
+  if (debug)
+    fprintf(debug,"TPI cg %d, atoms %d-%d\n",cg_tp,a_tp0,a_tp1);
+  if (a_tp1 - a_tp0 > 1 &&
+      (inputrec->rlist < inputrec->rcoulomb ||
+       inputrec->rlist < inputrec->rvdw))
+    gmx_fatal(FARGS,"Can not do TPI for multi-atom molecule with a twin-range cut-off");
+  snew(x_mol,a_tp1-a_tp0);
+
+  bDispCorr = (inputrec->eDispCorr != edispcNO);
+  bCharge = FALSE;
+  for(i=a_tp0; i<a_tp1; i++) {
+    /* Copy the coordinates of the molecule to be insterted */
+    copy_rvec(state->x[i],x_mol[i-a_tp0]);
+    /* Check if we need to print electrostatic energies */
+    bCharge |= (mdatoms->chargeA[i] != 0 ||
+               (mdatoms->chargeB && mdatoms->chargeB[i] != 0));
+  }
+  bRFExcl = (bCharge && EEL_RF(fr->eeltype) && fr->eeltype!=eelRF_NEC);
+
+  calc_cgcm(fplog,cg_tp,cg_tp+1,&(top->cgs),state->x,fr->cg_cm);
+  if (bCavity) {
+    if (norm(fr->cg_cm[cg_tp]) > 0.5*inputrec->rlist && fplog) {
+      fprintf(fplog, "WARNING: Your TPI molecule is not centered at 0,0,0\n");
+      fprintf(stderr,"WARNING: Your TPI molecule is not centered at 0,0,0\n");
+    }
+  } else {
+    /* Center the molecule to be inserted at zero */
+     for(i=0; i<a_tp1-a_tp0; i++)
+      rvec_dec(x_mol[i],fr->cg_cm[cg_tp]);
+  }
+
+  if (fplog) {
+    fprintf(fplog,"\nWill insert %d atoms %s partial charges\n",
+           a_tp1-a_tp0,bCharge ? "with" : "without");
+    
+    fprintf(fplog,"\nWill insert %d times in each frame of %s\n",
+           nsteps,opt2fn("-rerun",nfile,fnm));
+  }
+  
+    if (!bCavity)
+    {
+        if (inputrec->nstlist > 1)
+        {
+            if (drmax==0 && a_tp1-a_tp0==1)
+            {
+                gmx_fatal(FARGS,"Re-using the neighborlist %d times for insertions of a single atom in a sphere of radius %f does not make sense",inputrec->nstlist,drmax);
+            }
+            if (fplog)
+            {
+                fprintf(fplog,"Will use the same neighborlist for %d insertions in a sphere of radius %f\n",inputrec->nstlist,drmax);
+            }
+        }
+    }
+    else
+    {
+        if (fplog)
+        {
+            fprintf(fplog,"Will insert randomly in a sphere of radius %f around the center of the cavity\n",drmax);
+        }
+    }
+
+  ngid = groups->grps[egcENER].nr;
+  gid_tp = GET_CGINFO_GID(fr->cginfo[cg_tp]);
+  nener = 1 + ngid;
+  if (bDispCorr)
+    nener += 1;
+  if (bCharge) {
+    nener += ngid;
+    if (bRFExcl)
+      nener += 1;
+    if (EEL_FULL(fr->eeltype))
+      nener += 1;
+  }
+  snew(sum_UgembU,nener);
+
+  /* Initialize random generator */
+  tpi_rand = gmx_rng_init(inputrec->ld_seed);
+
+  if (MASTER(cr)) {
+    fp_tpi = xvgropen(opt2fn("-tpi",nfile,fnm),
+                     "TPI energies","Time (ps)",
+                     "(kJ mol\\S-1\\N) / (nm\\S3\\N)",oenv);
+    xvgr_subtitle(fp_tpi,"f. are averages over one frame",oenv);
+    snew(leg,4+nener);
+    e = 0;
+    sprintf(str,"-kT log(<Ve\\S-\\betaU\\N>/<V>)");
+    leg[e++] = strdup(str);
+    sprintf(str,"f. -kT log<e\\S-\\betaU\\N>");
+    leg[e++] = strdup(str);
+    sprintf(str,"f. <e\\S-\\betaU\\N>");
+    leg[e++] = strdup(str);
+    sprintf(str,"f. V");
+    leg[e++] = strdup(str);
+    sprintf(str,"f. <Ue\\S-\\betaU\\N>");
+    leg[e++] = strdup(str);
+    for(i=0; i<ngid; i++) {
+      sprintf(str,"f. <U\\sVdW %s\\Ne\\S-\\betaU\\N>",
+             *(groups->grpname[groups->grps[egcENER].nm_ind[i]]));
+      leg[e++] = strdup(str);
+    }
+    if (bDispCorr) {
+      sprintf(str,"f. <U\\sdisp c\\Ne\\S-\\betaU\\N>");
+      leg[e++] = strdup(str);
+    }
+    if (bCharge) {
+      for(i=0; i<ngid; i++) {
+       sprintf(str,"f. <U\\sCoul %s\\Ne\\S-\\betaU\\N>",
+               *(groups->grpname[groups->grps[egcENER].nm_ind[i]]));
+       leg[e++] = strdup(str);
+      }
+      if (bRFExcl) {
+       sprintf(str,"f. <U\\sRF excl\\Ne\\S-\\betaU\\N>");
+       leg[e++] = strdup(str);
+      }
+      if (EEL_FULL(fr->eeltype)) {
+       sprintf(str,"f. <U\\sCoul recip\\Ne\\S-\\betaU\\N>");
+       leg[e++] = strdup(str);
+      }
+    }
+    xvgr_legend(fp_tpi,4+nener,(const char**)leg,oenv);
+    for(i=0; i<4+nener; i++)
+      sfree(leg[i]);
+    sfree(leg);
+  }
+  clear_rvec(x_init);
+  V_all = 0;
+  VembU_all = 0;
+
+  invbinw = 10;
+  nbin = 10;
+  snew(bin,nbin);
+
+  bNotLastFrame = read_first_frame(oenv,&status,opt2fn("-rerun",nfile,fnm),
+                                  &rerun_fr,TRX_NEED_X);
+  frame = 0;
+
+  if (rerun_fr.natoms - (bCavity ? nat_cavity : 0) !=
+      mdatoms->nr - (a_tp1 - a_tp0))
+    gmx_fatal(FARGS,"Number of atoms in trajectory (%d)%s "
+             "is not equal the number in the run input file (%d) "
+             "minus the number of atoms to insert (%d)\n",
+             rerun_fr.natoms,bCavity ? " minus one" : "",
+             mdatoms->nr,a_tp1-a_tp0);
+
+  refvolshift = log(det(rerun_fr.box));
+
+#if ( defined(GMX_IA32_SSE) || defined(GMX_X86_64_SSE) || defined(GMX_X86_64_SSE2) )
+    /* Make sure we don't detect SSE overflow generated before this point */
+    gmx_mm_check_and_reset_overflow();
+#endif
+
+    while (bNotLastFrame)
+    {
+        lambda = rerun_fr.lambda;
+        t = rerun_fr.time;
+        
+        sum_embU = 0;
+        for(e=0; e<nener; e++)
+        {
+            sum_UgembU[e] = 0;
+        }
+        
+        /* Copy the coordinates from the input trajectory */
+        for(i=0; i<rerun_fr.natoms; i++)
+        {
+            copy_rvec(rerun_fr.x[i],state->x[i]);
+        }
+        
+        V = det(rerun_fr.box);
+        logV = log(V);
+        
+        bStateChanged = TRUE;
+        bNS = TRUE;
+        for(step=0; step<nsteps; step++)
+        {
+            /* In parallel all nodes generate all random configurations.
+             * In that way the result is identical to a single cpu tpi run.
+             */
+            if (!bCavity)
+            {
+                /* Random insertion in the whole volume */
+                bNS = (step % inputrec->nstlist == 0);
+                if (bNS)
+                {
+                    /* Generate a random position in the box */
+                    x_init[XX] = gmx_rng_uniform_real(tpi_rand)*state->box[XX][XX];
+                    x_init[YY] = gmx_rng_uniform_real(tpi_rand)*state->box[YY][YY];
+                    x_init[ZZ] = gmx_rng_uniform_real(tpi_rand)*state->box[ZZ][ZZ];
+                }
+                if (inputrec->nstlist == 1)
+                {
+                    copy_rvec(x_init,x_tp);
+                }
+                else
+                {
+                    /* Generate coordinates within |dx|=drmax of x_init */
+                    do
+                    {
+                        dx[XX] = (2*gmx_rng_uniform_real(tpi_rand) - 1)*drmax;
+                        dx[YY] = (2*gmx_rng_uniform_real(tpi_rand) - 1)*drmax;
+                        dx[ZZ] = (2*gmx_rng_uniform_real(tpi_rand) - 1)*drmax;
+                    }
+                    while (norm2(dx) > drmax*drmax);
+                    rvec_add(x_init,dx,x_tp);
+                }
+            }
+            else
+            {
+                /* Random insertion around a cavity location
+                 * given by the last coordinate of the trajectory.
+                 */
+                if (step == 0)
+                {
+                    if (nat_cavity == 1)
+                    {
+                        /* Copy the location of the cavity */
+                        copy_rvec(rerun_fr.x[rerun_fr.natoms-1],x_init);
+                    }
+                    else
+                    {
+                        /* Determine the center of mass of the last molecule */
+                        clear_rvec(x_init);
+                        mass_tot = 0;
+                        for(i=0; i<nat_cavity; i++)
+                        {
+                            for(d=0; d<DIM; d++)
+                            {
+                                x_init[d] +=
+                                    mass_cavity[i]*rerun_fr.x[rerun_fr.natoms-nat_cavity+i][d];
+                            }
+                            mass_tot += mass_cavity[i];
+                        }
+                        for(d=0; d<DIM; d++)
+                        {
+                            x_init[d] /= mass_tot;
+                        }
+                    }
+                }
+                /* Generate coordinates within |dx|=drmax of x_init */
+                do
+                {
+                    dx[XX] = (2*gmx_rng_uniform_real(tpi_rand) - 1)*drmax;
+                    dx[YY] = (2*gmx_rng_uniform_real(tpi_rand) - 1)*drmax;
+                    dx[ZZ] = (2*gmx_rng_uniform_real(tpi_rand) - 1)*drmax;
+                }
+                while (norm2(dx) > drmax*drmax);
+                rvec_add(x_init,dx,x_tp);
+            }
+            
+            if (a_tp1 - a_tp0 == 1)
+            {
+                /* Insert a single atom, just copy the insertion location */
+       copy_rvec(x_tp,state->x[a_tp0]);
+            }
+            else
+            {
+                /* Copy the coordinates from the top file */
+                for(i=a_tp0; i<a_tp1; i++)
+                {
+                    copy_rvec(x_mol[i-a_tp0],state->x[i]);
+                }
+                /* Rotate the molecule randomly */
+                rotate_conf(a_tp1-a_tp0,state->x+a_tp0,NULL,
+                            2*M_PI*gmx_rng_uniform_real(tpi_rand),
+                            2*M_PI*gmx_rng_uniform_real(tpi_rand),
+                            2*M_PI*gmx_rng_uniform_real(tpi_rand));
+                /* Shift to the insertion location */
+                for(i=a_tp0; i<a_tp1; i++)
+                {
+                    rvec_inc(state->x[i],x_tp);
+                }
+            }
+            
+            /* Check if this insertion belongs to this node */
+            bOurStep = TRUE;
+            if (PAR(cr))
+            {
+                switch (inputrec->eI)
+                {
+                case eiTPI:
+                    bOurStep = ((step / inputrec->nstlist) % nnodes == cr->nodeid);
+                    break;
+                case eiTPIC:
+                    bOurStep = (step % nnodes == cr->nodeid);
+                    break;
+                default:
+                    gmx_fatal(FARGS,"Unknown integrator %s",ei_names[inputrec->eI]);
+                }
+            }
+            if (bOurStep)
+            {
+                /* Clear some matrix variables  */
+                clear_mat(force_vir); 
+                clear_mat(shake_vir);
+                clear_mat(vir);
+                clear_mat(pres);
+                
+                /* Set the charge group center of mass of the test particle */
+                copy_rvec(x_init,fr->cg_cm[top->cgs.nr-1]);
+                
+                /* Calc energy (no forces) on new positions.
+                 * Since we only need the intermolecular energy
+                 * and the RF exclusion terms of the inserted molecule occur
+                 * within a single charge group we can pass NULL for the graph.
+                 * This also avoids shifts that would move charge groups
+                 * out of the box.
+                 *
+                 * Some checks above ensure than we can not have
+                 * twin-range interactions together with nstlist > 1,
+                 * therefore we do not need to remember the LR energies.
+                 */
+                /* Make do_force do a single node force calculation */
+                cr->nnodes = 1;
+                do_force(fplog,cr,inputrec,
+                         step,nrnb,wcycle,top,top_global,&top_global->groups,
+                         rerun_fr.box,state->x,&state->hist,
+                         f,force_vir,mdatoms,enerd,fcd,
+                         lambda,NULL,fr,NULL,mu_tot,t,NULL,NULL,FALSE,
+                         GMX_FORCE_NONBONDED |
+                         (bNS ? GMX_FORCE_NS | GMX_FORCE_DOLR : 0) |
+                         (bStateChanged ? GMX_FORCE_STATECHANGED : 0)); 
+                cr->nnodes = nnodes;
+                bStateChanged = FALSE;
+                bNS = FALSE;
+                
+                /* Calculate long range corrections to pressure and energy */
+                calc_dispcorr(fplog,inputrec,fr,step,top_global->natoms,rerun_fr.box,
+                              lambda,pres,vir,&prescorr,&enercorr,&dvdlcorr);
+                /* figure out how to rearrange the next 4 lines MRS 8/4/2009 */
+                enerd->term[F_DISPCORR] = enercorr;
+                enerd->term[F_EPOT] += enercorr;
+                enerd->term[F_PRES] += prescorr;
+                enerd->term[F_DVDL] += dvdlcorr;
+
+                epot = enerd->term[F_EPOT];
+                bEnergyOutOfBounds = FALSE;
+#if ( defined(GMX_IA32_SSE) || defined(GMX_X86_64_SSE) || defined(GMX_X86_64_SSE2) )
+                /* With SSE the energy can overflow, check for this */
+                if (gmx_mm_check_and_reset_overflow())
+                {
+                    if (debug)
+                    {
+                        fprintf(debug,"Found an SSE overflow, assuming the energy is out of bounds\n");
+                    }
+                    bEnergyOutOfBounds = TRUE;
+                }
+#endif
+                /* If the compiler doesn't optimize this check away
+                 * we catch the NAN energies.
+                 * The epot>GMX_REAL_MAX check catches inf values,
+                 * which should nicely result in embU=0 through the exp below,
+                 * but it does not hurt to check anyhow.
+                 */
+                /* Non-bonded Interaction usually diverge at r=0.
+                 * With tabulated interaction functions the first few entries
+                 * should be capped in a consistent fashion between
+                 * repulsion, dispersion and Coulomb to avoid accidental
+                 * negative values in the total energy.
+                 * The table generation code in tables.c does this.
+                 * With user tbales the user should take care of this.
+                 */
+                if (epot != epot || epot > GMX_REAL_MAX)
+                {
+                    bEnergyOutOfBounds = TRUE;
+                }
+                if (bEnergyOutOfBounds)
+                {
+                    if (debug)
+                    {
+                        fprintf(debug,"\n  time %.3f, step %d: non-finite energy %f, using exp(-bU)=0\n",t,step,epot);
+                    }
+                    embU = 0;
+                }
+                else
+                {
+                    embU = exp(-beta*epot);
+                    sum_embU += embU;
+                    /* Determine the weighted energy contributions of each energy group */
+                    e = 0;
+                    sum_UgembU[e++] += epot*embU;
+                    if (fr->bBHAM)
+                    {
+                        for(i=0; i<ngid; i++)
+                        {
+                            sum_UgembU[e++] +=
+                                (enerd->grpp.ener[egBHAMSR][GID(i,gid_tp,ngid)] +
+                                 enerd->grpp.ener[egBHAMLR][GID(i,gid_tp,ngid)])*embU;
+                        }
+                    }
+                    else
+                    {
+                        for(i=0; i<ngid; i++)
+                        {
+                            sum_UgembU[e++] +=
+                                (enerd->grpp.ener[egLJSR][GID(i,gid_tp,ngid)] +
+                                 enerd->grpp.ener[egLJLR][GID(i,gid_tp,ngid)])*embU;
+                        }
+                    }
+                    if (bDispCorr)
+                    {
+                        sum_UgembU[e++] += enerd->term[F_DISPCORR]*embU;
+                    }
+                    if (bCharge)
+                    {
+                        for(i=0; i<ngid; i++)
+                        {
+                            sum_UgembU[e++] +=
+                                (enerd->grpp.ener[egCOULSR][GID(i,gid_tp,ngid)] +
+                                 enerd->grpp.ener[egCOULLR][GID(i,gid_tp,ngid)])*embU;
+                        }
+                        if (bRFExcl)
+                        {
+                            sum_UgembU[e++] += enerd->term[F_RF_EXCL]*embU;
+                        }
+                        if (EEL_FULL(fr->eeltype))
+                        {
+                            sum_UgembU[e++] += enerd->term[F_COUL_RECIP]*embU;
+                        }
+                    }
+                }
+                
+                if (embU == 0 || beta*epot > bU_bin_limit)
+                {
+                    bin[0]++;
+                }
+                else
+                {
+                    i = (int)((bU_logV_bin_limit
+                               - (beta*epot - logV + refvolshift))*invbinw
+                              + 0.5);
+                    if (i < 0)
+                    {
+                        i = 0;
+                    }
+                    if (i >= nbin)
+                    {
+                        realloc_bins(&bin,&nbin,i+10);
+                    }
+                    bin[i]++;
+                }
+                
+                if (debug)
+                {
+                    fprintf(debug,"TPI %7d %12.5e %12.5f %12.5f %12.5f\n",
+                            step,epot,x_tp[XX],x_tp[YY],x_tp[ZZ]);
+                }
+
+                if (dump_pdb && epot <= dump_ener)
+                {
+                    sprintf(str,"t%g_step%d.pdb",t,step);
+                    sprintf(str2,"t: %f step %d ener: %f",t,step,epot);
+                    write_sto_conf_mtop(str,str2,top_global,state->x,state->v,
+                                        inputrec->ePBC,state->box);
+                }
+            }
+        }
+        
+        if (PAR(cr))
+        {
+            /* When running in parallel sum the energies over the processes */
+            gmx_sumd(1,    &sum_embU, cr);
+            gmx_sumd(nener,sum_UgembU,cr);
+        }
+
+        frame++;
+        V_all += V;
+        VembU_all += V*sum_embU/nsteps;
+        
+        if (fp_tpi)
+        {
+            if (bVerbose || frame%10==0 || frame<10)
+            {
+                fprintf(stderr,"mu %10.3e <mu> %10.3e\n",
+                        -log(sum_embU/nsteps)/beta,-log(VembU_all/V_all)/beta);
+            }
+            
+            fprintf(fp_tpi,"%10.3f %12.5e %12.5e %12.5e %12.5e",
+                    t,
+                    VembU_all==0 ? 20/beta : -log(VembU_all/V_all)/beta,
+                    sum_embU==0  ? 20/beta : -log(sum_embU/nsteps)/beta,
+                    sum_embU/nsteps,V);
+            for(e=0; e<nener; e++)
+            {
+                fprintf(fp_tpi," %12.5e",sum_UgembU[e]/nsteps);
+            }
+            fprintf(fp_tpi,"\n");
+            fflush(fp_tpi);
+        }
+        
+        bNotLastFrame = read_next_frame(oenv, status,&rerun_fr);
+    } /* End of the loop  */
+    runtime_end(runtime);
+
+    close_trj(status);
+
+    if (fp_tpi != NULL)
+    {
+        gmx_fio_fclose(fp_tpi);
+    }
+
+    if (fplog != NULL)
+    {
+        fprintf(fplog,"\n");
+        fprintf(fplog,"  <V>  = %12.5e nm^3\n",V_all/frame);
+        fprintf(fplog,"  <mu> = %12.5e kJ/mol\n",-log(VembU_all/V_all)/beta);
+    }
+  
+    /* Write the Boltzmann factor histogram */
+    if (PAR(cr))
+    {
+        /* When running in parallel sum the bins over the processes */
+        i = nbin;
+        global_max(cr,&i);
+        realloc_bins(&bin,&nbin,i);
+        gmx_sumd(nbin,bin,cr);
+    }
+    if (MASTER(cr))
+    {
+        fp_tpi = xvgropen(opt2fn("-tpid",nfile,fnm),
+                          "TPI energy distribution",
+                          "\\betaU - log(V/<V>)","count",oenv);
+        sprintf(str,"number \\betaU > %g: %9.3e",bU_bin_limit,bin[0]);
+        xvgr_subtitle(fp_tpi,str,oenv);
+        xvgr_legend(fp_tpi,2,(const char **)tpid_leg,oenv);
+        for(i=nbin-1; i>0; i--)
+        {
+            bUlogV = -i/invbinw + bU_logV_bin_limit - refvolshift + log(V_all/frame);
+            fprintf(fp_tpi,"%6.2f %10d %12.5e\n",
+                    bUlogV,
+                    (int)(bin[i]+0.5),
+                    bin[i]*exp(-bUlogV)*V_all/VembU_all);
+        }
+        gmx_fio_fclose(fp_tpi);
+    }
+    sfree(bin);
+
+    sfree(sum_UgembU);
+
+    runtime->nsteps_done = frame*inputrec->nsteps;
+
+    return 0;
+}
similarity index 100%
rename from src/mdlib/vcm.c
rename to src/gromacs/mdlib/vcm.c
similarity index 100%
rename from src/mdlib/vsite.c
rename to src/gromacs/mdlib/vsite.c
similarity index 100%
rename from src/mdlib/wall.c
rename to src/gromacs/mdlib/wall.c
diff --git a/src/gromacs/options.h b/src/gromacs/options.h
new file mode 100644 (file)
index 0000000..8d88ab5
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \defgroup module_options Extensible Handling of Options
+ * \ingroup group_utilitymodules
+ * \brief
+ * Provides functionality for handling options.
+ *
+ * <H3>Basic Use</H3>
+ *
+ * Basic interface for providing options is implemented by the Options class
+ * and classes defined in basicoptions.h for specifying individual options.
+ * Only these are needed if a class wants to provide a set of standard options.
+ *
+ * Values for options can be set using option parsers.
+ * Currently, only one is defined: CommandLineParser.
+ * As the name suggests, this parser gets values from command-line arguments.
+ * Multiple parsers can be used in sequence to provide option values from
+ * multiple sources; in such cases, if an option is provided in multiple
+ * sources, new values overwrite any values from previous sources.
+ *
+ * In most cases, it is desirable to be able to provide a help describing the
+ * available options.  When creating an Options object and adding options, it
+ * is possible to add descriptions for individual options as well as for the
+ * whole set of options.  These can then be used to write out a help using one
+ * of the provided help writers.
+ * Currently, only one is defined: AsciiHelpWriter
+ * (implementation is not yet complete).
+ *
+ * <H3>Advanced Use</H3>
+ *
+ * It is possible to extend the module with new option types and/or parsers for
+ * option values.
+ *
+ * To implement new option types, it is necessary to subclass the templates
+ * OptionTemplate and OptionStorageTemplate with the type of the values that
+ * the option should provide as the template argument.  After this is done, it
+ * is possible to add options of this new type using Options::addOption().
+ *
+ * There is limited support for options that need to share information across
+ * instances, e.g., to store values in a shared external data structure or to
+ * provide a global option to set a common setting for all such options,
+ * provided by the OptionsGlobalProperties class.  This mechanism is not
+ * generic, meaning that it is required to change the options module to add
+ * data to this structure.
+ *
+ * To implement new parsers, one can use OptionsAssigner, which provides an
+ * interface to set values in an Options object.
+ *
+ * There is also an interface to iterate over all options in an Options object.
+ * One should implement the OptionsVisitor interface, and then use
+ * OptionsIterator to apply this visitor to the Options object.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ */
+/*! \file
+ * \brief
+ * Public API convenience header for handling of options.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \inpublicapi
+ * \ingroup module_options
+ */
+#ifndef GMX_OPTIONS_H
+#define GMX_OPTIONS_H
+
+#include "options/basicoptions.h"
+#include "options/options.h"
+
+#endif
diff --git a/src/gromacs/options/CMakeLists.txt b/src/gromacs/options/CMakeLists.txt
new file mode 100644 (file)
index 0000000..eef1671
--- /dev/null
@@ -0,0 +1,16 @@
+file(GLOB OPTIONS_SOURCES *.cpp)
+set(LIBGROMACS_SOURCES ${LIBGROMACS_SOURCES} ${OPTIONS_SOURCES} PARENT_SCOPE)
+
+set(OPTIONS_PUBLIC_HEADERS
+    abstractoption.h
+    basicoptions.h
+    optionfiletype.h
+    optionflags.h
+    options.h)
+install(FILES ${OPTIONS_PUBLIC_HEADERS}
+        DESTINATION ${INCL_INSTALL_DIR}/gromacs/options
+        COMPONENT development)
+
+if (BUILD_TESTING)
+    add_subdirectory(tests)
+endif (BUILD_TESTING)
diff --git a/src/gromacs/options/abstractoption.h b/src/gromacs/options/abstractoption.h
new file mode 100644 (file)
index 0000000..f8e2636
--- /dev/null
@@ -0,0 +1,325 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \file
+ * \brief
+ * Defines gmx::AbstractOption and a related template.
+ *
+ * This header defines base classes for option settings that are used with
+ * Options::addOption().  These classes implement the "named parameter"
+ * idiom for specifying option properties.
+ *
+ * These classes also take care of creating and setting up the actual option
+ * objects.
+ *
+ * This header is needed directly only when implementing new option types,
+ * but methods of OptionTemplate are visible even to the normal user through
+ * its subclasses..
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \inlibraryapi
+ * \ingroup module_options
+ */
+#ifndef GMX_OPTIONS_ABSTRACTOPTION_H
+#define GMX_OPTIONS_ABSTRACTOPTION_H
+
+#include <string>
+#include <vector>
+
+#include "optionflags.h"
+
+namespace gmx
+{
+
+class AbstractOptionStorage;
+template <typename T> class OptionStorageTemplate;
+class Options;
+
+/*! \brief
+ * Abstract base class for specifying option properties.
+ *
+ * Concrete classes should normally not derive directly from this class,
+ * but from OptionTemplate instead.  Classes derived from this class
+ * are mainly designed to implement the "named parameter" idiom.  For
+ * efficiency and clarity, these classes should only store values provided to
+ * them.  All error checking and memory management should be postponed to the
+ * point when the actual option is created.
+ *
+ * Subclasses should override createDefaultStorage() to create the correct type
+ * of storage object.
+ *
+ * \ingroup module_options
+ */
+class AbstractOption
+{
+    public:
+        // Virtual only for completeness, in normal use should not be needed.
+        virtual ~AbstractOption() { }
+
+    protected:
+        //! Initializes the name and default values for an option.
+        explicit AbstractOption(const char *name)
+            : _minValueCount(1), _maxValueCount(1),
+              _name(name), _descr(NULL)
+        { }
+
+        /*! \brief
+         * Creates a default storage object for the option.
+         *
+         * \param[in]  options  Option collection object.
+         * \param[out] storage  The created storage object.
+         * \retval     0 if there are no errors.
+         *
+         * This method is called by when creating an option object
+         * The \p options object is used to implement global properties.
+         *
+         * Derived classes should implement the method to create an actual
+         * storage object and populate it with correct values.
+         *
+         * Should only be called by Options::addOption().
+         *
+         * \see AbstractOptionStorage::init()
+         */
+        virtual int createDefaultStorage(Options *options,
+                                         AbstractOptionStorage **storage) const = 0;
+
+        /*! \brief
+         * Creates the description string for the option.
+         *
+         * This function is virtual to allow derived classes to customize the
+         * description programmatically, e.g., by adding the list of allowed
+         * values.
+         * The default implementation simply returns the user-provided
+         * description.
+         */
+        virtual std::string createDescription() const
+        { return _descr ? _descr : ""; }
+
+        //! Sets the description for the option.
+        void setDescription(const char *descr) { _descr = descr; }
+        //! Sets a flag for the option.
+        void setFlag(OptionFlag flag) { _flags.set(flag); }
+        //! Clears a flag for the option.
+        void clearFlag(OptionFlag flag) { _flags.clear(flag); }
+        //! Returns true if the option is vector-valued.
+        bool isVector() const { return hasFlag(efVector); }
+        //! Sets the option to be vector-valued.
+        void setVector()
+        {
+            setFlag(efVector);
+            _minValueCount = 1;
+            if (_maxValueCount == 1)
+            {
+                _maxValueCount = 3;
+            }
+        }
+        //! Sets the required number of values for the option.
+        void setValueCount(int count)
+        {
+            if (!hasFlag(efVector))
+            {
+                _minValueCount = count;
+            }
+            _maxValueCount = count;
+        }
+
+        //! Minimum number of values required for the option.
+        int                     _minValueCount;
+        //! Maximum number of values allowed for the option.
+        int                     _maxValueCount;
+
+    private:
+        //! Returns true if a flag has been set.
+        bool hasFlag(OptionFlag flag) const { return _flags.test(flag); }
+
+        const char             *_name;
+        //! Pointer to description of the option.
+        const char             *_descr;
+        OptionFlags             _flags;
+
+        /*! \brief
+         * Needed to initialize an AbstractOptionStorage object from this class
+         * without otherwise unnecessary accessors.
+         */
+        friend class AbstractOptionStorage;
+        /*! \brief
+         * Needed to be able to call createDefaultStorage().
+         */
+        friend class Options;
+};
+
+/*! \brief
+ * Templated base class for constructing concrete option settings classes.
+ *
+ * \tparam T Assignable type that stores a single option value.
+ * \tparam U Type of the derived class.
+ *
+ * This template is used as a base class like this:
+ * \code
+class ConcreteOption : public OptionTemplate<int, ConcreteOption>
+{
+ * \endcode
+ *
+ * All public functions in this class return \c *this casted to a reference to
+ * \p U.
+ *
+ * For examples of how to use classes derived from this class, see the class
+ * documentation for Options.
+ *
+ * \inpublicapi
+ * \ingroup module_options
+ */
+template <typename T, class U>
+class OptionTemplate : public AbstractOption
+{
+    public:
+        //! Type that stores a single option value.
+        typedef T ValueType;
+        //! Alias for the derived class type.
+        typedef U MyClass;
+        //! Alias for the template class for use in base classes.
+        typedef OptionTemplate<T, U> MyBase;
+
+        /*! \brief
+         * Sets a description for the option.
+         *
+         * \param[in] descr Description to set.
+         *
+         * String in \p descr is copied when the option is created.
+         */
+        MyClass &description(const char *descr)
+        { setDescription(descr); return me(); }
+        //! Hides the option from normal help output.
+        MyClass &hidden() { setFlag(efHidden); return me(); }
+        //! Requires the option to be specified explicitly.
+        MyClass &required() { setFlag(efRequired); return me(); }
+        //! Allows the option to be specified multiple times.
+        MyClass &allowMultiple() { setFlag(efMulti); return me(); }
+        //! Requires exactly \p count values for the option.
+        MyClass &valueCount(int count) { setValueCount(count); return me(); }
+        //! Allows any number of values for the option.
+        MyClass &multiValue() { _maxValueCount = -1; return me(); }
+
+        /*! \brief
+         * Sets a default value for the option.
+         *
+         * \param[in] defaultValue Default value.
+         *
+         * If the option is never set, the default value is copied to the
+         * assigned storage.  Note that if the option is not set and there
+         * is no default value, the storage is not altered, which can also be
+         * used to provide a default value.  The latter method has to be used
+         * if the option can take multiple values.
+         * If required() is specified, only affects the default value shown in
+         * help output.
+         *
+         * \p defaultValue is copied when the option is created.
+         */
+        MyClass &defaultValue(const T &defaultValue)
+        { _defaultValue = &defaultValue; return me(); }
+        /*! \brief
+         * Stores value(s) in memory pointed by \p store.
+         *
+         * \param[in] store  Storage for option value(s).
+         *
+         * The caller is responsible for allocating enough memory such that
+         * the any allowed number of values fits into the array pointed by
+         * \p store.  If there is no maximum allowed number or if the maximum
+         * is inconveniently large, storeVector() should be used.
+         *
+         * The pointer provided should remain valid as long as the associated
+         * Options object exists.
+         */
+        MyClass &store(T *store)
+        { setFlag(efExternalStore); _store = store; return me(); }
+        /*! \brief
+         * Stores a pointer to array of values.
+         *
+         * \param[in] store   Storage for a pointer to an array of values.
+         * \param[in] nvalptr Storage for the number of values.
+         *
+         * The pointer written to *store should be freed by the caller using
+         * delete[].
+         * Either of the input parameters can be NULL, in which case the
+         * corresponding value is not stored.
+         * The pointers provided should remain valid as long as the associated
+         * Options object exists.
+         *
+         * This function is deprecated, but may be convenient for interfacing
+         * with legacy code.
+         */
+        MyClass &storeArray(T **store, int *nvalptr)
+        { setFlag(efExternalStoreArray); _storeArray = store; _nvalptr = nvalptr; return me(); }
+        /*! \brief
+         * Stores option values in the provided vector.
+         *
+         * \param[in] store  Vector to store option values in.
+         *
+         * The caller should not make any assumptions about the contents of the
+         * vector while options are being parsed.
+         *
+         * The pointer provided should remain valid as long as the associated
+         * Options object exists.
+         */
+        MyClass &storeVector(std::vector<T> *store)
+        { setFlag(efExternalValueVector); _storeVector = store; return me(); }
+
+    protected:
+        //! Initializes the name and default values for an option.
+        explicit OptionTemplate(const char *name)
+            : AbstractOption(name), _defaultValue(NULL), _store(NULL),
+              _storeArray(NULL), _nvalptr(NULL), _storeVector(NULL)
+        { }
+
+        /*! \brief
+         * Returns a pointer to user-specified default value, or NULL if there
+         * is none.
+         */
+        const T *defaultValue() const { return _defaultValue; }
+        //! Returns \p *this casted into MyClass to reduce typing.
+        MyClass &me() { return static_cast<MyClass &>(*this); }
+
+    private:
+        const T                *_defaultValue;
+        T                      *_store;
+        T                     **_storeArray;
+        int                    *_nvalptr;
+        std::vector<T>         *_storeVector;
+
+        /*! \brief
+         * Needed to initialize storage from this class without otherwise
+         * unnecessary accessors.
+         */
+        friend class OptionStorageTemplate<T>;
+};
+
+} // namespace gmx
+
+#endif
diff --git a/src/gromacs/options/abstractoptionstorage.cpp b/src/gromacs/options/abstractoptionstorage.cpp
new file mode 100644 (file)
index 0000000..1ad13ba
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * Implements gmx::AbstractOptionStorage.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_options
+ */
+#include "gromacs/options/abstractoptionstorage.h"
+
+#include <cassert>
+
+#include "gromacs/errorreporting/abstracterrorreporter.h"
+#include "gromacs/fatalerror/fatalerror.h"
+#include "gromacs/options/abstractoption.h"
+#include "gromacs/options/optionflags.h"
+
+namespace gmx
+{
+
+/********************************************************************
+ * AbstractOptionStorage
+ */
+
+AbstractOptionStorage::AbstractOptionStorage()
+    : _minValueCount(0), _maxValueCount(0), _currentValueCount(-1),
+      _options(NULL)
+{
+}
+
+AbstractOptionStorage::~AbstractOptionStorage()
+{
+}
+
+int AbstractOptionStorage::init(const AbstractOption &settings,
+                                Options *options)
+{
+    // We add user-provided flags to the ones possibly set by the subclass.
+    _flags |= settings._flags;
+    _minValueCount = settings._minValueCount;
+    _maxValueCount = settings._maxValueCount;
+    _options = options;
+
+    // If the maximum number of values is not known, storage to
+    // caller-allocated memory is unsafe.
+    if ((_maxValueCount < 0 || hasFlag(efMulti)) && hasFlag(efExternalStore))
+    {
+        GMX_ERROR(eeInvalidValue,
+                  "Cannot set user-allocated storage for arbitrary number of values");
+    }
+    // Check that user has not provided incorrect values for vectors.
+    if (hasFlag(efVector) && (_minValueCount > 1 || _maxValueCount < 1))
+    {
+        GMX_ERROR(eeInvalidValue,
+                  "Inconsistent value counts for vector values");
+    }
+
+    if (settings._name != NULL)
+    {
+        _name  = settings._name;
+    }
+    _descr = settings.createDescription();
+
+    return 0;
+}
+
+int AbstractOptionStorage::startSource()
+{
+    setFlag(efHasDefaultValue);
+    return 0;
+}
+
+int AbstractOptionStorage::startSet(AbstractErrorReporter *errors)
+{
+    if (hasFlag(efHasDefaultValue))
+    {
+        clearFlag(efHasDefaultValue);
+        clear();
+    }
+    else if (isSet() && !hasFlag(efMulti))
+    {
+        errors->error("Option specified multiple times");
+        return eeInvalidInput;
+    }
+    _currentValueCount = 0;
+    return 0;
+}
+
+int AbstractOptionStorage::appendValue(const std::string &value,
+                                       AbstractErrorReporter *errors)
+{
+    assert(_currentValueCount >= 0);
+    if (!hasFlag(efConversionMayNotAddValues) && _maxValueCount >= 0
+        && _currentValueCount >= _maxValueCount)
+    {
+        errors->warning("Ignoring extra value: " + value);
+        return eeInvalidInput;
+    }
+    return convertValue(value, errors);
+}
+
+int AbstractOptionStorage::finishSet(AbstractErrorReporter *errors)
+{
+    assert(_currentValueCount >= 0);
+
+    setFlag(efSet);
+    // TODO: Remove invalid values if there are too few
+    int rc = processSet(_currentValueCount, errors);
+    if (!hasFlag(efDontCheckMinimumCount)
+        && _currentValueCount < _minValueCount)
+    {
+        errors->error("Too few (valid) values");
+        rc = eeInvalidInput;
+    }
+    _currentValueCount = -1;
+    return rc;
+}
+
+int AbstractOptionStorage::finish(AbstractErrorReporter *errors)
+{
+    assert(_currentValueCount == -1);
+    int rc = processAll(errors);
+    if (hasFlag(efRequired) && !isSet())
+    {
+        errors->error("Required option '" + _name + "' not set");
+        rc = eeInconsistentInput;
+    }
+    return rc;
+}
+
+int AbstractOptionStorage::incrementValueCount()
+{
+    if (_currentValueCount == -1)
+    {
+        return 0;
+    }
+    if (_maxValueCount >= 0 && _currentValueCount >= _maxValueCount)
+    {
+        return eeInvalidInput;
+    }
+    ++_currentValueCount;
+    return 0;
+}
+
+} // namespace gmx
diff --git a/src/gromacs/options/abstractoptionstorage.h b/src/gromacs/options/abstractoptionstorage.h
new file mode 100644 (file)
index 0000000..3da2f3f
--- /dev/null
@@ -0,0 +1,265 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \libinternal \file
+ * \brief
+ * Declares gmx::AbstractOptionStorage.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \inlibraryapi
+ * \ingroup module_options
+ */
+#ifndef GMX_OPTIONS_ABSTRACTOPTIONSTORAGE_H
+#define GMX_OPTIONS_ABSTRACTOPTIONSTORAGE_H
+
+#include <string>
+
+#include "optionflags.h"
+
+namespace gmx
+{
+
+class AbstractErrorReporter;
+class AbstractOption;
+class Options;
+
+/*! \libinternal \brief
+ * Abstract base class for converting, validating, and storing option values.
+ *
+ * This class should normally not be subclassed directly, but the
+ * OptionStorageTemplate should be used instead.  The templated class provides
+ * basic functionality for most of the pure virtual methods, and also
+ * integrates well with option setting objects derived from OptionTemplate.
+ *
+ * \inlibraryapi
+ * \ingroup module_options
+ *
+ * \internal
+ * This class really consists of two parts: the public interface that is
+ * used by the internal implementation of the options module, and the
+ * interface that derived classes use to provide type-dependent functionality.
+ * The latter consists of a few pure virtual methods, of which a few simple
+ * query methods are also part of the module-internal interface, others are
+ * protected and called by the non-virtual methods when needed.
+ * The reason why these two roles are in one class is twofold:
+ *  -# Both the derived classes and the internal module implementation may need
+ *     access to the same information like the allowed number of values and the
+ *     name of the option.
+ *  -# Having only one class is consistent with the structure used for options
+ *     settings objects: there is very direct correspondence between
+ *     AbstractOption and AbstractOptionStorage and between OptionTemplate and
+ *     OptionStorageTemplate.
+ */
+class AbstractOptionStorage
+{
+    public:
+        virtual ~AbstractOptionStorage();
+
+        /*! \brief
+         * Initializes the storage object from the settings object.
+         *
+         * \param[in] settings  Option settings.
+         * \param[in] options   Option collection that will contain the
+         *     option.
+         * \retval 0 on success.
+         */
+        int init(const AbstractOption &settings, Options *options);
+
+        //! Returns true if the option has been set.
+        bool isSet() const { return hasFlag(efSet); }
+        //! Returns true if the option is a boolean option.
+        bool isBoolean() const { return hasFlag(efBoolean); }
+        //! Returns true if the option is a file option.
+        bool isFile() const { return hasFlag(efFile); }
+        //! Returns true if the option is a hidden option.
+        bool isHidden() const { return hasFlag(efHidden); }
+        //! Returns the name of the option.
+        const std::string &name() const { return _name; }
+        //! Returns the description of the option.
+        const std::string &description() const { return _descr; }
+        /*! \brief
+         * Returns a short string describing the type of the option.
+         *
+         * The caller is free to discard the returned string.
+         */
+        virtual const char *typeString() const = 0;
+        /*! \brief
+         * Returns the number of option values added so far.
+         */
+        virtual int valueCount() const = 0;
+        /*! \brief
+         * Returns the i'th value formatted as a string.
+         */
+        virtual std::string formatValue(int i) const = 0;
+
+        /*! \brief
+         * Starts adding values from a new source for the option.
+         *
+         * \retval 0 on success.
+         *
+         * This marks the vurrent value of the option as a default value,
+         * causing next call to startSet() to clear it.  This allows values
+         * from the new source to overwrite old values.
+         */
+        int startSource();
+        /*! \brief
+         * Starts adding a new set of values for the option.
+         *
+         * \param[in] errors Error reporter for errors.
+         * \retval 0 on success.
+         *
+         * If the parameter is specified multiple times, startSet() should be
+         * called before the values for each instance.
+         */
+        int startSet(AbstractErrorReporter *errors);
+        /*! \brief
+         * Adds a new value for the option, converting it from a string.
+         *
+         * \param[in] value  String value to convert.
+         * \param[in] errors Error reporter for errors.
+         * \retval 0 if the value was successfully converted and added.
+         */
+        int appendValue(const std::string &value,
+                        AbstractErrorReporter *errors);
+        /*! \brief
+         * Performs validation and/or actions once a set of values has been
+         * added.
+         *
+         * \param[in] errors Error reporter for errors.
+         * \retval 0 on success.
+         *
+         * If the parameter is specified multiple times, finishSet() should be
+         * called after the values for each instance.
+         */
+        int finishSet(AbstractErrorReporter *errors);
+        /*! \brief
+         * Performs validation and/or actions once all values have been added.
+         *
+         * \param[in] errors Error reporter for errors.
+         * \retval 0 on success.
+         *
+         * This function should be called after all values have been provided
+         * with appendValue().  Calls finishSet() if needed.
+         */
+        int finish(AbstractErrorReporter *errors);
+
+    protected:
+        //! Creates an uninitialized storage object.
+        AbstractOptionStorage();
+
+        //! Returns true if the given flag is set.
+        bool hasFlag(OptionFlag flag) const { return _flags.test(flag); }
+        //! Sets the given flag.
+        void setFlag(OptionFlag flag) { return _flags.set(flag); }
+        //! Clears the given flag.
+        void clearFlag(OptionFlag flag) { return _flags.clear(flag); }
+
+        //! Returns the minimum number of values required in one set.
+        int minValueCount() const { return _minValueCount; }
+        //! Returns the maximum allowed number of values in one set (-1 = no limit).
+        int maxValueCount() const { return _maxValueCount; }
+
+        //! Returns the Options object that houses the option.
+        Options &hostOptions() { return *_options; }
+        //! \copydoc hostOptions()
+        const Options &hostOptions() const { return *_options; }
+
+        /*! \brief
+         * Removes all values from the storage.
+         *
+         * This function is called also before the first value is added,
+         * allowing the storage to set a default value in initialization.
+         */
+        virtual void clear() = 0;
+        /*! \brief
+         * Adds a new value, converting it from a string.
+         *
+         * \param[in] value  String value to convert.
+         * \param[in] errors Error reporter object.
+         * \retval 0 if the value was successfully converted.
+         *
+         * This function may be called multiple times if the underlying
+         * option is defined to accept multiple values.
+         */
+        virtual int convertValue(const std::string &value,
+                                 AbstractErrorReporter *errors) = 0;
+        /*! \brief
+         * Performs validation and/or actions once a set of values has been
+         * added.
+         *
+         * \param[in] nvalues  Number of values added since the previous call
+         *      to finishSet().
+         * \param[in] errors Error reporter object.
+         * \retval 0 on success.
+         *
+         * This function may be called multiple times of the underlying option
+         * can be specified multiple times.
+         */
+        virtual int processSet(int nvalues, AbstractErrorReporter *errors) = 0;
+        /*! \brief
+         * Performs validation and/or actions once all values have been added.
+         *
+         * \param[in] errors Error reporter object.
+         * \retval 0 if final option values are valid.
+         *
+         * This function is always called once.
+         */
+        virtual int processAll(AbstractErrorReporter *errors) = 0;
+
+        /*! \brief
+         * Increments the number of values for the current set.
+         *
+         * \retval 0 on success.
+         * \retval ::eeInvalidInput if the maximum value count has been reached.
+         */
+        int incrementValueCount();
+
+    private:
+        std::string             _name;
+        std::string             _descr;
+        //! Flags for the option.
+        OptionFlags             _flags;
+        //! Minimum number of values required (in one set).
+        int                     _minValueCount;
+        //! Maximum allowed number of values (in one set), or -1 if no limit.
+        int                     _maxValueCount;
+        //! Number of values added so far to the current set, or -1 if not in one.
+        int                     _currentValueCount;
+        //! Parent Options object.
+        Options                *_options;
+
+        // Disallow copy and assign.
+        AbstractOptionStorage(const AbstractOptionStorage &);
+        void operator =(const AbstractOptionStorage &);
+};
+
+} // namespace gmx
+
+#endif
diff --git a/src/gromacs/options/asciihelpwriter-impl.h b/src/gromacs/options/asciihelpwriter-impl.h
new file mode 100644 (file)
index 0000000..6976e51
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * Declares private implementation class for gmx::AsciiHelpWriter.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_options
+ */
+#ifndef GMX_OPTIONS_ASCIIHELPWRITER_IMPL_HPP
+#define GMX_OPTIONS_ASCIIHELPWRITER_IMPL_HPP
+
+#include "asciihelpwriter.h"
+
+#include "../utility/flags.h"
+
+namespace gmx
+{
+
+class Options;
+
+/*! \internal \brief
+ * Private implementation class for AsciiHelpWriter.
+ *
+ * \ingroup module_options
+ */
+class AsciiHelpWriter::Impl
+{
+    public:
+        /*! \brief
+         * Possible flags for controlling output.
+         */
+        enum Flag
+        {
+            efShowDescriptions  = 1<<0,
+            efShowHidden        = 1<<1
+        };
+
+        //! Sets the Options object to use for generating help.
+        explicit Impl(const Options &options);
+
+        //! Options object to use for generating help.
+        const Options          &_options;
+        //! Flags for controlling what to write.
+        FlagsTemplate<Flag>     _flags;
+};
+
+/*! \internal \brief
+ * Helper object for writing section descriptions to help.
+ *
+ * \ingroup module_options
+ */
+class AsciiDescriptionWriter : public OptionsVisitor
+{
+    public:
+        //! Creates a helper object for writing section descriptions.
+        explicit AsciiDescriptionWriter(FILE *fp) : _fp(fp) {}
+
+        virtual void visitSubSection(const Options &section);
+        virtual void visitOption(const OptionInfo & /*option*/) { }
+
+    private:
+        FILE                   *_fp;
+};
+
+/*! \internal \brief
+ * Helper object for writing help for file parameters.
+ *
+ * \ingroup module_options
+ */
+class AsciiFileParameterWriter : public OptionsVisitor
+{
+    public:
+        //! Creates a helper object for writing file parameters.
+        explicit AsciiFileParameterWriter(FILE *fp)
+            : _fp(fp), _bFirst(true)
+        {
+        }
+
+        //! Returns true if anything was written out.
+        bool didOutput() const { return !_bFirst; }
+
+        virtual void visitSubSection(const Options &section);
+        virtual void visitOption(const OptionInfo &option);
+
+    private:
+        FILE                   *_fp;
+        bool                    _bFirst;
+};
+
+/*! \internal \brief
+ * Helper object for writing help for non-file parameters.
+ *
+ * \ingroup module_options
+ */
+class AsciiParameterWriter : public OptionsVisitor
+{
+    public:
+        //! Creates a helper object for writing non-file parameters.
+        explicit AsciiParameterWriter(FILE *fp)
+            : _fp(fp), _bFirst(true), _bShowHidden(false)
+        {
+        }
+
+        //! Sets the writer to show hidden options.
+        void setShowHidden(bool bSet)
+        {
+            _bShowHidden = bSet;
+        }
+        //! Returns true if anything was written out.
+        bool didOutput() const { return !_bFirst; }
+
+        virtual void visitSubSection(const Options &section);
+        virtual void visitOption(const OptionInfo &option);
+
+    private:
+        FILE                   *_fp;
+        bool                    _bFirst;
+        bool                    _bShowHidden;
+};
+
+} // namespace gmx
+
+#endif
diff --git a/src/gromacs/options/asciihelpwriter.cpp b/src/gromacs/options/asciihelpwriter.cpp
new file mode 100644 (file)
index 0000000..f19a263
--- /dev/null
@@ -0,0 +1,279 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * Implements gmx::AsciiHelpWriter.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_options
+ */
+#include "gromacs/options/asciihelpwriter.h"
+
+#include <cstdio>
+#include <cstdlib>
+
+#include "gromacs/options/options.h"
+#include "gromacs/options/optionsvisitor.h"
+
+#include "asciihelpwriter-impl.h"
+
+namespace gmx
+{
+
+/********************************************************************
+ * AsciiHelpWriter::Impl
+ */
+
+AsciiHelpWriter::Impl::Impl(const Options &options)
+    : _options(options)
+{
+}
+
+
+/********************************************************************
+ * AsciiDescriptionWriter
+ */
+
+void AsciiDescriptionWriter::visitSubSection(const Options &section)
+{
+    if (!section.description().empty())
+    {
+        fprintf(_fp, "\n");
+        const std::string &title = section.title();
+        if (!title.empty())
+        {
+            fprintf(_fp, "%s\n\n", title.c_str());
+        }
+        // TODO: Wrap lines and do markup substitutions.
+        fprintf(_fp, "%s\n\n", section.description().c_str());
+    }
+    OptionsIterator(section).acceptSubSections(this);
+}
+
+
+/********************************************************************
+ * AsciiFileParameterWriter
+ */
+
+void AsciiFileParameterWriter::visitSubSection(const Options &section)
+{
+    OptionsIterator iterator(section);
+    iterator.acceptSubSections(this);
+    iterator.acceptOptions(this);
+}
+
+void AsciiFileParameterWriter::visitOption(const OptionInfo &option)
+{
+    if (!option.isFile())
+    {
+        return;
+    }
+
+    if (_bFirst)
+    {
+        fprintf(_fp, "%6s %12s  %-12s %s\n",
+                "Option", "Filename", "Type", "Description");
+        fprintf(_fp, "------------------------------------------------------------\n");
+        _bFirst = false;
+    }
+
+    std::string optionLine("-");
+    optionLine.reserve(30 + option.description().size());
+    optionLine.append(option.name()).append(" ");
+    if (optionLine.size() < 11)
+    {
+        optionLine.resize(11, ' ');
+    }
+    bool bTypePrinted = false;
+    size_t lineStart = 0;
+    for (int i = 0; i < option.valueCount(); ++i)
+    {
+        if (i > 0)
+        {
+            optionLine.append("\n");
+            lineStart = optionLine.size();
+            optionLine.append(11, ' ');
+        }
+        optionLine.append(option.formatValue(i)).append(" ");
+        // TODO: Do eliding
+        if (optionLine.size() <= lineStart + 21)
+        {
+            optionLine.resize(lineStart + 21, ' ');
+            if (!bTypePrinted)
+            {
+                optionLine.append(option.type()).append(" ");
+                bTypePrinted = true;
+            }
+        }
+    }
+    if (!bTypePrinted)
+    {
+        optionLine.append("\n");
+        lineStart = optionLine.size();
+        optionLine.append(21, ' ');
+        optionLine.append(option.type()).append(" ");
+    }
+    if (optionLine.size() > lineStart + 34)
+    {
+        if (!option.description().empty())
+        {
+            optionLine.append("\n");
+            optionLine.append(34, ' ');
+        }
+    }
+    else
+    {
+        optionLine.resize(lineStart + 34, ' ');
+    }
+    // TODO: Markup substitution.
+    optionLine.append(option.description());
+    // TODO: Wrap lines.
+    fprintf(_fp, "%s\n", optionLine.c_str());
+}
+
+
+/********************************************************************
+ * AsciiParameterWriter
+ */
+
+void AsciiParameterWriter::visitSubSection(const Options &section)
+{
+    OptionsIterator iterator(section);
+    iterator.acceptSubSections(this);
+    iterator.acceptOptions(this);
+}
+
+void AsciiParameterWriter::visitOption(const OptionInfo &option)
+{
+    if (option.isFile() || (!_bShowHidden && option.isHidden()))
+    {
+        return;
+    }
+
+    if (_bFirst)
+    {
+        fprintf(_fp, "%-12s %-6s %-6s  %s\n",
+                "Option", "Type", "Value", "Description");
+        fprintf(_fp, "----------------------------------------------------\n");
+        _bFirst = false;
+    }
+
+    std::string optionLine("-");
+    optionLine.reserve(30 + option.description().size());
+    if (option.isBoolean())
+    {
+        optionLine.append("[no]");
+    }
+    optionLine.append(option.name()).append(" ");
+    if (optionLine.size() < 13)
+    {
+        optionLine.resize(13, ' ');
+    }
+    optionLine.append(option.type()).append(" ");
+    if (optionLine.size() < 20)
+    {
+        optionLine.resize(20, ' ');
+    }
+    optionLine.append(option.formatValues()).append(" ");
+    if (optionLine.size() > 28)
+    {
+        // TODO: Wrap lines / do eliding
+        if (!option.description().empty())
+        {
+            optionLine.append("\n");
+            optionLine.append(28, ' ');
+        }
+    }
+    else
+    {
+        optionLine.resize(28, ' ');
+    }
+    // TODO: Markup substitution.
+    optionLine.append(option.description());
+    // TODO: Wrap lines.
+    fprintf(_fp, "%s\n", optionLine.c_str());
+}
+
+/********************************************************************
+ * AsciiHelpWriter
+ */
+
+AsciiHelpWriter::AsciiHelpWriter(const Options &options)
+    : _impl(new Impl(options))
+{
+}
+
+AsciiHelpWriter::~AsciiHelpWriter()
+{
+    delete _impl;
+}
+
+AsciiHelpWriter &AsciiHelpWriter::setShowHidden(bool bSet)
+{
+    _impl->_flags.set(Impl::efShowHidden, bSet);
+    return *this;
+}
+
+AsciiHelpWriter &AsciiHelpWriter::setShowDescriptions(bool bSet)
+{
+    _impl->_flags.set(Impl::efShowDescriptions, bSet);
+    return *this;
+}
+
+int AsciiHelpWriter::writeHelp(FILE *fp)
+{
+    if (_impl->_flags.test(Impl::efShowDescriptions))
+    {
+        fprintf(fp, "DESCRIPTION\n"
+                    "-----------\n");
+        AsciiDescriptionWriter(fp).visitSubSection(_impl->_options);
+    }
+    {
+        AsciiFileParameterWriter writer(fp);
+        writer.visitSubSection(_impl->_options);
+        if (writer.didOutput())
+        {
+            fprintf(fp, "\n");
+        }
+    }
+    {
+        AsciiParameterWriter writer(fp);
+        writer.setShowHidden(_impl->_flags.test(Impl::efShowHidden));
+        writer.visitSubSection(_impl->_options);
+        if (writer.didOutput())
+        {
+            fprintf(fp, "\n");
+        }
+    }
+    return 0;
+}
+
+} // namespace gmx
diff --git a/src/gromacs/options/asciihelpwriter.h b/src/gromacs/options/asciihelpwriter.h
new file mode 100644 (file)
index 0000000..255de4c
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \file
+ * \brief
+ * Declares gmx::AsciiHelpWriter.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \inpublicapi
+ * \ingroup module_options
+ */
+#ifndef GMX_OPTIONS_ASCIIHELPWRITER_H
+#define GMX_OPTIONS_ASCIIHELPWRITER_H
+
+#include <cstdio>
+
+namespace gmx
+{
+
+class Options;
+
+/*! \brief
+ * Writes help information for Options in ascii format.
+ *
+ * \inpublicapi
+ * \ingroup module_options
+ */
+class AsciiHelpWriter
+{
+    public:
+        /*! \brief
+         * Creates an object that writer ascii-formatted help for Options.
+         *
+         * \param[in] options  Options for which help should be printed.
+         */
+        explicit AsciiHelpWriter(const Options &options);
+        ~AsciiHelpWriter();
+
+        /*! \brief
+         * Sets whether hidden options are shown in the help.
+         */
+        AsciiHelpWriter &setShowHidden(bool bShow);
+        /*! \brief
+         * Sets whether long descriptions for sections are shown in the help.
+         */
+        AsciiHelpWriter &setShowDescriptions(bool bShow);
+
+        /*! \brief
+         * Writes the help.
+         *
+         * \param[in] fp  File to write the help to.
+         * \retval 0 on success.
+         */
+        int writeHelp(FILE *fp);
+
+    private:
+        class Impl;
+
+        Impl                   *_impl;
+
+        // Disallow copy and assign.
+        AsciiHelpWriter(const AsciiHelpWriter &);
+        void operator =(const AsciiHelpWriter &);
+};
+
+} // namespace gmx
+
+#endif
diff --git a/src/gromacs/options/basicoptions.cpp b/src/gromacs/options/basicoptions.cpp
new file mode 100644 (file)
index 0000000..ef36f9d
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * Implements classes in basicoptions.h.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_options
+ */
+#include "gromacs/options/basicoptions.h"
+
+#include "basicoptionstorage.h"
+
+namespace gmx
+{
+
+/********************************************************************
+ * BooleanOption
+ */
+
+int BooleanOption::createDefaultStorage(Options *options,
+                                        AbstractOptionStorage **storage) const
+{
+    return createOptionStorage<BooleanOption, BooleanOptionStorage>(this, options, storage);
+}
+
+/********************************************************************
+ * IntegerOption
+ */
+
+int IntegerOption::createDefaultStorage(Options *options,
+                                        AbstractOptionStorage **storage) const
+{
+    return createOptionStorage<IntegerOption, IntegerOptionStorage>(this, options, storage);
+}
+
+/********************************************************************
+ * DoubleOption
+ */
+
+int DoubleOption::createDefaultStorage(Options *options,
+                                       AbstractOptionStorage **storage) const
+{
+    return createOptionStorage<DoubleOption, DoubleOptionStorage>(this, options, storage);
+}
+
+/********************************************************************
+ * StringOption
+ */
+
+int StringOption::createDefaultStorage(Options *options,
+                                       AbstractOptionStorage **storage) const
+{
+    return createOptionStorage<StringOption, StringOptionStorage>(this, options, storage);
+}
+
+std::string StringOption::createDescription() const
+{
+    std::string value(MyBase::createDescription());
+
+    if (_enumValues != NULL)
+    {
+        value.append(": ");
+        for (int i = 0; _enumValues[i] != NULL; ++i)
+        {
+            value.append(_enumValues[i]);
+            if (_enumValues[i + 1] != NULL)
+            {
+                value.append(_enumValues[i + 2] != NULL ? ", " : ", or ");
+            }
+        }
+    }
+    return value;
+}
+
+/********************************************************************
+ * FileNameOption
+ */
+
+int FileNameOption::createDefaultStorage(Options *options,
+                                         AbstractOptionStorage **storage) const
+{
+    return createOptionStorage<FileNameOption, FileNameOptionStorage>(this, options, storage);
+}
+
+} // namespace gmx
diff --git a/src/gromacs/options/basicoptions.h b/src/gromacs/options/basicoptions.h
new file mode 100644 (file)
index 0000000..dc34567
--- /dev/null
@@ -0,0 +1,309 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \file
+ * \brief
+ * Declares option settings objects for basic option types.
+ *
+ * Together with options.h, this header forms the part of the public API
+ * that most classes will use to provide options.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \inpublicapi
+ * \ingroup module_options
+ */
+#ifndef GMX_OPTIONS_BASICOPTIONS_H
+#define GMX_OPTIONS_BASICOPTIONS_H
+
+#include <cassert>
+
+#include <string>
+
+#include "abstractoption.h"
+#include "optionfiletype.h"
+
+namespace gmx
+{
+
+class IntegerOptionStorage;
+class DoubleOptionStorage;
+class StringOptionStorage;
+class FileNameOptionStorage;
+class Options;
+
+/*! \addtogroup module_options
+ * \{
+ */
+
+/*! \brief
+ * Specifies an option that provides boolean values.
+ *
+ * Example:
+ * \code
+bool  bPBC;
+using gmx::BooleanOption;
+options.addOption(BooleanOption("pbc").store(&bPBC));
+ * \endcode
+ *
+ * \inpublicapi
+ */
+class BooleanOption : public OptionTemplate<bool, BooleanOption>
+{
+    public:
+        //! Initializes an option with the given name.
+        explicit BooleanOption(const char *name) : MyBase(name)
+        {
+            setFlag(efBoolean);
+        }
+
+    protected:
+        virtual int createDefaultStorage(Options *options,
+                                         AbstractOptionStorage **storage) const;
+};
+
+/*! \brief
+ * Specifies an option that provides integer values.
+ *
+ * Examples:
+ * \code
+using gmx::IntegerOption;
+// Simple option
+int  rcut = 0;
+options.addOption(IntegerOption("rcut").store(&rcut));
+// Vector-valued option
+int  box[3] = {1, 1, 1};  // Default value
+options.addOption(IntegerOption("box").store(box).vector());
+ * \endcode
+ *
+ * \inpublicapi
+ */
+class IntegerOption : public OptionTemplate<int, IntegerOption>
+{
+    public:
+        //! Initializes an option with the given name.
+        explicit IntegerOption(const char *name) : MyBase(name) {}
+
+        /*! \brief
+         * Sets the option to return a vector value.
+         *
+         * A vector value returns a fixed number of values, the default being
+         * three (can be changed with valueCount()).  However, it also accepts
+         * a single value, in which case the value is used to fill the whole
+         * vector.
+         */
+        MyClass &vector() { setVector(); return me(); }
+
+    protected:
+        virtual int createDefaultStorage(Options *options,
+                                         AbstractOptionStorage **storage) const;
+
+        /*! \brief
+         * Needed to initialize IntegerOptionStorage from this class without
+         * otherwise unnecessary accessors.
+         */
+        friend class IntegerOptionStorage;
+};
+
+/*! \brief
+ * Specifies an option that provides floating-point (double) values.
+ *
+ * \inpublicapi
+ */
+class DoubleOption : public OptionTemplate<double, DoubleOption>
+{
+    public:
+        //! Initializes an option with the given name.
+        explicit DoubleOption(const char *name) : MyBase(name), _bTime(false)
+        {
+        }
+
+        //! \copydoc IntegerOption::vector()
+        MyClass &vector() { setVector(); return me(); }
+        /*! \brief
+         * Sets the option to obey time conversion rules.
+         */
+        MyClass &timeValue() { _bTime = true; return me(); }
+
+    private:
+        virtual int createDefaultStorage(Options *options,
+                                         AbstractOptionStorage **storage) const;
+
+        bool _bTime;
+
+        /*! \brief
+         * Needed to initialize DoubleOptionStorage from this class without
+         * otherwise unnecessary accessors.
+         */
+        friend class DoubleOptionStorage;
+};
+
+/*! \brief
+ * Specifies an option that provides string values.
+ *
+ * Examples:
+ * \code
+using gmx::StringOption;
+// Simple option
+std::string  str;
+options.addOption(StringOption("str").store(&str));
+// Option that only accepts predefined values
+const char * const  allowed[] = { "atom", "residue", "molecule", NULL };
+std::string  str;
+int          type;
+options.addOption(StringOption("type").enumValue(allowed).store(&str)
+                     .storeEnumIndex(&type));
+ * \endcode
+ *
+ * \inpublicapi
+ */
+class StringOption : public OptionTemplate<std::string, StringOption>
+{
+    public:
+        //! Initializes an option with the given name.
+        explicit StringOption(const char *name)
+            : MyBase(name), _enumValues(NULL), _defaultEnumIndex(-1),
+              _enumIndexStore(NULL)
+        {}
+
+        /*! \brief
+         * Sets the option to only accept one of a fixed set of strings.
+         *
+         * \param[in] values  Array of strings to accept, terminated with a
+         *     NULL value.
+         *
+         * Also accepts prefixes of the strings; if a prefix matches more than
+         * one of the possible strings, the shortest one is used (in a tie, the
+         * first one is).
+         *
+         * It is not possible to provide multiple values for an option with
+         * this property set, i.e., valueCount() and similar attributes cannot
+         * be set.
+         *
+         * The strings are copied once the option is created.
+         */
+        MyClass &enumValue(const char *const *values)
+        { _enumValues = values; return me(); }
+        /*! \brief
+         * Sets the default value using an index into the enumeration table.
+         *
+         * Cannot be specified without enumValue().
+         */
+        MyClass &defaultEnumIndex(int index)
+        { assert(index >= 0); _defaultEnumIndex = index; return me(); }
+        /*! \brief
+         * Stores the index of the selected value into the provided memory
+         * location.
+         *
+         * The index (zero-based) of the selected value in the array \p values
+         * provided to enumValues() is written into \p *store after the
+         * option gets its value.  If the option has not been provided,
+         * and there is no default value, -1 is stored.
+         *
+         * Cannot be specified without enumValue().
+         */
+        MyClass &storeEnumIndex(int *store)
+        { _enumIndexStore = store; return me(); }
+
+    protected:
+        virtual int createDefaultStorage(Options *options,
+                                         AbstractOptionStorage **storage) const;
+        virtual std::string createDescription() const;
+
+    private:
+        const char *const      *_enumValues;
+        int                     _defaultEnumIndex;
+        int                    *_enumIndexStore;
+
+        /*! \brief
+         * Needed to initialize StringOptionStorage from this class without
+         * otherwise unnecessary accessors.
+         */
+        friend class StringOptionStorage;
+};
+
+/*! \brief
+ * Specifies an option that provides file names.
+ *
+ * \inpublicapi
+ */
+class FileNameOption : public OptionTemplate<std::string, FileNameOption>
+{
+    public:
+        //! Initializes an option with the given name.
+        explicit FileNameOption(const char *name)
+            : MyBase(name), _filetype(eftUnknown)
+        {
+            setFlag(efFile);
+        }
+
+        /*! \brief
+         * Sets the type of the file this option accepts.
+         *
+         * This attribute must be provided.
+         */
+        MyClass &filetype(OptionFileType type)
+        { _filetype = type; return me(); }
+        //! Tells that the file provided by this option is used read-only.
+        MyClass &readOnly()
+        { setFlag(efFileRead); clearFlag(efFileWrite); return me(); }
+        //! Tells that the file provided by this option is used write-only.
+        MyClass &writeOnly()
+        { setFlag(efFileWrite); clearFlag(efFileRead); return me(); }
+        /*! \brief
+         * Tells that the file provided by this option is used for reading and
+         * writing.
+         */
+        MyClass &readwrite()
+        { setFlag(efFileRead); setFlag(efFileWrite); return me(); }
+        /*! \brief
+         * Tells that the file will be looked up in library directories in
+         * addition to working directory.
+         */
+        MyClass &libraryFile() { setFlag(efFileLibrary); return me(); }
+
+    protected:
+        virtual int createDefaultStorage(Options *options,
+                                         AbstractOptionStorage **storage) const;
+
+    private:
+        OptionFileType          _filetype;
+
+        /*! \brief
+         * Needed to initialize FileNameOptionStorage from this class without
+         * otherwise unnecessary accessors.
+         */
+        friend class FileNameOptionStorage;
+};
+
+/*!\}*/
+
+} // namespace gmx
+
+#endif
diff --git a/src/gromacs/options/basicoptionstorage.cpp b/src/gromacs/options/basicoptionstorage.cpp
new file mode 100644 (file)
index 0000000..6310c33
--- /dev/null
@@ -0,0 +1,384 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * Implements classes in basicoptionstorage.h.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_options
+ */
+#include "basicoptionstorage.h"
+
+#include <cstdio>
+#include <cstdlib>
+
+#include <string>
+#include <vector>
+
+#include "gromacs/errorreporting/abstracterrorreporter.h"
+#include "gromacs/fatalerror/fatalerror.h"
+#include "gromacs/options/basicoptions.h"
+#include "gromacs/options/globalproperties.h"
+#include "gromacs/options/options.h"
+
+template <typename T> static
+int expandVector(int length, int *nvalues, gmx::AbstractErrorReporter *errors,
+                 std::vector<T> *values)
+{
+    if (length > 0 && *nvalues > 0 && *nvalues != length)
+    {
+        if (*nvalues != 1)
+        {
+            char err_buf[256];
+            std::sprintf(err_buf, "Expected 1 or %d values, got %d",
+                         length, *nvalues);
+            errors->error(err_buf);
+            values->resize(values->size() - *nvalues);
+            return gmx::eeInvalidInput;
+        }
+        const T &value = (*values)[values->size() - 1];
+        values->resize(values->size() + length - 1, value);
+        *nvalues = length;
+    }
+    return 0;
+}
+
+namespace gmx
+{
+
+/********************************************************************
+ * BooleanOptionStorage
+ */
+
+std::string BooleanOptionStorage::formatValue(int i) const
+{
+    bool value = values()[i];
+    return value ? "yes" : "no";
+}
+
+int BooleanOptionStorage::convertValue(const std::string &value,
+                                       AbstractErrorReporter *errors)
+{
+    // TODO: Case-independence
+    if (value == "1" || value == "yes" || value == "true")
+    {
+        addValue(true);
+        return 0;
+    }
+    else if (value == "0" || value == "no" || value == "false")
+    {
+        addValue(false);
+        return 0;
+    }
+    errors->error("Invalid value: '" + value + "'; supported values are: 1, 0, yes, no, true, false");
+    return eeInvalidInput;
+}
+
+/********************************************************************
+ * IntegerOptionStorage
+ */
+
+IntegerOptionStorage::IntegerOptionStorage()
+{
+}
+
+std::string IntegerOptionStorage::formatValue(int i) const
+{
+    char buf[64];
+    int value = values()[i];
+    std::sprintf(buf, "%d", value);
+    return std::string(buf);
+}
+
+int IntegerOptionStorage::convertValue(const std::string &value,
+                                       AbstractErrorReporter *errors)
+{
+    const char *ptr = value.c_str();
+    char *endptr = NULL;
+    long int ival = std::strtol(ptr, &endptr, 10);
+    if (*endptr == '\0')
+    {
+        addValue(ival);
+        return 0;
+    }
+    errors->error("Invalid value: " + value);
+    return eeInvalidInput;
+}
+
+int IntegerOptionStorage::processSet(int nvalues, AbstractErrorReporter *errors)
+{
+    if (hasFlag(efVector))
+    {
+        int rc = expandVector(maxValueCount(), &nvalues, errors, &values());
+        if (rc != 0)
+        {
+            return rc;
+        }
+    }
+    return MyBase::processSet(nvalues, errors);
+}
+
+/********************************************************************
+ * DoubleOptionStorage
+ */
+
+DoubleOptionStorage::DoubleOptionStorage()
+    : _bTime(false)
+{
+}
+
+int DoubleOptionStorage::init(const DoubleOption &settings, Options *options)
+{
+    _bTime = settings._bTime;
+    if (_bTime)
+    {
+        options->globalProperties().request(eogpTimeScaleFactor);
+    }
+    return MyBase::init(settings, options);
+}
+
+const char *DoubleOptionStorage::typeString() const
+{
+    return hasFlag(efVector) > 0 ? "vector" : (_bTime ? "time" : "double");
+}
+
+std::string DoubleOptionStorage::formatValue(int i) const
+{
+    char buf[64];
+    double value = values()[i];
+    if (_bTime)
+    {
+        double factor = hostOptions().globalProperties().timeScaleFactor();
+        value /= factor;
+    }
+    std::sprintf(buf, "%g", value);
+    return std::string(buf);
+}
+
+int DoubleOptionStorage::convertValue(const std::string &value,
+                                      AbstractErrorReporter *errors)
+{
+    const char *ptr = value.c_str();
+    char *endptr = NULL;
+    double dval = std::strtod(ptr, &endptr);
+    if (*endptr == '\0')
+    {
+        addValue(dval);
+        return 0;
+    }
+    errors->error("Invalid value: " + value);
+    return eeInvalidInput;
+}
+
+int DoubleOptionStorage::processSet(int nvalues, AbstractErrorReporter *errors)
+{
+    if (hasFlag(efVector))
+    {
+        int rc = expandVector(maxValueCount(), &nvalues, errors, &values());
+        if (rc != 0)
+        {
+            return rc;
+        }
+    }
+    return MyBase::processSet(nvalues, errors);
+}
+
+int DoubleOptionStorage::processAll(AbstractErrorReporter *errors)
+{
+    if (_bTime)
+    {
+        double factor = hostOptions().globalProperties().timeScaleFactor();
+        ValueList::iterator i;
+        for (i = values().begin(); i != values().end(); ++i)
+        {
+            (*i) *= factor;
+        }
+    }
+    return MyBase::processAll(errors);
+}
+
+/********************************************************************
+ * StringOptionStorage
+ */
+
+StringOptionStorage::StringOptionStorage()
+    : _enumIndexStore(NULL)
+{
+}
+
+int StringOptionStorage::init(const StringOption &settings, Options *options)
+{
+    if (settings._defaultEnumIndex >= 0 && settings._enumValues == NULL)
+    {
+        GMX_ERROR(eeInvalidValue,
+                  "Cannot set default enum index without enum values");
+    }
+    if (settings._enumIndexStore != NULL && settings._enumValues == NULL)
+    {
+        GMX_ERROR(eeInvalidValue,
+                  "Cannot set enum index store without enum values");
+    }
+    if (settings._enumIndexStore != NULL && settings._maxValueCount < 0)
+    {
+        GMX_ERROR(eeInvalidValue,
+                  "Cannot set enum index store with arbitrary number of values");
+    }
+    if (settings._enumValues != NULL)
+    {
+        _enumIndexStore = settings._enumIndexStore;
+        const std::string *defaultValue = settings.defaultValue();
+        int match = -1;
+        for (int i = 0; settings._enumValues[i] != NULL; ++i)
+        {
+            if (defaultValue && settings._enumValues[i] == *defaultValue)
+            {
+                match = i;
+            }
+            _allowed.push_back(settings._enumValues[i]);
+        }
+        if (defaultValue)
+        {
+            if (match < 0)
+            {
+                GMX_ERROR(eeInvalidValue,
+                          "Default value is not one of allowed values");
+            }
+        }
+        if (settings._defaultEnumIndex >= 0)
+        {
+            if (settings._defaultEnumIndex >= static_cast<int>(_allowed.size()))
+            {
+                GMX_ERROR(eeInvalidValue,
+                          "Default enumeration index is out of range");
+            }
+            if (defaultValue && *defaultValue != _allowed[settings._defaultEnumIndex])
+            {
+                GMX_ERROR(eeInvalidValue,
+                          "Conflicting default values");
+            }
+        }
+        // If there is no default value, match is still -1.
+        if (_enumIndexStore != NULL)
+        {
+            *_enumIndexStore = match;
+        }
+    }
+    int rc = MyBase::init(settings, options);
+    if (rc == 0)
+    {
+        if (settings._defaultEnumIndex >= 0)
+        {
+            clear();
+            addValue(_allowed[settings._defaultEnumIndex]);
+            if (_enumIndexStore != NULL)
+            {
+                *_enumIndexStore = settings._defaultEnumIndex;
+            }
+            processValues(1, false);
+        }
+    }
+    return rc;
+}
+
+std::string StringOptionStorage::formatValue(int i) const
+{
+    return values()[i];
+}
+
+int StringOptionStorage::convertValue(const std::string &value,
+                                      AbstractErrorReporter *errors)
+{
+    if (_allowed.size() == 0)
+    {
+        addValue(value);
+    }
+    else
+    {
+        ValueList::const_iterator  i;
+        ValueList::const_iterator  match = _allowed.end();
+        for (i = _allowed.begin(); i != _allowed.end(); ++i)
+        {
+            // TODO: Case independence.
+            if (i->find(value) == 0)
+            {
+                if (match == _allowed.end() || i->size() < match->size())
+                {
+                    match = i;
+                }
+            }
+        }
+        if (match == _allowed.end())
+        {
+            errors->error("Invalid value: " + value);
+            return eeInvalidInput;
+        }
+        addValue(*match);
+        if (_enumIndexStore)
+        {
+            _enumIndexStore[valueCount() - 1] = (match - _allowed.begin());
+        }
+    }
+    return 0;
+}
+
+/********************************************************************
+ * FileNameOptionStorage
+ */
+
+FileNameOptionStorage::FileNameOptionStorage()
+    : _filetype(eftUnknown)
+{
+}
+
+int FileNameOptionStorage::init(const FileNameOption &settings, Options *options)
+{
+    _filetype = settings._filetype;
+    if (_filetype == eftPlot)
+    {
+        options->globalProperties().request(eogpPlotFormat);
+    }
+    return MyBase::init(settings, options);
+}
+
+std::string FileNameOptionStorage::formatValue(int i) const
+{
+    return values()[i];
+}
+
+int FileNameOptionStorage::convertValue(const std::string &value,
+                                        AbstractErrorReporter * /*errors*/)
+{
+    // TODO: Proper implementation.
+    addValue(value);
+    return 0;
+}
+
+} // namespace gmx
diff --git a/src/gromacs/options/basicoptionstorage.h b/src/gromacs/options/basicoptionstorage.h
new file mode 100644 (file)
index 0000000..85f19b9
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * Declares storage classes for basic option types.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_options
+ */
+#ifndef GMX_OPTIONS_BASICOPTIONSTORAGE_H
+#define GMX_OPTIONS_BASICOPTIONSTORAGE_H
+
+#include <string>
+#include <vector>
+
+#include "optionfiletype.h"
+#include "optionstoragetemplate.h"
+
+namespace gmx
+{
+
+class IntegerOption;
+class DoubleOption;
+class StringOption;
+class FileNameOption;
+
+/*! \addtogroup module_options
+ * \{
+ */
+
+/*! \internal \brief
+ * Converts, validates, and stores boolean values.
+ */
+class BooleanOptionStorage : public OptionStorageTemplate<bool>
+{
+    public:
+        virtual const char *typeString() const { return "bool"; }
+        virtual std::string formatValue(int i) const;
+
+    private:
+        virtual int convertValue(const std::string &value,
+                                 AbstractErrorReporter *errors);
+};
+
+/*! \internal \brief
+ * Converts, validates, and stores integer values.
+ */
+class IntegerOptionStorage : public OptionStorageTemplate<int>
+{
+    public:
+        IntegerOptionStorage();
+
+        virtual const char *typeString() const
+        { return hasFlag(efVector) ? "vector" : "int"; }
+        virtual std::string formatValue(int i) const;
+
+    private:
+        virtual int convertValue(const std::string &value,
+                                 AbstractErrorReporter *errors);
+        virtual int processSet(int nvalues, AbstractErrorReporter *errors);
+};
+
+/*! \internal \brief
+ * Converts, validates, and stores floating-point (double) values.
+ */
+class DoubleOptionStorage : public OptionStorageTemplate<double>
+{
+    public:
+        DoubleOptionStorage();
+
+        /*! \brief
+         * Initializes the storage from option settings.
+         *
+         * \param[in] settings   Storage settings.
+         * \param[in] options    Options object.
+         * \retval 0 on success.
+         */
+        int init(const DoubleOption &settings, Options *options);
+
+        virtual const char *typeString() const;
+        virtual std::string formatValue(int i) const;
+
+    private:
+        virtual int convertValue(const std::string &value,
+                                 AbstractErrorReporter *errors);
+        virtual int processSet(int nvalues, AbstractErrorReporter *errors);
+        virtual int processAll(AbstractErrorReporter *errors);
+
+        bool                    _bTime;
+};
+
+/*! \internal \brief
+ * Converts, validates, and stores string values.
+ */
+class StringOptionStorage : public OptionStorageTemplate<std::string>
+{
+    public:
+        StringOptionStorage();
+
+        //! \copydoc DoubleOptionStorage::init()
+        int init(const StringOption &settings, Options *options);
+
+        virtual const char *typeString() const { return _allowed.empty() ? "string" : "enum"; }
+        virtual std::string formatValue(int i) const;
+
+    private:
+        virtual int convertValue(const std::string &value,
+                                 AbstractErrorReporter *errors);
+
+        ValueList               _allowed;
+        int                    *_enumIndexStore;
+};
+
+/*! \internal \brief
+ * Converts, validates, and stores file names.
+ */
+class FileNameOptionStorage : public OptionStorageTemplate<std::string>
+{
+    public:
+        FileNameOptionStorage();
+
+        //! \copydoc StringOptionStorage::init()
+        int init(const FileNameOption &settings, Options *options);
+
+        virtual const char *typeString() const { return "file"; }
+        virtual std::string formatValue(int i) const;
+
+    private:
+        virtual int convertValue(const std::string &value,
+                                 AbstractErrorReporter *errors);
+
+        OptionFileType          _filetype;
+};
+
+/*!\}*/
+
+} // namespace gmx
+
+#endif
diff --git a/src/gromacs/options/cmdlineparser-impl.h b/src/gromacs/options/cmdlineparser-impl.h
new file mode 100644 (file)
index 0000000..a1865c4
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * Declares private implementation class for gmx::CommandLineParser.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_options
+ */
+#ifndef GMX_OPTIONS_CMDLINEPARSER_IMPL_H
+#define GMX_OPTIONS_CMDLINEPARSER_IMPL_H
+
+#include "cmdlineparser.h"
+#include "optionsassigner.h"
+
+namespace gmx
+{
+
+/*! \internal \brief
+ * Private implementation class for CommandLineParser.
+ *
+ * \ingroup module_options
+ */
+class CommandLineParser::Impl
+{
+    public:
+        //! Sets the options object to parse to.
+        Impl(Options *options, AbstractErrorReporter *errors);
+
+        //! Helper object for assigning the options.
+        OptionsAssigner         _assigner;
+};
+
+} // namespace gmx
+
+#endif
diff --git a/src/gromacs/options/cmdlineparser.cpp b/src/gromacs/options/cmdlineparser.cpp
new file mode 100644 (file)
index 0000000..68d5b47
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * Implements gmx::CommandLineParser.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_options
+ */
+#include "gromacs/options/cmdlineparser.h"
+
+#include "gromacs/errorreporting/abstracterrorreporter.h"
+#include "gromacs/options/optionsassigner.h"
+
+#include "cmdlineparser-impl.h"
+
+namespace gmx
+{
+
+/********************************************************************
+ * CommandLineParser::Impl
+ */
+
+CommandLineParser::Impl::Impl(Options *options, AbstractErrorReporter *errors)
+    : _assigner(options, errors)
+{
+    _assigner.setAcceptBooleanNoPrefix(true);
+    _assigner.setNoStrictSectioning(true);
+}
+
+/********************************************************************
+ * CommandLineParser
+ */
+
+CommandLineParser::CommandLineParser(Options *options,
+                                     AbstractErrorReporter *errors)
+    : _impl(new Impl(options, errors))
+{
+}
+
+CommandLineParser::~CommandLineParser()
+{
+    delete _impl;
+}
+
+int CommandLineParser::parse(int *argc, char *argv[])
+{
+    AbstractErrorReporter *errors = _impl->_assigner.errorReporter();
+    int  i = 1;
+    // Start in the discard phase to skip options that can't be understood.
+    bool bDiscard = true;
+
+    _impl->_assigner.start();
+    while (i < *argc)
+    {
+        // Lone '-' is passed as a value.
+        if (argv[i][0] == '-' && argv[i][1] != '\0')
+        {
+            if (!bDiscard)
+            {
+                _impl->_assigner.finishOption();
+                errors->finishContext();
+            }
+            errors->startContext("In command-line option " + std::string(argv[i]));
+            const char *name = &argv[i][1];
+            int rc = _impl->_assigner.startOption(name);
+            bDiscard = (rc != 0);
+            if (bDiscard)
+            {
+                errors->finishContext();
+            }
+        }
+        else if (!bDiscard)
+        {
+            _impl->_assigner.appendValue(argv[i]);
+        }
+        ++i;
+    }
+    if (!bDiscard)
+    {
+        _impl->_assigner.finishOption();
+        errors->finishContext();
+    }
+    return _impl->_assigner.finish();
+}
+
+} // namespace gmx
diff --git a/src/gromacs/options/cmdlineparser.h b/src/gromacs/options/cmdlineparser.h
new file mode 100644 (file)
index 0000000..5f7bc28
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \file
+ * \brief
+ * Declares gmx::CommandLineParser.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \inpublicapi
+ * \ingroup module_options
+ */
+#ifndef GMX_OPTIONS_CMDLINEPARSER_H
+#define GMX_OPTIONS_CMDLINEPARSER_H
+
+namespace gmx
+{
+
+class AbstractErrorReporter;
+
+class Options;
+
+/*! \brief
+ * Implements command-line parsing for Options objects.
+ *
+ * Typical usage (without error checking):
+ * \code
+gmx::Options options("name", "description");
+// Fill up options
+
+gmx::StandardErrorReporter errors;
+gmx::CommandLineParser(&options, &errors).parse(&argc, argv);
+options.finish(&errors);
+ * \endcode
+ *
+ * \inpublicapi
+ * \ingroup module_options
+ */
+class CommandLineParser
+{
+    public:
+        /*! \brief
+         * Creates a command-line parser that sets values for options.
+         *
+         * \param[in] options  Options object whose options should be set.
+         * \param[in] errors   Error reporter object.
+         */
+        CommandLineParser(Options *options, AbstractErrorReporter *errors);
+        ~CommandLineParser();
+
+        /*! \brief
+         * Parses the command-line.
+         *
+         * \retval 0 if there were no errors.
+         */
+        int parse(int *argc, char *argv[]);
+
+    private:
+        class Impl;
+
+        Impl                   *_impl;
+
+        // Disallow copy and assign.
+        CommandLineParser(const CommandLineParser &);
+        void operator =(const CommandLineParser &);
+};
+
+} // namespace gmx
+
+#endif
diff --git a/src/gromacs/options/globalproperties.cpp b/src/gromacs/options/globalproperties.cpp
new file mode 100644 (file)
index 0000000..377b097
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * Implements gmx::OptionsGlobalProperties.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_options
+ */
+#include "gromacs/options/globalproperties.h"
+
+#include <cassert>
+#include <cstddef>
+
+#include <smalloc.h>
+#include <statutil.h>
+
+#include "gromacs/options/basicoptions.h"
+#include "gromacs/options/options.h"
+
+namespace gmx
+{
+
+static const char *const timeUnits[] = {
+    "fs", "ps", "ns", "us", "ms",  "s", NULL
+};
+static const char *const plotFormats[] = {
+    "none", "xmgrace", "xmgr", NULL
+};
+static const double timeScaleFactors[] = {
+    1e-3,    1,  1e3,  1e6,  1e9, 1e12
+};
+
+
+OptionsGlobalProperties::OptionsGlobalProperties()
+    : _usedProperties(0), _timeUnit(1), _plotFormat(1),
+      _selectionCollection(NULL), _oenv(NULL)
+{
+    snew(_oenv, 1);
+    output_env_init_default(_oenv);
+}
+
+
+OptionsGlobalProperties::~OptionsGlobalProperties()
+{
+    if (_oenv != NULL)
+    {
+        output_env_done(_oenv);
+    }
+}
+
+
+double OptionsGlobalProperties::timeScaleFactor() const
+{
+    assert(_timeUnit >= 0
+           && (size_t)_timeUnit < sizeof(timeScaleFactors)/sizeof(timeScaleFactors[0]));
+    return timeScaleFactors[_timeUnit];
+}
+
+
+void OptionsGlobalProperties::addDefaultOptions(Options *options)
+{
+    if (isPropertyUsed(eogpTimeScaleFactor))
+    {
+        options->addOption(StringOption("tu").enumValue(timeUnits)
+                               .defaultValue("ps")
+                               .storeEnumIndex(&_timeUnit)
+                               .description("Unit for time values"));
+    }
+    if (isPropertyUsed(eogpPlotFormat))
+    {
+        options->addOption(StringOption("xvg").enumValue(plotFormats)
+                               .defaultValue("xmgrace")
+                               .storeEnumIndex(&_plotFormat)
+                               .description("Plot formatting"));
+    }
+}
+
+
+void OptionsGlobalProperties::finish()
+{
+    if (isPropertyUsed(eogpTimeScaleFactor))
+    {
+        _oenv->time_unit = static_cast<time_unit_t>(_timeUnit + 1);
+    }
+    if (isPropertyUsed(eogpPlotFormat))
+    {
+        if (_plotFormat == 0)
+        {
+            _oenv->xvg_format = exvgNONE;
+        }
+        else
+        {
+            _oenv->xvg_format = static_cast<xvg_format_t>(_plotFormat);
+        }
+    }
+}
+
+} // namespace gmx
diff --git a/src/gromacs/options/globalproperties.h b/src/gromacs/options/globalproperties.h
new file mode 100644 (file)
index 0000000..0f2be17
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \libinternal \file
+ * \brief
+ * Declares gmx::OptionsGlobalProperties.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \inlibraryapi
+ * \ingroup module_options
+ */
+#ifndef GMX_OPTIONS_GLOBALPROPERTIES_H
+#define GMX_OPTIONS_GLOBALPROPERTIES_H
+
+#include <typedefs.h>
+
+namespace gmx
+{
+
+class Options;
+class SelectionCollection;
+
+/*! \libinternal \brief
+ * ID numbers for global properties.
+ */
+enum OptionGlobalPropertyId
+{
+    eogpTimeScaleFactor,
+    eogpPlotFormat,
+    eogpSelectionCollection,
+};
+
+/*! \libinternal \brief
+ * Describes global properties of an Options collection.
+ *
+ * These properties are used to implement features that require all options of
+ * a certain type to access some global data.
+ * For example, if there are options that specify times, and in addition an
+ * option that specifies the unit for these times, all the time options need to
+ * know the scaling factor to get the time in internal units.
+ *
+ * \inlibraryapi
+ * \ingroup module_options
+ */
+class OptionsGlobalProperties
+{
+    public:
+        //! Request for a global property to be used.
+        void request(OptionGlobalPropertyId id)
+        {
+            _usedProperties |= (1<<id);
+        }
+
+        //! Set the selection collection for selection option output.
+        void setSelectionCollection(SelectionCollection *sc)
+        {
+            _selectionCollection = sc;
+        }
+
+        //! Returns the scaling factor to get times in ps.
+        double timeScaleFactor() const;
+        //! Returns the selection collection.
+        SelectionCollection *selectionCollection() const
+        {
+            return _selectionCollection;
+        }
+        /*! \brief
+         * Returns an output environment structure for interfacing with old
+         * code.
+         *
+         * Currently, the returned structure is always filled with default
+         * values.
+         *
+         * \deprecated
+         */
+        output_env_t output_env() const
+        {
+            return _oenv;
+        }
+
+    private:
+        OptionsGlobalProperties();
+        ~OptionsGlobalProperties();
+
+        //! Returns true if request() has been called for the given property.
+        bool isPropertyUsed(OptionGlobalPropertyId id) const
+        {
+            return _usedProperties & (1<<id);
+        }
+        void addDefaultOptions(Options *options);
+        /*! \brief
+         * Initializes variables dependent on global properties.
+         *
+         * This method should be called after the values for the options
+         * generated with addDefaultOptions() have been set.
+         */
+        void finish();
+
+        unsigned long           _usedProperties;
+        int                     _timeUnit;
+        int                     _plotFormat;
+        SelectionCollection    *_selectionCollection;
+        output_env_t            _oenv;
+
+        friend class Options;
+
+        // Disallow copy and assign.
+        OptionsGlobalProperties(const OptionsGlobalProperties &);
+        void operator =(const OptionsGlobalProperties &);
+};
+
+} // namespace gmx
+
+#endif
diff --git a/src/gromacs/options/optionfiletype.h b/src/gromacs/options/optionfiletype.h
new file mode 100644 (file)
index 0000000..5b2223e
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \file
+ * \brief
+ * Defines an enumeration type for specifying file types for options.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \inpublicapi
+ * \ingroup module_options
+ */
+#ifndef GMX_OPTIONS_OPTIONFILETYPE_HPP
+#define GMX_OPTIONS_OPTIONFILETYPE_HPP
+
+namespace gmx
+{
+
+/*! \brief
+ * Purpose of file(s) provided through an option.
+ *
+ * \ingroup module_options
+ */
+enum OptionFileType {
+    eftUnknown,
+    eftTopology,
+    eftRunInput,
+    eftTrajectory,
+    eftIndex,
+    eftPlot,
+};
+
+} // namespace gmx
+
+#endif
diff --git a/src/gromacs/options/optionflags.h b/src/gromacs/options/optionflags.h
new file mode 100644 (file)
index 0000000..2dc3bbc
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * Defines flags used in option implementation.
+ *
+ * Symbols in this header are considered an implementation detail, and should
+ * not be accessed outside the module.
+ * Because of details in the implementation, it is still installed.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_options
+ */
+#ifndef GMX_OPTIONS_OPTIONFLAGS_H
+#define GMX_OPTIONS_OPTIONFLAGS_H
+
+#include "../utility/flags.h"
+
+namespace gmx
+{
+
+/*! \internal \brief
+ * Flags for options.
+ *
+ * These flags are not part of the public interface, even though they are in an
+ * installed header.  They are needed in a few template class implementations.
+ */
+enum OptionFlag
+{
+    //! %Option has been set.
+    efSet                 = 1<<0,
+    /*! \brief
+     * The current value of the option is a default value.
+     *
+     * This flag is also set when a new option source starts, such that values
+     * from the new source will overwrite old ones.
+     */
+    efHasDefaultValue     = 1<<1,
+    //! %Option is required to be set.
+    efRequired            = 1<<2,
+    //! %Option can be specified multiple times.
+    efMulti               = 1<<3,
+    //! %Option is hidden from standard help.
+    efHidden              = 1<<4,
+    /*! \brief
+     * %Option provides a boolean value.
+     *
+     * This is used to optionally support an alternative syntax where an
+     * option provided with no value sets the value to true and an
+     * option prefixed with "no" clears the value.
+     */
+    efBoolean             = 1<<5,
+    /*! \brief
+     * %Option value is a vector, but a single value is also accepted.
+     *
+     * If only a single value is provided, the storage object should fill the
+     * whole vector with that value.  The length of the vector must be fixed.
+     * The default length is 3 elements.
+     */
+    efVector              = 1<<6,
+    efExternalStore       = 1<<8,
+    efExternalStoreArray  = 1<<9,
+    efExternalValueVector = 1<<10,
+    //! %Option does not support default values.
+    efNoDefaultValue      = 1<<7,
+    /*! \brief
+     * Storage object may add zero values even when a value is provided.
+     *
+     * In order to do proper error checking, this flag should be set when it is
+     * possible that the AbstractOptionStorage::appendValue() method of the
+     * storage object does not add any values for the option and still
+     * succeeds.
+     */
+    efConversionMayNotAddValues = 1<<11,
+    /*! \brief
+     * Storage object does its custom checking for minimum value count.
+     *
+     * If this flag is set, the class derived from AbstractOptionStorage should
+     * implement processSet(), processAll(), and possible other functions it
+     * provides such that it always fails if not enough values are provided.
+     * This is useful to override the default check, which is done in
+     * AbstractOptionStorage::processSet().
+     */
+    efDontCheckMinimumCount     = 1<<16,
+    efFile                = 1<<12,
+    efFileRead            = 1<<13,
+    efFileWrite           = 1<<14,
+    efFileLibrary         = 1<<15,
+    //efDynamic             = 1<<16,
+    //efRanges              = 1<<17,
+    //efEnum                = 1<<18,
+    //efStaticEnum          = 1<<19,
+    //efVarNum              = 1<<20,
+    //efAtomVal             = 1<<21,
+};
+
+//! Holds a combination of ::OptionFlag values.
+typedef FlagsTemplate<OptionFlag> OptionFlags;
+
+} // namespace gmx
+
+#endif
diff --git a/src/gromacs/options/options-impl.h b/src/gromacs/options/options-impl.h
new file mode 100644 (file)
index 0000000..99e992c
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * Declares private implementation class for gmx::Options.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_options
+ */
+#ifndef GMX_OPTIONS_OPTIONS_IMPL_H
+#define GMX_OPTIONS_OPTIONS_IMPL_H
+
+#include <string>
+#include <vector>
+
+#include "options.h"
+
+namespace gmx
+{
+
+class AbstractOptionStorage;
+class OptionsGlobalProperties;
+
+/*! \internal \brief
+ * Private implementation class for Options.
+ *
+ * Note that in addition to Options, the OptionsAssigner and OptionsIterator
+ * classes also directly access this class.
+ *
+ * \ingroup module_options
+ */
+class Options::Impl
+{
+    public:
+        //! Convenience type for list of sections.
+        typedef std::vector<Options *> SubSectionList;
+        //! Convenience type for list of options.
+        typedef std::vector<AbstractOptionStorage *> OptionList;
+
+        //! Sets the name and title.
+        Impl(const char *name, const char *title);
+        ~Impl();
+
+        /*! \brief
+         * Finds a subsection by name.
+         *
+         * \param[in] name  Name to search for.
+         * \returns Pointer to the found subsection, or NULL if not found.
+         */
+        Options *findSubSection(const char *name) const;
+        /*! \brief
+         * Finds an option by name.
+         *
+         * \param[in] name  Name to search for.
+         * \returns Pointer to the found option, or NULL if not found.
+         */
+        AbstractOptionStorage *findOption(const char *name) const;
+
+        /*! \brief
+         * Calls Option::startSource() for all options, including subsections.
+         *
+         * \returns 0 on success, or the first non-zero return value of the
+         *      called functions.
+         */
+        int startSource();
+
+        //! Name for the Options object.
+        std::string             _name;
+        //! Description title for the Options object.
+        std::string             _title;
+        //! Full description for the Options object.
+        std::string             _description;
+        /*! \brief
+         * List of subsections, in insertion order.
+         *
+         * This container contains only references to external objects; memory
+         * management is performed elsewhere.
+         */
+        SubSectionList          _subSections;
+        /*! \brief
+         * List of options, in insertion order.
+         *
+         * All objects in this container are owned by this object, and are
+         * freed in the destructor.
+         */
+        OptionList              _options;
+        //! Options object that contains this object as a subsection, or NULL.
+        Options                *_parent;
+        /*! \brief
+         * Object that contains global properties, or NULL if \a _parent != NULL.
+         *
+         * This object is always owned by the Options object.
+         * For subsections, the global properties are kept in the parent, and
+         * this pointer is NULL.
+         */
+        OptionsGlobalProperties *_globalProperties;
+};
+
+} // namespace gmx
+
+#endif
diff --git a/src/gromacs/options/options.cpp b/src/gromacs/options/options.cpp
new file mode 100644 (file)
index 0000000..e41229a
--- /dev/null
@@ -0,0 +1,245 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * Implements gmx::Options.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_options
+ */
+#include "gromacs/options/options.h"
+
+#include <cassert>
+#include <cctype>
+#include <cstring>
+
+#include "gromacs/options/abstractoption.h"
+#include "gromacs/options/abstractoptionstorage.h"
+#include "gromacs/options/globalproperties.h"
+
+#include "options-impl.h"
+
+namespace gmx
+{
+
+static std::string composeString(const char *const *sarray)
+{
+    std::string result;
+
+    for (int i = 0; sarray[i] != NULL; ++i)
+    {
+        if (sarray[i][0] != '\0')
+        {
+            result.append(sarray[i]);
+            char lastchar = sarray[i][std::strlen(sarray[i])-1];
+            if (!std::isspace(lastchar))
+            {
+                result.append(" ");
+            }
+        }
+    }
+    result.resize(result.find_last_not_of(" \n\r\t") + 1);
+    return result;
+}
+
+/********************************************************************
+ * Options::Impl
+ */
+
+Options::Impl::Impl(const char *name, const char *title)
+    : _name(name != NULL ? name : ""), _title(title != NULL ? title : ""),
+      _parent(NULL), _globalProperties(new OptionsGlobalProperties)
+{
+}
+
+Options::Impl::~Impl()
+{
+    OptionList::const_iterator i;
+    for (i = _options.begin(); i != _options.end(); ++i)
+    {
+        delete *i;
+    }
+    delete _globalProperties;
+}
+
+Options *Options::Impl::findSubSection(const char *name) const
+{
+    SubSectionList::const_iterator i;
+    for (i = _subSections.begin(); i != _subSections.end(); ++i)
+    {
+        if ((*i)->name() == name)
+        {
+            return *i;
+        }
+    }
+    return NULL;
+}
+
+AbstractOptionStorage *Options::Impl::findOption(const char *name) const
+{
+    OptionList::const_iterator i;
+    for (i = _options.begin(); i != _options.end(); ++i)
+    {
+        if ((*i)->name() == name)
+        {
+            return *i;
+        }
+    }
+    return NULL;
+}
+
+int Options::Impl::startSource()
+{
+    int rc = 0;
+    OptionList::const_iterator i;
+    for (i = _options.begin(); i != _options.end(); ++i)
+    {
+        AbstractOptionStorage *option = *i;
+        int rc1 = option->startSource();
+        rc = (rc != 0 ? rc : rc1);
+    }
+    SubSectionList::const_iterator j;
+    for (j = _subSections.begin(); j != _subSections.end(); ++j)
+    {
+        Options *section = *j;
+        int rc1 = section->_impl->startSource();
+        rc = (rc != 0 ? rc : rc1);
+    }
+    return rc;
+}
+
+/********************************************************************
+ * Options
+ */
+
+Options::Options(const char *name, const char *title)
+    : _impl(new Impl(name, title))
+{
+}
+
+Options::~Options()
+{
+    delete _impl;
+}
+
+const std::string &Options::name() const
+{
+    return _impl->_name;
+}
+
+const std::string &Options::title() const
+{
+    return _impl->_title;
+}
+
+const std::string &Options::description() const
+{
+    return _impl->_description;
+}
+
+void Options::setDescription(const char *const *desc)
+{
+    _impl->_description = composeString(desc);
+}
+
+void Options::addSubSection(Options *section)
+{
+    // Make sure that section is not already inserted somewhere.
+    assert(section->_impl->_parent == NULL);
+    // Make sure that there are no duplicate sections.
+    assert(_impl->findSubSection(section->name().c_str()) == NULL);
+    _impl->_subSections.push_back(section);
+    section->_impl->_parent = this;
+
+    globalProperties()._usedProperties |=
+        section->_impl->_globalProperties->_usedProperties;
+    delete section->_impl->_globalProperties;
+    section->_impl->_globalProperties = NULL;
+}
+
+void Options::addOption(const AbstractOption &settings)
+{
+    AbstractOptionStorage *option = NULL;
+    int rc = settings.createDefaultStorage(this, &option);
+    // Caller code should be fixed if option initialization fails.
+    assert(rc == 0);
+    // Make sure that there are no duplicate options.
+    assert(_impl->findOption(option->name().c_str()) == NULL);
+    _impl->_options.push_back(option);
+}
+
+void Options::addDefaultOptions()
+{
+    globalProperties().addDefaultOptions(this);
+}
+
+bool Options::isSet(const char *name) const
+{
+    AbstractOptionStorage *option = _impl->findOption(name);
+    return (option != NULL ? option->isSet() : false);
+}
+
+int Options::finish(AbstractErrorReporter *errors)
+{
+    int rc = 0;
+    Impl::OptionList::const_iterator i;
+    for (i = _impl->_options.begin(); i != _impl->_options.end(); ++i)
+    {
+        AbstractOptionStorage *option = *i;
+        int rc1 = option->finish(errors);
+        rc = (rc != 0 ? rc : rc1);
+    }
+    Impl::SubSectionList::const_iterator j;
+    for (j = _impl->_subSections.begin(); j != _impl->_subSections.end(); ++j)
+    {
+        Options *section = *j;
+        int rc1 = section->finish(errors);
+        rc = (rc != 0 ? rc : rc1);
+    }
+    if (_impl->_parent == NULL)
+    {
+        assert(_impl->_globalProperties != NULL);
+        _impl->_globalProperties->finish();
+    }
+    return rc;
+}
+
+OptionsGlobalProperties &Options::globalProperties()
+{
+    Options *section = this;
+    while (section->_impl->_parent != NULL)
+    {
+        section = section->_impl->_parent;
+    }
+    return *section->_impl->_globalProperties;
+}
+
+} // namespace gmx
diff --git a/src/gromacs/options/options.h b/src/gromacs/options/options.h
new file mode 100644 (file)
index 0000000..c0ffeb4
--- /dev/null
@@ -0,0 +1,203 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \file
+ * \brief
+ * Declares gmx::Options.
+ *
+ * Together with basicoptions.h, this header forms the part of the public
+ * API that most classes will use to provide options.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \inpublicapi
+ * \ingroup module_options
+ */
+#ifndef GMX_OPTIONS_OPTIONS_H
+#define GMX_OPTIONS_OPTIONS_H
+
+#include <string>
+
+namespace gmx
+{
+
+class AbstractErrorReporter;
+
+class AbstractOption;
+class OptionsGlobalProperties;
+class OptionsAssigner;
+class OptionsIterator;
+
+/*! \brief
+ * Collection of options.
+ *
+ * This class provides a standard interface for implementing input options.
+ * Standard usage is to write a method that creates an Options that is owned by
+ * the object, populates it with supported options, and then returns it:
+ * \code
+// <as class attributes>
+using gmx::Options;
+Options      options("common", "Common Options");
+std::string  arg1;
+int          arg2;
+
+// <populating>
+using gmx::StringOption;
+using gmx::IntegerOption;
+options.addOption(StringOption("arg1").store(&arg1));
+options.addOption(IntegerOption("arg2").store(&arg2));
+return &options;
+ * \endcode
+ * The caller of that method can then use a parser implementation such as
+ * CommandLineParser to provide values for the options.
+ *
+ * Header basicoptions.h provides declarations of several standard
+ * option types for use with addOption().  Documentation of those classes
+ * also give more examples of how to define options.
+ *
+ * In order to keep the public interface of this class simple and to reduce
+ * build dependencies on objects that simply provide options, functionality
+ * to assign values to options is provided by a separate OptionsAssigner class.
+ * Similarly, functionality for looping over all options (e.g., for writing out
+ * help) is provided by OptionsIterator.
+ *
+ * \inpublicapi
+ * \ingroup module_options
+ */
+class Options
+{
+    public:
+        /*! \brief
+         * Initializes the name and title of an option collection.
+         *
+         * \param[in] name  Single-word name.
+         * \param[in] title Descriptive title.
+         *
+         * Copies the input strings.
+         */
+        Options(const char *name, const char *title);
+        ~Options();
+
+        //! Returns the short name of the option collection.
+        const std::string &name() const;
+        //! Returns the title of the option collection.
+        const std::string &title() const;
+        //! Returns the full description of the option collection.
+        const std::string &description() const;
+
+        //! Sets the full description of the option collection.
+        void setDescription(const char *const *desc);
+        //int addBugs(int nbugs, const char *const *bugs);
+
+        /*! \brief
+         * Adds an option collection as a subsection of this collection.
+         *
+         * The name() field of \p section is used as the name of the
+         * subsection.
+         *
+         * For certain functionality to work properly, no options should
+         * be added to the subsection after it has been added to another
+         * collection.
+         *
+         * Only a pointer to the provided object is stored.  The caller is
+         * responsible that the object exists for the lifetime of the
+         * collection.
+         * It is not possible to add the same Options object as a subsection to
+         * several different Options.
+         */
+        void addSubSection(Options *section);
+        /*! \brief
+         * Adds a recognized option to the collection.
+         *
+         * The behavior is undefined if invalid settings are provided.
+         * The current implementation asserts if it detects an error.
+         *
+         * See \link Options class documentation \endlink for example usage.
+         */
+        void addOption(const AbstractOption &settings);
+        /*! \brief
+         * Adds default options to this collection.
+         *
+         * Adds default options for altering global properties such as the time
+         * unit into this collection.
+         *
+         * It is possible to call this method on a subsection of a collection.
+         * Even in that case, the generated options set the properties for the
+         * parent collection.
+         */
+        void addDefaultOptions();
+
+        //! Returns true if option is set.
+        bool isSet(const char *name) const;
+        /*! \brief
+         * Notifies the collection that all option values are assigned.
+         *
+         * \param[in] errors  Error reporter for reporting errors.
+         * \retval 0 on success.
+         *
+         * This function should be called after no more option values are
+         * to be assigned.  Values in storage variables are guaranteed to be
+         * available only after this call.
+         */
+        int finish(AbstractErrorReporter *errors);
+
+        /*! \brief
+         * Returns the global property object for this collection.
+         *
+         * The caller should not store pointers or references to the object;
+         * it can change if this object is added as a subsection into
+         * another collection.
+         *
+         * \see OptionsGlobalProperties
+         */
+        OptionsGlobalProperties &globalProperties();
+        //! \copydoc globalProperties()
+        const OptionsGlobalProperties &globalProperties() const
+        { return const_cast<Options *>(this)->globalProperties(); }
+
+    private:
+        class Impl;
+
+        Impl                   *_impl;
+
+        friend class Impl;
+
+        //! Needed to be able to extend the interface of this object.
+        friend class OptionsAssigner;
+        //! Needed to be able to extend the interface of this object.
+        friend class OptionsIterator;
+
+        // Disallow copy and assign.
+        Options(const Options &);
+        void operator =(const Options &);
+};
+
+} // namespace gmx
+
+#endif
diff --git a/src/gromacs/options/optionsassigner-impl.h b/src/gromacs/options/optionsassigner-impl.h
new file mode 100644 (file)
index 0000000..378422f
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * Declares private implementation class for gmx::OptionsAssigner.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_options
+ */
+#ifndef GMX_OPTIONS_OPTIONSASSIGNER_IMPL_H
+#define GMX_OPTIONS_OPTIONSASSIGNER_IMPL_H
+
+#include <vector>
+
+#include "optionsassigner.h"
+
+namespace gmx
+{
+
+class AbstractErrorReporter;
+
+class AbstractOptionStorage;
+class Options;
+
+/*! \internal \brief
+ * Private implementation class for OptionsAssigner.
+ *
+ * \ingroup module_options
+ */
+class OptionsAssigner::Impl
+{
+    public:
+        //! Possible flags for controlling assignment behavior.
+        enum Flag
+        {
+            //! Recognize boolean option "name" also as "noname".
+            efAcceptBooleanNoPrefix     = 1<<0,
+            //! Look for options in all sections, not just the current one.
+            efNoStrictSectioning        = 1<<1,
+        };
+        //! Sets the option object to assign to.
+        Impl(Options *options, AbstractErrorReporter *errors);
+
+        /*! \brief
+         * Stores error code for later retrieval if it is the first error.
+         *
+         * \param[in] code  Error code to store.
+         * \returns \p code
+         *
+         * The first call with a non-zero \p code sets the \p _errorCode
+         * attribute; later calls do nothing   The return value allows the
+         * function to be used like \c "return keepError(rc);"
+         */
+        int keepError(int code)
+        {
+            if (_errorCode == 0)
+            {
+                _errorCode = code;
+            }
+            return code;
+        }
+
+        //! Sets or clears the given flag.
+        void setFlag(Flag flag, bool bSet);
+
+        //! Returns true if the given flag is set.
+        bool hasFlag(Flag flag) const { return _flags & flag; }
+        //! Returns true if a subsection has been set.
+        bool inSubSection() const { return _sectionStack.size() > 1; }
+        //! Returns the Options object for the current section.
+        Options &currentSection() const { return *_sectionStack.back(); }
+        /*! \brief
+         * Finds an option by the given name.
+         *
+         * \param[in] name  Name of the option to look for.
+         * \returns Pointer to the found option, or NULL if none found.
+         *
+         * This function takes into account the flags specified, and may change
+         * the internal state of the assigner to match the option found.
+         * If no option is found, the internal state is not modified.
+         */
+        AbstractOptionStorage *findOption(const char *name);
+
+        //! Options object to assign to.
+        Options                &_options;
+        //! Error reporter to use for errors.
+        AbstractErrorReporter  *_errors;
+        //! Flags that control assignment behavior.
+        unsigned long           _flags;
+        /*! \brief
+         * List of (sub)sections being assigned to.
+         *
+         * The first element always points to \a _options.
+         */
+        std::vector<Options *>  _sectionStack;
+        //! Current option being assigned to, or NULL if none.
+        AbstractOptionStorage  *_currentOption;
+        //! Keeps the error code of the first error encountered, or 0 if none.
+        int                     _errorCode;
+        //! Number of values assigned so far to the current option.
+        int                     _currentValueCount;
+        //! If true, a "no" prefix was given for the current boolean option.
+        bool                    _reverseBoolean;
+};
+
+} // namespace gmx
+
+#endif
diff --git a/src/gromacs/options/optionsassigner.cpp b/src/gromacs/options/optionsassigner.cpp
new file mode 100644 (file)
index 0000000..e8c7dd2
--- /dev/null
@@ -0,0 +1,295 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * Implements gmx::OptionsAssigner.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_options
+ */
+#include "gromacs/options/optionsassigner.h"
+
+#include <deque>
+
+#include <cassert>
+
+#include "gromacs/errorreporting/abstracterrorreporter.h"
+#include "gromacs/fatalerror/fatalerror.h"
+#include "gromacs/options/abstractoptionstorage.h"
+#include "gromacs/options/options.h"
+
+#include "optionsassigner-impl.h"
+#include "options-impl.h"
+
+namespace gmx
+{
+
+/********************************************************************
+ * OptionsAssigner::Impl
+ */
+
+OptionsAssigner::Impl::Impl(Options *options, AbstractErrorReporter *errors)
+    : _options(*options), _errors(errors), _flags(0), _currentOption(NULL),
+      _errorCode(0), _currentValueCount(0), _reverseBoolean(false)
+{
+    _sectionStack.push_back(&_options);
+}
+
+void OptionsAssigner::Impl::setFlag(OptionsAssigner::Impl::Flag flag, bool bSet)
+{
+    if (bSet)
+    {
+        _flags |= flag;
+    }
+    else
+    {
+        _flags &= ~flag;
+    }
+}
+
+AbstractOptionStorage *
+OptionsAssigner::Impl::findOption(const char *name)
+{
+    assert(_currentOption == NULL);
+    AbstractOptionStorage *option = NULL;
+    Options *section = NULL;
+    Options *root = &currentSection();
+    Options *oldRoot = NULL;
+    int      upcount = 0;
+    std::deque<Options *> searchList;
+    searchList.push_back(root);
+    while (option == NULL && !searchList.empty())
+    {
+        section = searchList.front();
+        option = section->_impl->findOption(name);
+        if (option == NULL && hasFlag(efAcceptBooleanNoPrefix))
+        {
+            if (name[0] == 'n' && name[1] == 'o')
+            {
+                option = section->_impl->findOption(name + 2);
+                if (option != NULL && option->isBoolean())
+                {
+                    _reverseBoolean = true;
+                }
+                else
+                {
+                    option = NULL;
+                }
+            }
+        }
+        searchList.pop_front();
+        if (hasFlag(efNoStrictSectioning))
+        {
+            Options::Impl::SubSectionList::const_iterator i;
+            for (i = section->_impl->_subSections.begin();
+                 i != section->_impl->_subSections.end(); ++i)
+            {
+                if (*i != oldRoot)
+                {
+                    searchList.push_back(*i);
+                }
+            }
+            if (searchList.empty() && root != &_options)
+            {
+                Options *oldRoot = root;
+                root = root->_impl->_parent;
+                ++upcount;
+                searchList.push_back(root);
+            }
+        }
+    }
+    if (hasFlag(efNoStrictSectioning) && option != NULL)
+    {
+        while (upcount > 0)
+        {
+            _sectionStack.pop_back();
+            --upcount;
+        }
+        std::vector<Options *> sections;
+        while (section != &currentSection())
+        {
+            sections.push_back(section);
+            section = section->_impl->_parent;
+        }
+        while (!sections.empty())
+        {
+            _sectionStack.push_back(sections.back());
+            sections.pop_back();
+        }
+    }
+    return option;
+}
+
+/********************************************************************
+ * OptionsAssigner
+ */
+
+OptionsAssigner::OptionsAssigner(Options *options, AbstractErrorReporter *errors)
+    : _impl(new Impl(options, errors))
+{
+}
+
+OptionsAssigner::~OptionsAssigner()
+{
+    delete _impl;
+}
+
+AbstractErrorReporter *OptionsAssigner::errorReporter() const
+{
+    return _impl->_errors;
+}
+
+void OptionsAssigner::setAcceptBooleanNoPrefix(bool enabled)
+{
+    _impl->setFlag(Impl::efAcceptBooleanNoPrefix, enabled);
+}
+
+void OptionsAssigner::setNoStrictSectioning(bool enabled)
+{
+    _impl->setFlag(Impl::efNoStrictSectioning, enabled);
+}
+
+int OptionsAssigner::start()
+{
+    return _impl->keepError(_impl->_options._impl->startSource());
+}
+
+int OptionsAssigner::startSubSection(const char *name)
+{
+    if (_impl->_currentOption != NULL)
+    {
+        // The return code is ignored to keep on assigning, but any error is
+        // stored to be returned in finish().
+        finishOption();
+    }
+
+    Options *section = _impl->currentSection()._impl->findSubSection(name);
+    if (section == NULL)
+    {
+        // TODO: Print an error
+        return _impl->keepError(eeInvalidInput);
+    }
+    _impl->_sectionStack.push_back(section);
+    return 0;
+}
+
+int OptionsAssigner::startOption(const char *name)
+{
+    if (_impl->_currentOption != NULL)
+    {
+        // The return code is ignored to keep on assigning, but any error is
+        // stored to be returned in finish().
+        finishOption();
+    }
+
+    AbstractOptionStorage *option = _impl->findOption(name);
+    if (option == NULL)
+    {
+        _impl->_errors->error("Unknown option");
+        return _impl->keepError(eeInvalidInput);
+    }
+    int rc = option->startSet(_impl->_errors);
+    if (rc != 0)
+    {
+        return _impl->keepError(rc);
+    }
+    _impl->_currentOption = option;
+    _impl->_currentValueCount = 0;
+    return 0;
+}
+
+int OptionsAssigner::appendValue(const std::string &value)
+{
+    AbstractOptionStorage *option = _impl->_currentOption;
+    // The option should have been successfully started.
+    assert(option != NULL);
+    ++_impl->_currentValueCount;
+    return _impl->keepError(option->appendValue(value, _impl->_errors));
+}
+
+int OptionsAssigner::finishOption()
+{
+    AbstractOptionStorage *option = _impl->_currentOption;
+    // The option should have been successfully started.
+    assert(option != NULL);
+    int rc = 0;
+    if (option->isBoolean())
+    {
+        if (_impl->_currentValueCount == 0)
+        {
+            // TODO: Get rid of the hard-coded strings.
+            rc = option->appendValue(_impl->_reverseBoolean ? "0" : "1",
+                                     _impl->_errors);
+            // If the above fails, there is something wrong.
+            assert(rc == 0);
+        }
+        else if (_impl->_reverseBoolean)
+        {
+            _impl->_errors->error("Cannot specify a value together with 'no' prefix");
+            rc = eeInvalidInput;
+        }
+    }
+    int rc1 = _impl->_currentOption->finishSet(_impl->_errors);
+    rc = (rc != 0 ? rc : rc1);
+    _impl->_currentOption = NULL;
+    _impl->_reverseBoolean = false;
+    return _impl->keepError(rc);
+}
+
+int OptionsAssigner::finishSubSection()
+{
+    // Should only be called if we are in a subsection.
+    assert(_impl->inSubSection());
+    if (_impl->_currentOption != NULL)
+    {
+        // Possible error codes are stored and returned in the end.
+        finishOption();
+    }
+    _impl->_sectionStack.pop_back();
+    return 0;
+}
+
+int OptionsAssigner::finish()
+{
+    if (_impl->_currentOption != NULL)
+    {
+        // Possible error codes are stored and returned in the end.
+        finishOption();
+    }
+    while (_impl->inSubSection())
+    {
+        // Possible error codes are stored and returned in the end.
+        finishSubSection();
+    }
+    return _impl->_errorCode;
+}
+
+} // namespace gmx
diff --git a/src/gromacs/options/optionsassigner.h b/src/gromacs/options/optionsassigner.h
new file mode 100644 (file)
index 0000000..fd81977
--- /dev/null
@@ -0,0 +1,206 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \libinternal \file
+ * \brief
+ * Declares gmx::OptionsAssigner.
+ *
+ * This header is only needed when implementing option parsers.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \inlibraryapi
+ * \ingroup module_options
+ */
+#ifndef GMX_OPTIONS_OPTIONSASSIGNER_H
+#define GMX_OPTIONS_OPTIONSASSIGNER_H
+
+#include <string>
+
+namespace gmx
+{
+
+class AbstractErrorReporter;
+
+class Options;
+
+/*! \libinternal \brief
+ * Decorator class for assigning values to Options.
+ *
+ * This class extends the interface of an Options object by providing methods
+ * to set values for options.  It also keeps track of necessary state variables
+ * to assign values to options in subsections within the Options object.
+ * Typical use (without error checking):
+ * \code
+gmx::options::Options options("name", "Title");
+// Set up options
+
+gmx::error::StandardReporter errors;
+gmx::options::OptionsAssigner assigner(&options, &errors);
+assigner.startOption("opt1");
+assigner.appendValue("3");
+assigner.startSubSection("section");
+assigner.startOption("opt2"); // Now in the subsection
+assigner.appendValue("yes");
+assigner.finishSubSection()
+assigner.startOption("opt3"); // Again in the main options
+assigner.appendValue("2");
+assigner.finish(); // At minimum, the return value of finish() should be checked.
+ * \endcode
+ *
+ * As shown in the example, calling finishOption() or finishSubSection() is
+ * optional; they are automatically called when appropriate by startOption(),
+ * startSubSection(), and finish().
+ * However, you need to call them explicitly if you want to act on the return
+ * value: these calls do not influence the return value of
+ * startOption() / startSubSection().
+ * They do influence the return value of finish(), however.
+ * The finish() method should always be called.
+ *
+ * \inlibraryapi
+ * \ingroup module_options
+ */
+class OptionsAssigner
+{
+    public:
+        /*! \brief
+         * Creates an object that assigns to the given object.
+         */
+        OptionsAssigner(Options *options, AbstractErrorReporter *errors);
+        ~OptionsAssigner();
+
+        /*! \brief
+         * Returns the error reporter object passed to the constructor.
+         *
+         * This method is provided for convenience such that users of this
+         * class do not need to store a separate pointer to the error reporter
+         * if they need to use it.
+         */
+        AbstractErrorReporter *errorReporter() const;
+
+        /*! \brief
+         * Sets the assigner to recognize boolean options with a "no" prefix.
+         *
+         * With this option set, \c startOption("noname") is interpreted as
+         * \c startOption("name") followed by \c appendValue("no"), if there is
+         * no option by the name "noname", but there is a boolean option with
+         * name "name".
+         *
+         * By default, the prefix is not recognized.
+         *
+         * Can be set or cleared at any time, and will have effect on all
+         * subsequent calls of startOption().
+         */
+        void setAcceptBooleanNoPrefix(bool enabled);
+        /*! \brief
+         * Sets the assigner to find options in non-active sections.
+         *
+         * By default, options are only looked for in the currently active
+         * subsection.  With this option set, if no matching option is found in
+         * the current section, a breadth-first search is performed, first on
+         * all subsections of the current section, and then going up one level
+         * at a time.  The first matching option is used, and the current
+         * section is changed to the section that contains the matching option.
+         *
+         * Can be set or cleared at any time, and will have effect on all
+         * subsequent calls of startOption().
+         */
+        void setNoStrictSectioning(bool enabled);
+
+        /*! \brief
+         * Start assigning values.
+         *
+         * \retval 0 on success.
+         */
+        int start();
+        /*! \brief
+         * Start assigning values to options in a subsection.
+         *
+         * \param[in] name  Name of the subsection to start assigning to.
+         * \retval 0 if assignment can proceed.
+         *
+         * Does not call finishSubSection() automatically to enable nested
+         * sections.
+         */
+        int startSubSection(const char *name);
+        /*! \brief
+         * Start assigning values for an option.
+         *
+         * \param[in] name  Name of the option to start assigning to.
+         * \retval 0 if assignment can proceed.
+         */
+        int startOption(const char *name);
+        /*! \brief
+         * Appends a value to the value list of the current option.
+         *
+         * \param[in] value  String representation of the value to assign.
+         * \retval 0 if assignment was successful.
+         */
+        int appendValue(const std::string &value);
+        /*! \brief
+         * Finish assigning values for the current option.
+         *
+         * \retval 0 if there were no errors in the assignment.
+         *
+         * This function returns non-zero only if the error could not have been
+         * detected earlier, i.e., from the return value of appendValue().
+         */
+        int finishOption();
+        /*! \brief
+         * Finish assigning values to a subsection.
+         *
+         * \retval 0 for success.
+         *
+         * This function returns non-zero only if the error could not have been
+         * detected earlier.
+         */
+        int finishSubSection();
+        /*! \brief
+         * Finish assigning options through the object.
+         *
+         * \retval 0 if there were no errors in the assignment.
+         *
+         * If an error was detected in any of the other calls to this class,
+         * this function returns the error code of the first of such errors.
+         */
+        int finish();
+
+    private:
+        class Impl;
+
+        Impl                   *_impl;
+
+        // Disallow copy and assign.
+        OptionsAssigner(const OptionsAssigner &);
+        void operator =(const OptionsAssigner &);
+};
+
+} // namespace gmx
+
+#endif
diff --git a/src/gromacs/options/optionstoragetemplate.h b/src/gromacs/options/optionstoragetemplate.h
new file mode 100644 (file)
index 0000000..4a6e32d
--- /dev/null
@@ -0,0 +1,328 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \libinternal \file
+ * \brief
+ * Defines gmx::OptionStorageTemplate template.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \inlibraryapi
+ * \ingroup module_options
+ */
+#ifndef GMX_OPTIONS_OPTIONSTORAGETEMPLATE_H
+#define GMX_OPTIONS_OPTIONSTORAGETEMPLATE_H
+
+#include <cassert>
+
+#include <string>
+#include <vector>
+
+#include "abstractoption.h"
+#include "abstractoptionstorage.h"
+
+namespace gmx
+{
+
+class Options;
+
+/*! \brief
+ * Templated base class for constructing option value storage classes.
+ *
+ * \tparam T Assignable type that stores a single option value.
+ *
+ * Provides an implementation of the clear() and valueCount() methods of
+ * AbstractOptionStorage, as well as a basic implementation of processSet() and
+ * processAll().  This leaves typeString(), formatValue(), and convertValue()
+ * to be implemented in derived classes.
+ *
+ * \inlibraryapi
+ * \ingroup module_options
+ */
+template <typename T>
+class OptionStorageTemplate : public AbstractOptionStorage
+{
+    public:
+        //! Alias for the template class for use in base classes.
+        typedef OptionStorageTemplate<T> MyBase;
+        //! Type of the container that contains the current values.
+        typedef std::vector<T> ValueList;
+
+        virtual ~OptionStorageTemplate();
+
+        /*! \brief
+         * Initializes the storage from option settings.
+         *
+         * \retval 0 on success.
+         *
+         * \see OptionTemplate::createDefaultStorage()
+         */
+        template <class U>
+        int init(const OptionTemplate<T, U> &settings, Options *options);
+
+        // No implementation in this class for the pure virtual methods, but
+        // the declarations are still included for clarity.
+        virtual const char *typeString() const = 0;
+        virtual int valueCount() const { return _values->size(); }
+        virtual std::string formatValue(int i) const = 0;
+
+    protected:
+        //! Initializes default values (no storage).
+        OptionStorageTemplate();
+
+        virtual void clear();
+        /*! \copydoc AbstractOptionStorage::convertValue()
+         *
+         * Derived classes should call addValue() after they have converted
+         * \p value to the storage type.
+         */
+        virtual int convertValue(const std::string &value,
+                                 AbstractErrorReporter *errors) = 0;
+        /*! \copydoc AbstractOptionStorage::processSet()
+         *
+         * The implementation in OptionStorageTemplate copies the values
+         * from the main storage vector to alternate locations, and always
+         * succeeds.  Derived classes should always call the base class
+         * implementation if they override this method.
+         */
+        virtual int processSet(int nvalues,
+                               AbstractErrorReporter * /*errors*/)
+        {
+            processValues(nvalues, true);
+            return 0;
+        }
+        /*! \copydoc AbstractOptionStorage::processAll()
+         *
+         * The implementation in OptionStorageTemplate does nothing, and always
+         * returns zero.  Derived classes should still always call the base
+         * class implementation if they override this method.
+         */
+        virtual int processAll(AbstractErrorReporter * /*errors*/)
+        { return 0; }
+
+        /*! \brief
+         * Adds a value to the storage.
+         *
+         * \param[in] value  Value to add. A copy is made.
+         * \retval 0 on success.
+         * \retval ::eeInvalidInput if the maximum value count has been reached.
+         *
+         * Derived classes should call this function from the convertValue()
+         * implementation to add converted values to the storage.
+         * It is only necessary to check the return value if addValue() is
+         * called more than once from one convertValue() invocation, or if
+         * ::efConversionMayNotAddValues is specified.
+         */
+        int addValue(const T &value);
+        /*! \brief
+         * Store values in alternate locations.
+         *
+         * \param[in] nvalues  Number of values to process.
+         * \param[in] bDoArray Whether to put values in the array storage as
+         *      well.
+         *
+         * Stores the last \p nvalues values added with addValue() to the
+         * alternate storage locations.
+         * The current implementation asserts if it is called more than once
+         * with \p bDoArray set to true.
+         *
+         * Derived classes should call this method if they use addValue()
+         * outside convertValue(), e.g., to set a default value.  In such
+         * cases, \p bDoArray should be set to false.
+         */
+        void processValues(int nvalues, bool bDoArray);
+
+        //! Provides derived classes access to the current list of values.
+        ValueList &values() { return *_values; }
+        //! Provides derived classes access to the current list of values.
+        const ValueList &values() const { return *_values; }
+
+    private:
+        /*! \brief
+         * Vector for primary storage of option values.
+         *
+         * Is never NULL; points either to externally provided vector, or an
+         * internally allocated one.  The allocation is performed by init().
+         *
+         * addValue() adds values only to this storage.  Other memory locations
+         * are updated only when processAll() is called.
+         */
+        ValueList              *_values;
+        T                      *_store;
+        T                     **_storeArray;
+        int                    *_nvalptr;
+
+        // Copy and assign disallowed by base.
+};
+
+/*! \brief
+ * Helper function for creating storage objects.
+ *
+ * \tparam     T  Type of the settings object (derived from OptionTemplate).
+ * \tparam     S  Type of the storage object (derived from OptionStorageTemplate).
+ * \param[in]  settings  Settings object to pass to S::init().
+ * \param[in]  options   Options object to pass to S::init().
+ * \param[out] output    Pointer to the created storage object.
+ * \returns    The return value of S::init().
+ *
+ * Creates a new instance of S and calls the init() method with the provided
+ * parameters.  If the initialization fails, destroys the partially constructed
+ * object.
+ *
+ * \inlibraryapi
+ */
+template <class T, class S> int
+createOptionStorage(const T *settings, Options *options,
+                    AbstractOptionStorage **output)
+{
+    S *storage = new S;
+    int rc = storage->init(*settings, options);
+    if (rc != 0)
+    {
+        delete storage;
+        return rc;
+    }
+    *output = storage;
+    return 0;
+}
+
+
+template <typename T>
+OptionStorageTemplate<T>::OptionStorageTemplate()
+    : _values(NULL), _store(NULL), _storeArray(NULL), _nvalptr(NULL)
+{
+}
+
+
+template <typename T>
+OptionStorageTemplate<T>::~OptionStorageTemplate()
+{
+    if (!hasFlag(efExternalValueVector))
+    {
+        delete _values;
+    }
+}
+
+
+template <typename T>
+template <class U>
+int OptionStorageTemplate<T>::init(const OptionTemplate<T, U> &settings, Options *options)
+{
+    // It's impossible for the caller to do proper memory management if
+    // the provided memory is not initialized as NULL.
+    assert(settings._storeArray == NULL || *settings._storeArray == NULL);
+    int rc = AbstractOptionStorage::init(settings, options);
+    if (rc != 0)
+    {
+        return rc;
+    }
+    _store      = settings._store;
+    _storeArray = settings._storeArray;
+    _nvalptr    = settings._nvalptr;
+    _values     = settings._storeVector;
+    if (!_values)
+    {
+        // The flag should be set for proper error checking.
+        assert(!hasFlag(efExternalValueVector));
+        _values = new std::vector<T>;
+    }
+    // If the option does not support default values, one should not be set.
+    assert(!hasFlag(efNoDefaultValue) || settings._defaultValue == NULL);
+    if (!hasFlag(efNoDefaultValue))
+    {
+        if (settings._defaultValue != NULL)
+        {
+            _values->clear();
+            addValue(*settings._defaultValue);
+            processValues(1, false);
+            setFlag(efHasDefaultValue);
+        }
+        else if (!hasFlag(efExternalValueVector) && _store != NULL)
+        {
+            _values->clear();
+            int count = (settings.isVector() ?
+                            settings._maxValueCount : settings._minValueCount);
+            for (int i = 0; i < count; ++i)
+            {
+                _values->push_back(_store[i]);
+            }
+            setFlag(efHasDefaultValue);
+        }
+    }
+    return 0;
+}
+
+
+template <typename T>
+void OptionStorageTemplate<T>::clear()
+{
+    _values->clear();
+}
+
+
+template <typename T>
+int OptionStorageTemplate<T>::addValue(const T &value)
+{
+    int rc = incrementValueCount();
+    if (rc == 0)
+    {
+        _values->push_back(value);
+    }
+    return rc;
+}
+
+
+template <typename T>
+void OptionStorageTemplate<T>::processValues(int nvalues, bool bDoArray)
+{
+    if (_nvalptr)
+    {
+        *_nvalptr = _values->size();
+    }
+    if (bDoArray && _storeArray != NULL)
+    {
+        assert(*_storeArray == NULL);
+        *_storeArray = new T[_values->size()];
+    }
+    for (size_t i = _values->size() - nvalues; i < _values->size(); ++i)
+    {
+        if (_store)
+        {
+            _store[i] = (*_values)[i];
+        }
+        if (bDoArray && _storeArray != NULL)
+        {
+            (*_storeArray)[i] = (*_values)[i];
+        }
+    }
+}
+
+} // namespace gmx
+
+#endif
diff --git a/src/gromacs/options/optionsvisitor.cpp b/src/gromacs/options/optionsvisitor.cpp
new file mode 100644 (file)
index 0000000..fbf1f75
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * Implements classes in optionsvisitor.h.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_options
+ */
+#include "gromacs/options/optionsvisitor.h"
+
+#include "gromacs/options/abstractoptionstorage.h"
+#include "gromacs/options/options.h"
+
+#include "options-impl.h"
+
+namespace gmx
+{
+
+/********************************************************************
+ * OptionInfo
+ */
+
+OptionInfo::OptionInfo(const AbstractOptionStorage &option)
+    : _option(option)
+{
+}
+
+bool OptionInfo::isBoolean() const
+{
+    return _option.isBoolean();
+}
+
+bool OptionInfo::isFile() const
+{
+    return _option.isFile();
+}
+
+bool OptionInfo::isHidden() const
+{
+    return _option.isHidden();
+}
+
+const std::string &OptionInfo::name() const
+{
+    return _option.name();
+}
+
+const std::string &OptionInfo::description() const
+{
+    return _option.description();
+}
+
+const char *OptionInfo::type() const
+{
+    return _option.typeString();
+}
+
+int OptionInfo::valueCount() const
+{
+    return _option.valueCount();
+}
+
+std::string OptionInfo::formatValue(int i) const
+{
+    return _option.formatValue(i);
+}
+
+std::string OptionInfo::formatValues() const
+{
+    std::string result;
+    int count = valueCount();
+    for (int i = 0; i < count; ++i)
+    {
+        if (i != 0)
+        {
+            result.append(" ");
+        }
+        result.append(formatValue(i));
+    }
+    return result;
+}
+
+/********************************************************************
+ * OptionsIterator
+ */
+
+OptionsIterator::OptionsIterator(const Options &options)
+    : _options(options)
+{
+}
+
+void OptionsIterator::acceptSubSections(OptionsVisitor *visitor) const
+{
+    const Options::Impl::SubSectionList &subSectionList =
+        _options._impl->_subSections;
+    Options::Impl::SubSectionList::const_iterator i;
+    for (i = subSectionList.begin(); i != subSectionList.end(); ++i)
+    {
+        visitor->visitSubSection(*(*i));
+    }
+}
+
+void OptionsIterator::acceptOptions(OptionsVisitor *visitor) const
+{
+    const Options::Impl::OptionList &optionList =
+        _options._impl->_options;
+    Options::Impl::OptionList::const_iterator i;
+    for (i = optionList.begin(); i != optionList.end(); ++i)
+    {
+        visitor->visitOption(OptionInfo(*(*i)));
+    }
+}
+
+} // namespace gmx
diff --git a/src/gromacs/options/optionsvisitor.h b/src/gromacs/options/optionsvisitor.h
new file mode 100644 (file)
index 0000000..8e1a86c
--- /dev/null
@@ -0,0 +1,179 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \libinternal \file
+ * \brief
+ * Declares gmx::OptionsVisitor interface and supporting classes.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \inlibraryapi
+ * \ingroup module_options
+ */
+#ifndef GMX_OPTIONS_OPTIONSVISITOR_H
+#define GMX_OPTIONS_OPTIONSVISITOR_H
+
+#include <string>
+
+namespace gmx
+{
+
+class AbstractOptionStorage;
+class Options;
+
+/*! \libinternal \brief
+ * Wrapper class for accessing option information.
+ *
+ * This class isolates the details of the internal option implementation
+ * from option visitors.
+ *
+ * \see OptionsVisitor
+ *
+ * \inlibraryapi
+ * \ingroup module_options
+ */
+class OptionInfo
+{
+    public:
+        /*! \brief
+         * Wraps a given option object.
+         */
+        OptionInfo(const AbstractOptionStorage &option);
+
+        //! Returns true if the option is a boolean option.
+        bool isBoolean() const;
+        //! Returns true if the option is a file name option.
+        bool isFile() const;
+        //! Returns true if the option is a hidden option.
+        bool isHidden() const;
+        //! Returns the name of the option.
+        const std::string &name() const;
+        //! Returns the description of the option.
+        const std::string &description() const;
+        //! Returns the type of the option as a string.
+        const char *type() const;
+        //! Returns the number of values given for the option.
+        int valueCount() const;
+        //! Returns the i'th value of the option as a string.
+        std::string formatValue(int i) const;
+        //! Returns all the values of the option as a single string.
+        std::string formatValues() const;
+
+    private:
+        //! The wrapped option.
+        const AbstractOptionStorage &_option;
+
+        // Disallow copy and assign.
+        OptionInfo(const OptionInfo &);
+        void operator =(const OptionInfo &);
+};
+
+/*! \libinternal \brief
+ * Pure interface for visiting options in a Options object.
+ *
+ * \see OptionsIterator
+ *
+ * \inlibraryapi
+ * \ingroup module_options
+ */
+class OptionsVisitor
+{
+    public:
+        virtual ~OptionsVisitor() {}
+
+        /*! \brief
+         * Called for each subsection in Options.
+         */
+        virtual void visitSubSection(const Options &section) = 0;
+        /*! \brief
+         * Called for each option in Options.
+         */
+        virtual void visitOption(const OptionInfo &option) = 0;
+};
+
+/*! \libinternal \brief
+ * Decorator class for visiting options in a Options object.
+ *
+ * This class provides an interface for looping through subsections and
+ * options in a Options object.
+ *
+ * Typical use (loop over all options, iteratively descending into
+ * subsections):
+ * \code
+class Visitor : public gmx::options::OptionsVisitor
+{
+    public:
+        void visitSubSection(const Options &section)
+        {
+            OptionsIterator iterator(section);
+            iterator.acceptSubSections(this);
+            iterator.acceptOptions(this);
+        }
+
+        void visitOption(const OptionInfo &option)
+        {
+            // Do something.
+        }
+}
+
+Visitor().visitSubSection(options);
+ * \endcode
+ *
+ * \inlibraryapi
+ * \ingroup module_options
+ */
+class OptionsIterator
+{
+    public:
+        /*! \brief
+         * Creates an object for visiting options in a Options object.
+         */
+        OptionsIterator(const Options &options);
+
+        /*! \brief
+         * Visits each subsection in the wrapped Options object.
+         */
+        void acceptSubSections(OptionsVisitor *visitor) const;
+        /*! \brief
+         * Visits each option in the wrapped Options object.
+         */
+        void acceptOptions(OptionsVisitor *visitor) const;
+
+    private:
+        //! The wrapped Options object.
+        const Options          &_options;
+
+        // Disallow copy and assign.
+        OptionsIterator(const OptionsIterator &);
+        void operator =(const OptionsIterator &);
+};
+
+} // namespace gmx
+
+#endif
diff --git a/src/gromacs/options/tests/.gitignore b/src/gromacs/options/tests/.gitignore
new file mode 100644 (file)
index 0000000..0672786
--- /dev/null
@@ -0,0 +1 @@
+options-test
diff --git a/src/gromacs/options/tests/CMakeLists.txt b/src/gromacs/options/tests/CMakeLists.txt
new file mode 100644 (file)
index 0000000..18528b1
--- /dev/null
@@ -0,0 +1,17 @@
+IF (GTEST_FOUND)
+    include_directories(${GTEST_INCLUDE_DIRS})
+    set(UNITTEST_SOURCES cmdlineparser.cpp option.cpp optionsassigner.cpp)
+    IF (GMOCK_FOUND)
+        include_directories(${GMOCK_INCLUDE_DIRS})
+        list(APPEND UNITTEST_SOURCES
+             abstractoptionstorage.cpp test_gmock_main.cpp)
+    ELSE (GMOCK_FOUND)
+        list(APPEND UNITTEST_SOURCES test_main.cpp)
+    ENDIF (GMOCK_FOUND)
+    add_executable(options-test ${UNITTEST_SOURCES})
+    target_link_libraries(options-test libgromacs ${GTEST_LIBRARIES})
+    IF (GMOCK_FOUND)
+        target_link_libraries(options-test ${GMOCK_LIBRARIES})
+    ENDIF (GMOCK_FOUND)
+    add_test(OptionsUnitTests options-test)
+ENDIF (GTEST_FOUND)
diff --git a/src/gromacs/options/tests/abstractoptionstorage.cpp b/src/gromacs/options/tests/abstractoptionstorage.cpp
new file mode 100644 (file)
index 0000000..e03576e
--- /dev/null
@@ -0,0 +1,369 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * Tests proper handling of option storage.
+ *
+ * These tests check that methods in storage objects are called properly in all
+ * situations, and also that the OptionStorageTemplate class behaves properly.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_options
+ */
+#include <vector>
+#include <string>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "gromacs/fatalerror/fatalerror.h"
+#include "gromacs/errorreporting/emptyerrorreporter.h"
+#include "gromacs/options/abstractoption.h"
+#include "gromacs/options/options.h"
+#include "gromacs/options/optionstoragetemplate.h"
+#include "gromacs/options/optionsassigner.h"
+
+class MockOption;
+
+/*! \internal \brief
+ * Mock implementation of an option storage class for unit testing.
+ *
+ * Provides facilities for checking that correct methods are called, and for
+ * controlling how they add values using the base class methods.
+ *
+ * \ingroup module_options
+ */
+class MockOptionStorage : public gmx::OptionStorageTemplate<std::string>
+{
+    public:
+        /*! \brief
+         * Initializes the storage from option settings.
+         *
+         * \param[in] settings   Storage settings.
+         * \param[in] options    Options object.
+         * \retval 0 on success.
+         */
+        int init(const MockOption &settings, gmx::Options *options);
+
+        /*! \brief
+         * Calls addValue() in the base class and expects it to succeed.
+         */
+        void addValue(const std::string &value)
+        {
+            EXPECT_EQ(0, MyBase::addValue(value));
+        }
+        /*! \brief
+         * Calls addValue() in the base class and expects it to fail.
+         */
+        void addValueExpectFail(const std::string &value)
+        {
+            EXPECT_NE(0, MyBase::addValue(value));
+        }
+        /*! \brief
+         * Calls processAll() in the base class.
+         */
+        int processAllBase(gmx::AbstractErrorReporter *errors)
+        {
+            return MyBase::processAll(errors);
+        }
+        /*! \brief
+         * Calls addValue("dummy") in the base class and expects it to succeed.
+         */
+        void addDummyValue()
+        {
+            addValue("dummy");
+        }
+        /*! \brief
+         * Calls addValue("dummy") in the base class and expects it to fail.
+         */
+        void addDummyValueExpectFail()
+        {
+            addValueExpectFail("dummy");
+        }
+        /*! \brief
+         * Calls setFlag(efSet).
+         */
+        void setOption()
+        {
+            setFlag(gmx::efSet);
+        }
+
+        virtual const char *typeString() const { return "mock"; }
+        virtual std::string formatValue(int /*i*/) const { return ""; }
+
+        MOCK_METHOD2(convertValue, int(const std::string &value,
+                                       gmx::AbstractErrorReporter *errors));
+        MOCK_METHOD2(processSet, int(int nvalues,
+                                     gmx::AbstractErrorReporter *errors));
+        MOCK_METHOD1(processAll, int(gmx::AbstractErrorReporter *errors));
+};
+
+/*! \internal \brief
+ * Specifies an option that has a mock storage object for unit testing.
+ *
+ * \ingroup module_options
+ */
+class MockOption : public gmx::OptionTemplate<std::string, MockOption>
+{
+    public:
+        //! Initializes an option with the given name.
+        explicit MockOption(const char *name)
+            : MyBase(name), _storagePtr(NULL)
+        {
+        }
+
+        //! Sets the required flags to support storage that may not add values.
+        MyClass &mayNotAddValues()
+        { setFlag(gmx::efConversionMayNotAddValues); return me(); }
+        //! Sets an output pointer to give access to the created storage object.
+        MyClass &storageObject(MockOptionStorage **storagePtr)
+        { _storagePtr = storagePtr; return me(); }
+
+    private:
+        virtual int createDefaultStorage(gmx::Options *options,
+                                         gmx::AbstractOptionStorage **storage) const
+        {
+            int rc = gmx::createOptionStorage<MockOption, MockOptionStorage>(this, options, storage);
+            if (_storagePtr != NULL)
+            {
+                *_storagePtr = static_cast<MockOptionStorage *>(*storage);
+            }
+            return rc;
+        }
+
+        MockOptionStorage     **_storagePtr;
+};
+
+int MockOptionStorage::init(const MockOption &settings, gmx::Options *options)
+{
+    using ::testing::_;
+    using ::testing::DoAll;
+    using ::testing::Invoke;
+    using ::testing::Return;
+    using ::testing::WithArg;
+    ON_CALL(*this, convertValue(_, _))
+        .WillByDefault(DoAll(WithArg<0>(Invoke(this, &MockOptionStorage::addValue)),
+                             Return(0)));
+    ON_CALL(*this, processAll(_))
+        .WillByDefault(Invoke(this, &MockOptionStorage::processAllBase));
+    return MyBase::init(settings, options);
+}
+
+namespace
+{
+
+/*
+ * Tests that finish() can set a required option even if the user has not
+ * provided it.
+ */
+TEST(AbstractOptionStorageTest, HandlesSetInFinish)
+{
+    gmx::Options                options(NULL, NULL);
+    std::vector<std::string>    values;
+    MockOptionStorage          *mock;
+    options.addOption(MockOption("name").storageObject(&mock).required()
+                          .storeVector(&values));
+
+    {
+        ::testing::InSequence dummy;
+        using ::testing::_;
+        using ::testing::DoAll;
+        using ::testing::Return;
+        using ::testing::InvokeWithoutArgs;
+        EXPECT_CALL(*mock, processAll(_))
+            .WillOnce(DoAll(InvokeWithoutArgs(mock, &MockOptionStorage::setOption),
+                            InvokeWithoutArgs(mock, &MockOptionStorage::addDummyValue),
+                            Return(0)));
+    }
+
+    gmx::EmptyErrorReporter errors;
+    gmx::OptionsAssigner assigner(&options, &errors);
+    EXPECT_EQ(0, assigner.finish());
+    EXPECT_EQ(0, options.finish(&errors));
+
+    ASSERT_EQ(1U, values.size());
+    EXPECT_EQ("dummy", values[0]);
+}
+
+/*
+ * Tests that storage works if the storage object does not add a value in a
+ * call to appendValue().
+ */
+TEST(AbstractOptionStorageTest, HandlesValueRemoval)
+{
+    gmx::Options                options(NULL, NULL);
+    std::vector<std::string>    values;
+    MockOptionStorage          *mock;
+    options.addOption(MockOption("name").storageObject(&mock).mayNotAddValues()
+                          .storeVector(&values).multiValue());
+
+    {
+        ::testing::InSequence dummy;
+        using ::testing::_;
+        using ::testing::Return;
+        EXPECT_CALL(*mock, convertValue("a", _));
+        EXPECT_CALL(*mock, convertValue("b", _))
+            .WillOnce(Return(0));
+        EXPECT_CALL(*mock, convertValue("c", _));
+        EXPECT_CALL(*mock, processSet(2, _));
+        EXPECT_CALL(*mock, processAll(_));
+    }
+
+    gmx::EmptyErrorReporter errors;
+    gmx::OptionsAssigner assigner(&options, &errors);
+    EXPECT_EQ(0, assigner.startOption("name"));
+    EXPECT_EQ(0, assigner.appendValue("a"));
+    EXPECT_EQ(0, assigner.appendValue("b"));
+    EXPECT_EQ(0, assigner.appendValue("c"));
+    EXPECT_EQ(0, assigner.finish());
+    EXPECT_EQ(0, options.finish(&errors));
+
+    ASSERT_EQ(2U, values.size());
+    EXPECT_EQ("a", values[0]);
+    EXPECT_EQ("c", values[1]);
+}
+
+/*
+ * Tests that storage works if the storage object adds more than one value in
+ * one call to appendValue().
+ */
+TEST(AbstractOptionStorageTest, HandlesValueAddition)
+{
+    gmx::Options                options(NULL, NULL);
+    std::vector<std::string>    values;
+    MockOptionStorage          *mock;
+    options.addOption(MockOption("name").storageObject(&mock)
+                          .storeVector(&values).multiValue());
+
+    {
+        ::testing::InSequence dummy;
+        using ::testing::_;
+        using ::testing::DoAll;
+        using ::testing::InvokeWithoutArgs;
+        using ::testing::Return;
+        EXPECT_CALL(*mock, convertValue("a", _));
+        EXPECT_CALL(*mock, convertValue("b", _))
+            .WillOnce(DoAll(InvokeWithoutArgs(mock, &MockOptionStorage::addDummyValue),
+                            InvokeWithoutArgs(mock, &MockOptionStorage::addDummyValue),
+                            Return(0)));
+        EXPECT_CALL(*mock, processSet(3, _));
+        EXPECT_CALL(*mock, processAll(_));
+    }
+
+    gmx::EmptyErrorReporter errors;
+    gmx::OptionsAssigner assigner(&options, &errors);
+    EXPECT_EQ(0, assigner.startOption("name"));
+    EXPECT_EQ(0, assigner.appendValue("a"));
+    EXPECT_EQ(0, assigner.appendValue("b"));
+    EXPECT_EQ(0, assigner.finish());
+    EXPECT_EQ(0, options.finish(&errors));
+
+    ASSERT_EQ(3U, values.size());
+    EXPECT_EQ("a", values[0]);
+    EXPECT_EQ("dummy", values[1]);
+    EXPECT_EQ("dummy", values[2]);
+}
+
+/*
+ * Tests that storage works if the storage object adds more than one value in
+ * one call to appendValue(), and this results in too many values.
+ */
+TEST(AbstractOptionStorageTest, HandlesTooManyValueAddition)
+{
+    gmx::Options                options(NULL, NULL);
+    std::vector<std::string>    values;
+    MockOptionStorage          *mock;
+    options.addOption(MockOption("name").storageObject(&mock)
+                          .storeVector(&values).valueCount(2));
+
+    {
+        ::testing::InSequence dummy;
+        using ::testing::_;
+        using ::testing::DoAll;
+        using ::testing::InvokeWithoutArgs;
+        using ::testing::Return;
+        EXPECT_CALL(*mock, convertValue("a", _));
+        EXPECT_CALL(*mock, convertValue("b", _))
+            .WillOnce(DoAll(InvokeWithoutArgs(mock, &MockOptionStorage::addDummyValue),
+                            InvokeWithoutArgs(mock, &MockOptionStorage::addDummyValueExpectFail),
+                            Return(gmx::eeInvalidInput)));
+        EXPECT_CALL(*mock, processSet(2, _));
+        EXPECT_CALL(*mock, processAll(_));
+    }
+
+    gmx::EmptyErrorReporter errors;
+    gmx::OptionsAssigner assigner(&options, &errors);
+    EXPECT_EQ(0, assigner.startOption("name"));
+    EXPECT_EQ(0, assigner.appendValue("a"));
+    EXPECT_NE(0, assigner.appendValue("b"));
+    EXPECT_NE(0, assigner.finish());
+    EXPECT_EQ(0, options.finish(&errors));
+
+    ASSERT_EQ(2U, values.size());
+    EXPECT_EQ("a", values[0]);
+    EXPECT_EQ("dummy", values[1]);
+}
+
+/*
+ * Tests that the storage object is properly invoked even if no output values
+ * should be produced.
+ */
+TEST(AbstractOptionStorageTest, AllowsEmptyValues)
+{
+    gmx::Options                options(NULL, NULL);
+    std::vector<std::string>    values;
+    MockOptionStorage          *mock;
+    options.addOption(MockOption("name").storageObject(&mock).mayNotAddValues()
+                          .storeVector(&values).valueCount(0));
+
+    {
+        ::testing::InSequence dummy;
+        using ::testing::_;
+        using ::testing::DoAll;
+        using ::testing::InvokeWithoutArgs;
+        using ::testing::Return;
+        EXPECT_CALL(*mock, convertValue("a", _))
+            .WillOnce(Return(0));
+        EXPECT_CALL(*mock, processSet(0, _));
+        EXPECT_CALL(*mock, processAll(_));
+    }
+
+    gmx::EmptyErrorReporter errors;
+    gmx::OptionsAssigner assigner(&options, &errors);
+    EXPECT_EQ(0, assigner.startOption("name"));
+    EXPECT_EQ(0, assigner.appendValue("a"));
+    EXPECT_EQ(0, assigner.finish());
+    EXPECT_EQ(0, options.finish(&errors));
+
+    ASSERT_EQ(0U, values.size());
+}
+
+} // namespace
diff --git a/src/gromacs/options/tests/cmdlineparser.cpp b/src/gromacs/options/tests/cmdlineparser.cpp
new file mode 100644 (file)
index 0000000..1a41faa
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * Tests gmx::CommandLineParser.
+ *
+ * These tests exercise a large fraction of the code, so they may
+ * catch errors in other parts than just in command-line parsing.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_options
+ */
+#include <cstdlib>
+#include <cstring>
+#include <vector>
+
+#include <gtest/gtest.h>
+
+#include "gromacs/errorreporting/emptyerrorreporter.h"
+#include "gromacs/options/basicoptions.h"
+#include "gromacs/options/cmdlineparser.h"
+#include "gromacs/options/options.h"
+
+namespace
+{
+
+class CommandLineParserTest : public ::testing::Test
+{
+    public:
+        CommandLineParserTest();
+        ~CommandLineParserTest();
+
+        void createArguments(const char *cmdline[]);
+
+        gmx::Options            _options;
+        gmx::EmptyErrorReporter _errors;
+        gmx::CommandLineParser  _parser;
+        bool                    _flag;
+        std::vector<int>        _ivalues;
+        std::vector<double>     _dvalues;
+        int                     _argc;
+        char                  **_argv;
+};
+
+CommandLineParserTest::CommandLineParserTest()
+    : _options(NULL, NULL), _parser(&_options, &_errors),
+      _flag(false),
+      _argc(0), _argv(NULL)
+{
+    using gmx::BooleanOption;
+    using gmx::IntegerOption;
+    using gmx::DoubleOption;
+    _options.addOption(BooleanOption("flag").store(&_flag));
+    _options.addOption(IntegerOption("mvi").storeVector(&_ivalues).multiValue());
+    _options.addOption(DoubleOption("mvd").storeVector(&_dvalues).allowMultiple());
+}
+
+CommandLineParserTest::~CommandLineParserTest()
+{
+    if (_argv != NULL)
+    {
+        for (int i = 0; i < _argc; ++i)
+        {
+            free(_argv[i]);
+        }
+    }
+    delete [] _argv;
+}
+
+void CommandLineParserTest::createArguments(const char *cmdline[])
+{
+    _argc = 0;
+    while (cmdline[_argc] != NULL) ++_argc;
+    ++_argc;
+
+    _argv = new char *[_argc];
+    _argv[0] = strdup("test");
+    for (int i = 1; i < _argc; ++i)
+    {
+        _argv[i] = strdup(cmdline[i - 1]);
+    }
+}
+
+TEST_F(CommandLineParserTest, HandlesSingleValues)
+{
+    const char *cmdline[] = {"-flag", "yes", "-mvi", "2", "-mvd", "2.7", NULL};
+    createArguments(cmdline);
+    ASSERT_EQ(0, _parser.parse(&_argc, _argv));
+    ASSERT_EQ(0, _options.finish(&_errors));
+
+    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
diff --git a/src/gromacs/options/tests/option.cpp b/src/gromacs/options/tests/option.cpp
new file mode 100644 (file)
index 0000000..3146cdc
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * Tests construction of basic option types.
+ *
+ * Most of the tests for the basic options are in optionsassigner.cpp.
+ * This file only tests behavior that should fail in parameter construction,
+ * which would result in higher-level code asserting.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_options
+ */
+#include <vector>
+#include <string>
+
+#include <gtest/gtest.h>
+
+#include "gromacs/options/basicoptions.h"
+
+#include "../basicoptionstorage.h"
+
+namespace
+{
+
+TEST(OptionTest, SetsNameAndDescription)
+{
+    gmx::IntegerOptionStorage   option;
+    int value = -1;
+    using gmx::IntegerOption;
+    ASSERT_EQ(0, option.init(IntegerOption("name").store(&value)
+                                 .description("Description"), NULL));
+    EXPECT_EQ("name", option.name());
+    EXPECT_EQ("Description", option.description());
+    EXPECT_FALSE(option.isSet());
+}
+
+TEST(OptionTest, FailsOnNonsafeStorage)
+{
+    gmx::IntegerOptionStorage   option;
+    int value = -1;
+    using gmx::IntegerOption;
+    ASSERT_NE(0, option.init(IntegerOption("name").store(&value)
+                                 .multiValue(), NULL));
+}
+
+TEST(OptionTest, FailsOnIncorrectEnumDefaultValue)
+{
+    gmx::StringOptionStorage    option;
+    std::string                 value;
+    const char * const          allowed[] = { "none", "test", "value", NULL };
+    using gmx::StringOption;
+    ASSERT_NE(0, option.init(StringOption("name").store(&value)
+                                 .enumValue(allowed)
+                                 .defaultValue("unknown"), NULL));
+}
+
+} // namespace
diff --git a/src/gromacs/options/tests/optionsassigner.cpp b/src/gromacs/options/tests/optionsassigner.cpp
new file mode 100644 (file)
index 0000000..665ba19
--- /dev/null
@@ -0,0 +1,603 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * Tests option assignment.
+ *
+ * In addition to testing gmx::OptionsAssigner, these are the main
+ * tests for the classes from basicoptions.h and basicoptionstorage.h (and
+ * their base classes) that actually implement the behavior, as well as for the
+ * internal implementation of the gmx::Options and gmx::Option classes.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_options
+ */
+#include <vector>
+
+#include <gtest/gtest.h>
+
+#include "gromacs/errorreporting/emptyerrorreporter.h"
+#include "gromacs/options/basicoptions.h"
+#include "gromacs/options/options.h"
+#include "gromacs/options/optionsassigner.h"
+
+namespace
+{
+
+TEST(OptionsAssignerTest, HandlesMissingRequiredParameter)
+{
+    gmx::Options options(NULL, NULL);
+    int value = 0;
+    using gmx::IntegerOption;
+    options.addOption(IntegerOption("p").store(&value).required());
+
+    gmx::EmptyErrorReporter errors;
+    EXPECT_NE(0, options.finish(&errors));
+}
+
+TEST(OptionsAssignerTest, HandlesInvalidMultipleParameter)
+{
+    gmx::Options options(NULL, NULL);
+    std::vector<int> values;
+    using gmx::IntegerOption;
+    options.addOption(IntegerOption("p").storeVector(&values).multiValue());
+
+    gmx::EmptyErrorReporter errors;
+    gmx::OptionsAssigner assigner(&options, &errors);
+    EXPECT_EQ(0, assigner.startOption("p"));
+    EXPECT_EQ(0, assigner.appendValue("1"));
+    EXPECT_NE(0, assigner.startOption("p"));
+    EXPECT_NE(0, assigner.finish());
+}
+
+TEST(OptionsAssignerTest, HandlesMultipleParameter)
+{
+    gmx::Options options(NULL, NULL);
+    std::vector<int> values;
+    using gmx::IntegerOption;
+    options.addOption(IntegerOption("p").storeVector(&values).allowMultiple());
+
+    gmx::EmptyErrorReporter errors;
+    gmx::OptionsAssigner assigner(&options, &errors);
+    EXPECT_EQ(0, assigner.startOption("p"));
+    EXPECT_EQ(0, assigner.appendValue("1"));
+    EXPECT_EQ(0, assigner.startOption("p"));
+    EXPECT_EQ(0, assigner.appendValue("2"));
+    EXPECT_EQ(0, assigner.finish());
+    EXPECT_EQ(0, options.finish(&errors));
+    EXPECT_TRUE(options.isSet("p"));
+    ASSERT_EQ(2U, values.size());
+    EXPECT_EQ(1, values[0]);
+    EXPECT_EQ(2, values[1]);
+}
+
+TEST(OptionsAssignerTest, HandlesMissingValue)
+{
+    gmx::Options options(NULL, NULL);
+    int value1 = 0, value2 = 0;
+    using gmx::IntegerOption;
+    options.addOption(IntegerOption("p").store(&value1));
+    options.addOption(IntegerOption("q").store(&value2));
+
+    gmx::EmptyErrorReporter errors;
+    gmx::OptionsAssigner assigner(&options, &errors);
+    EXPECT_EQ(0, assigner.startOption("p"));
+    EXPECT_EQ(0, assigner.startOption("q"));
+    EXPECT_EQ(0, assigner.appendValue("2"));
+    EXPECT_NE(0, assigner.finish());
+}
+
+TEST(OptionsAssignerTest, HandlesExtraValue)
+{
+    gmx::Options options(NULL, NULL);
+    int value1 = 0;
+    using gmx::IntegerOption;
+    options.addOption(IntegerOption("p").store(&value1));
+
+    gmx::EmptyErrorReporter errors;
+    gmx::OptionsAssigner assigner(&options, &errors);
+    EXPECT_EQ(0, assigner.startOption("p"));
+    EXPECT_EQ(0, assigner.appendValue("2"));
+    EXPECT_NE(0, assigner.appendValue("3"));
+    EXPECT_NE(0, assigner.finish());
+}
+
+TEST(OptionsAssignerTest, HandlesSubSections)
+{
+    gmx::Options options(NULL, NULL);
+    gmx::Options sub1("section1", NULL);
+    gmx::Options sub2("section2", NULL);
+    int value = 3;
+    int value1 = 1;
+    int value2 = 2;
+    using gmx::IntegerOption;
+    options.addOption(IntegerOption("p").store(&value));
+    sub1.addOption(IntegerOption("p").store(&value1));
+    sub2.addOption(IntegerOption("p").store(&value2));
+    options.addSubSection(&sub1);
+    options.addSubSection(&sub2);
+
+    gmx::EmptyErrorReporter errors;
+    gmx::OptionsAssigner assigner(&options, &errors);
+    EXPECT_EQ(0, assigner.startSubSection("section1"));
+    EXPECT_EQ(0, assigner.startOption("p"));
+    EXPECT_EQ(0, assigner.appendValue("5"));
+    EXPECT_EQ(0, assigner.finishSubSection());
+    EXPECT_EQ(0, assigner.startOption("p"));
+    EXPECT_EQ(0, assigner.appendValue("4"));
+    EXPECT_EQ(0, assigner.startSubSection("section2"));
+    EXPECT_EQ(0, assigner.startOption("p"));
+    EXPECT_EQ(0, assigner.appendValue("6"));
+    EXPECT_EQ(0, assigner.finish());
+    EXPECT_EQ(0, options.finish(&errors));
+
+    EXPECT_EQ(4, value);
+    EXPECT_EQ(5, value1);
+    EXPECT_EQ(6, value2);
+}
+
+TEST(OptionsAssignerTest, HandlesNoStrictSubSections)
+{
+    gmx::Options options(NULL, NULL);
+    gmx::Options sub1("section1", NULL);
+    gmx::Options sub2("section2", NULL);
+    int pvalue = 3;
+    int pvalue1 = 1;
+    int qvalue  = 4;
+    int pvalue2 = 2;
+    int rvalue  = 5;
+    using gmx::IntegerOption;
+    options.addOption(IntegerOption("p").store(&pvalue));
+    sub1.addOption(IntegerOption("p").store(&pvalue1));
+    sub1.addOption(IntegerOption("q").store(&qvalue));
+    sub2.addOption(IntegerOption("p").store(&pvalue2));
+    sub2.addOption(IntegerOption("r").store(&rvalue));
+    options.addSubSection(&sub1);
+    options.addSubSection(&sub2);
+
+    gmx::EmptyErrorReporter errors;
+    gmx::OptionsAssigner assigner(&options, &errors);
+    assigner.setNoStrictSectioning(true);
+    EXPECT_EQ(0, assigner.startOption("q"));
+    EXPECT_EQ(0, assigner.appendValue("6"));
+    EXPECT_EQ(0, assigner.startOption("p"));
+    EXPECT_EQ(0, assigner.appendValue("7"));
+    EXPECT_EQ(0, assigner.startOption("r"));
+    EXPECT_EQ(0, assigner.appendValue("8"));
+    EXPECT_EQ(0, assigner.startOption("p"));
+    EXPECT_EQ(0, assigner.appendValue("9"));
+    EXPECT_EQ(0, assigner.finishSubSection());
+    EXPECT_EQ(0, assigner.startOption("p"));
+    EXPECT_EQ(0, assigner.appendValue("10"));
+    EXPECT_EQ(0, assigner.finish());
+    EXPECT_EQ(0, options.finish(&errors));
+
+    EXPECT_EQ(6, qvalue);
+    EXPECT_EQ(7, pvalue1);
+    EXPECT_EQ(8, rvalue);
+    EXPECT_EQ(9, pvalue2);
+    EXPECT_EQ(10, pvalue);
+}
+
+TEST(OptionsAssignerTest, HandlesMultipleSources)
+{
+    gmx::Options options(NULL, NULL);
+    int value = -1;
+    using gmx::IntegerOption;
+    options.addOption(IntegerOption("p").store(&value));
+
+    gmx::EmptyErrorReporter errors;
+    gmx::OptionsAssigner assigner(&options, &errors);
+    EXPECT_EQ(0, assigner.start());
+    EXPECT_EQ(0, assigner.startOption("p"));
+    EXPECT_EQ(0, assigner.appendValue("1"));
+    EXPECT_EQ(0, assigner.finish());
+    gmx::OptionsAssigner assigner2(&options, &errors);
+    EXPECT_EQ(0, assigner2.start());
+    EXPECT_EQ(0, assigner2.startOption("p"));
+    EXPECT_EQ(0, assigner2.appendValue("2"));
+    EXPECT_EQ(0, assigner2.finish());
+    EXPECT_EQ(0, options.finish(&errors));
+
+    EXPECT_EQ(2, value);
+}
+
+
+TEST(OptionsAssignerBooleanTest, StoresYesValue)
+{
+    gmx::Options options(NULL, NULL);
+    bool  value = false;
+    using gmx::BooleanOption;
+    options.addOption(BooleanOption("p").store(&value));
+
+    gmx::EmptyErrorReporter errors;
+    gmx::OptionsAssigner assigner(&options, &errors);
+    EXPECT_EQ(0, assigner.startOption("p"));
+    EXPECT_EQ(0, assigner.appendValue("yes"));
+    EXPECT_EQ(0, assigner.finish());
+    EXPECT_EQ(0, options.finish(&errors));
+
+    EXPECT_TRUE(value);
+}
+
+TEST(OptionsAssignerBooleanTest, SetsBooleanWithoutExplicitValue)
+{
+    gmx::Options options(NULL, NULL);
+    bool value = false;
+    using gmx::BooleanOption;
+    options.addOption(BooleanOption("p").store(&value));
+
+    gmx::EmptyErrorReporter errors;
+    gmx::OptionsAssigner assigner(&options, &errors);
+    EXPECT_EQ(0, assigner.startOption("p"));
+    EXPECT_EQ(0, assigner.finish());
+    EXPECT_EQ(0, options.finish(&errors));
+
+    EXPECT_TRUE(value);
+}
+
+TEST(OptionsAssignerBooleanTest, ClearsBooleanWithPrefixNo)
+{
+    gmx::Options options(NULL, NULL);
+    bool value = true;
+    using gmx::BooleanOption;
+    options.addOption(BooleanOption("p").store(&value));
+
+    gmx::EmptyErrorReporter errors;
+    gmx::OptionsAssigner assigner(&options, &errors);
+    assigner.setAcceptBooleanNoPrefix(true);
+    EXPECT_EQ(0, assigner.startOption("nop"));
+    EXPECT_EQ(0, assigner.finish());
+    EXPECT_EQ(0, options.finish(&errors));
+
+    EXPECT_FALSE(value);
+}
+
+TEST(OptionsAssignerBooleanTest, HandlesBooleanWithPrefixAndValue)
+{
+    gmx::Options options(NULL, NULL);
+    bool value = false;
+    using gmx::BooleanOption;
+    options.addOption(BooleanOption("p").store(&value));
+
+    gmx::EmptyErrorReporter errors;
+    gmx::OptionsAssigner assigner(&options, &errors);
+    assigner.setAcceptBooleanNoPrefix(true);
+    EXPECT_EQ(0, assigner.startOption("nop"));
+    assigner.appendValue("no");
+    int rc = assigner.finish();
+    // It's OK to fail, but if it doesn't, it should work.
+    if (rc == 0)
+    {
+        EXPECT_EQ(0, options.finish(&errors));
+        EXPECT_TRUE(value);
+    }
+}
+
+
+TEST(OptionsAssignerIntegerTest, StoresSingleValue)
+{
+    gmx::Options options(NULL, NULL);
+    int value = 1;
+    using gmx::IntegerOption;
+    options.addOption(IntegerOption("p").store(&value));
+
+    gmx::EmptyErrorReporter errors;
+    gmx::OptionsAssigner assigner(&options, &errors);
+    ASSERT_EQ(0, assigner.startOption("p"));
+    ASSERT_EQ(0, assigner.appendValue("3"));
+    EXPECT_EQ(0, assigner.finish());
+    EXPECT_EQ(0, options.finish(&errors));
+
+    EXPECT_EQ(3, value);
+}
+
+TEST(OptionsAssignerIntegerTest, StoresDefaultValue)
+{
+    gmx::Options options(NULL, NULL);
+    int value = -1;
+    using gmx::IntegerOption;
+    options.addOption(IntegerOption("p").store(&value).defaultValue(2));
+    EXPECT_EQ(2, value);
+
+    gmx::EmptyErrorReporter errors;
+    gmx::OptionsAssigner assigner(&options, &errors);
+    EXPECT_EQ(0, assigner.finish());
+    EXPECT_EQ(0, options.finish(&errors));
+
+    EXPECT_EQ(2, value);
+}
+
+TEST(OptionsAssignerIntegerTest, StoresToArray)
+{
+    gmx::Options          options(NULL, NULL);
+    int                  *values = NULL;
+    int                   nval = -1;
+    using gmx::IntegerOption;
+    options.addOption(IntegerOption("p").storeArray(&values, &nval).multiValue());
+
+    gmx::EmptyErrorReporter errors;
+    gmx::OptionsAssigner assigner(&options, &errors);
+    ASSERT_EQ(0, assigner.startOption("p"));
+    ASSERT_EQ(0, assigner.appendValue("-2"));
+    ASSERT_EQ(0, assigner.appendValue("1"));
+    ASSERT_EQ(0, assigner.appendValue("4"));
+    EXPECT_EQ(0, assigner.finish());
+    EXPECT_EQ(0, options.finish(&errors));
+
+    EXPECT_EQ(3, nval);
+    EXPECT_EQ(-2, values[0]);
+    EXPECT_EQ(1, values[1]);
+    EXPECT_EQ(4, values[2]);
+    delete[] values;
+}
+
+TEST(OptionsAssignerIntegerTest, StoresToVector)
+{
+    gmx::Options          options(NULL, NULL);
+    std::vector<int>      values;
+    using gmx::IntegerOption;
+    options.addOption(IntegerOption("p").storeVector(&values).multiValue());
+
+    gmx::EmptyErrorReporter errors;
+    gmx::OptionsAssigner assigner(&options, &errors);
+    ASSERT_EQ(0, assigner.startOption("p"));
+    ASSERT_EQ(0, assigner.appendValue("-2"));
+    ASSERT_EQ(0, assigner.appendValue("1"));
+    ASSERT_EQ(0, assigner.appendValue("4"));
+    EXPECT_EQ(0, assigner.finish());
+    EXPECT_EQ(0, options.finish(&errors));
+
+    EXPECT_EQ(3U, values.size());
+    EXPECT_EQ(-2, values[0]);
+    EXPECT_EQ(1, values[1]);
+    EXPECT_EQ(4, values[2]);
+}
+
+TEST(OptionsAssignerIntegerTest, HandlesVectors)
+{
+    gmx::Options options(NULL, NULL);
+    int  vec[3] = {0, 0, 0};
+    using gmx::IntegerOption;
+    options.addOption(IntegerOption("p").store(vec).vector());
+
+    gmx::EmptyErrorReporter errors;
+    gmx::OptionsAssigner assigner(&options, &errors);
+    ASSERT_EQ(0, assigner.startOption("p"));
+    ASSERT_EQ(0, assigner.appendValue("-2"));
+    ASSERT_EQ(0, assigner.appendValue("1"));
+    ASSERT_EQ(0, assigner.appendValue("4"));
+    EXPECT_EQ(0, assigner.finish());
+    EXPECT_EQ(0, options.finish(&errors));
+
+    EXPECT_EQ(-2, vec[0]);
+    EXPECT_EQ(1, vec[1]);
+    EXPECT_EQ(4, vec[2]);
+}
+
+TEST(OptionsAssignerIntegerTest, HandlesVectorFromSingleValue)
+{
+    gmx::Options options(NULL, NULL);
+    int  vec[3] = {0, 0, 0};
+    using gmx::IntegerOption;
+    options.addOption(IntegerOption("p").store(vec).vector());
+
+    gmx::EmptyErrorReporter errors;
+    gmx::OptionsAssigner assigner(&options, &errors);
+    ASSERT_EQ(0, assigner.startOption("p"));
+    ASSERT_EQ(0, assigner.appendValue("2"));
+    EXPECT_EQ(0, assigner.finish());
+    EXPECT_EQ(0, options.finish(&errors));
+
+    EXPECT_EQ(2, vec[0]);
+    EXPECT_EQ(2, vec[1]);
+    EXPECT_EQ(2, vec[2]);
+}
+
+TEST(OptionsAssignerIntegerTest, HandlesVectorsWithDefaultValue)
+{
+    gmx::Options options(NULL, NULL);
+    int  vec[3] = {3, 2, 1};
+    using gmx::IntegerOption;
+    options.addOption(IntegerOption("p").store(vec).vector());
+
+    gmx::EmptyErrorReporter errors;
+    EXPECT_EQ(0, options.finish(&errors));
+
+    EXPECT_EQ(3, vec[0]);
+    EXPECT_EQ(2, vec[1]);
+    EXPECT_EQ(1, vec[2]);
+}
+
+
+TEST(OptionsAssignerDoubleTest, StoresSingleValue)
+{
+    gmx::Options options(NULL, NULL);
+    double value = 0.0;
+    using gmx::DoubleOption;
+    options.addOption(DoubleOption("p").store(&value));
+
+    gmx::EmptyErrorReporter errors;
+    gmx::OptionsAssigner assigner(&options, &errors);
+    ASSERT_EQ(0, assigner.startOption("p"));
+    ASSERT_EQ(0, assigner.appendValue("2.7"));
+    ASSERT_EQ(0, assigner.finish());
+    ASSERT_EQ(0, options.finish(&errors));
+
+    EXPECT_DOUBLE_EQ(2.7, value);
+}
+
+
+TEST(OptionsAssignerStringTest, StoresSingleValue)
+{
+    gmx::Options           options(NULL, NULL);
+    std::string            value;
+    using gmx::StringOption;
+    options.addOption(StringOption("p").store(&value));
+
+    gmx::EmptyErrorReporter errors;
+    gmx::OptionsAssigner assigner(&options, &errors);
+    ASSERT_EQ(0, assigner.startOption("p"));
+    ASSERT_EQ(0, assigner.appendValue("value"));
+    ASSERT_EQ(0, assigner.finish());
+    ASSERT_EQ(0, options.finish(&errors));
+
+    EXPECT_EQ("value", value);
+}
+
+TEST(OptionsAssignerStringTest, HandlesEnumValue)
+{
+    gmx::Options           options(NULL, NULL);
+    std::string            value;
+    const char * const     allowed[] = { "none", "test", "value", NULL };
+    int                    index = -1;
+    using gmx::StringOption;
+    options.addOption(StringOption("p").store(&value)
+                          .enumValue(allowed)
+                          .storeEnumIndex(&index));
+
+    gmx::EmptyErrorReporter errors;
+    gmx::OptionsAssigner assigner(&options, &errors);
+    ASSERT_EQ(0, assigner.startOption("p"));
+    ASSERT_EQ(0, assigner.appendValue("test"));
+    ASSERT_EQ(0, assigner.finish());
+    ASSERT_EQ(0, options.finish(&errors));
+
+    EXPECT_EQ("test", value);
+    EXPECT_EQ(1, index);
+}
+
+TEST(OptionsAssignerStringTest, HandlesIncorrectEnumValue)
+{
+    gmx::Options           options(NULL, NULL);
+    std::string            value;
+    const char * const     allowed[] = { "none", "test", "value", NULL };
+    int                    index = -1;
+    using gmx::StringOption;
+    options.addOption(StringOption("p").store(&value)
+                          .enumValue(allowed)
+                          .storeEnumIndex(&index));
+
+    gmx::EmptyErrorReporter errors;
+    gmx::OptionsAssigner assigner(&options, &errors);
+    ASSERT_EQ(0, assigner.startOption("p"));
+    ASSERT_NE(0, assigner.appendValue("unknown"));
+}
+
+TEST(OptionsAssignerStringTest, CompletesEnumValue)
+{
+    gmx::Options           options(NULL, NULL);
+    std::string            value;
+    const char * const     allowed[] = { "none", "test", "value", NULL };
+    int                    index = -1;
+    using gmx::StringOption;
+    options.addOption(StringOption("p").store(&value)
+                          .enumValue(allowed)
+                          .storeEnumIndex(&index));
+
+    gmx::EmptyErrorReporter errors;
+    gmx::OptionsAssigner assigner(&options, &errors);
+    ASSERT_EQ(0, assigner.startOption("p"));
+    ASSERT_EQ(0, assigner.appendValue("te"));
+    ASSERT_EQ(0, assigner.finish());
+    ASSERT_EQ(0, options.finish(&errors));
+
+    EXPECT_EQ("test", value);
+    EXPECT_EQ(1, index);
+}
+
+TEST(OptionsAssignerStringTest, HandlesEnumWithNoValue)
+{
+    gmx::Options           options(NULL, NULL);
+    std::string            value;
+    const char * const     allowed[] = { "none", "test", "value", NULL };
+    int                    index = -3;
+    using gmx::StringOption;
+    options.addOption(StringOption("p").store(&value)
+                          .enumValue(allowed)
+                          .storeEnumIndex(&index));
+    EXPECT_TRUE(value.empty());
+    EXPECT_EQ(-1, index);
+
+    gmx::EmptyErrorReporter errors;
+    ASSERT_EQ(0, options.finish(&errors));
+
+    EXPECT_TRUE(value.empty());
+    EXPECT_EQ(-1, index);
+}
+
+TEST(OptionsAssignerStringTest, HandlesEnumDefaultValue)
+{
+    gmx::Options           options(NULL, NULL);
+    std::string            value;
+    const char * const     allowed[] = { "none", "test", "value", NULL };
+    int                    index = -1;
+    using gmx::StringOption;
+    options.addOption(StringOption("p").store(&value)
+                          .enumValue(allowed)
+                          .defaultValue("test")
+                          .storeEnumIndex(&index));
+    EXPECT_EQ("test", value);
+    EXPECT_EQ(1, index);
+
+    gmx::EmptyErrorReporter errors;
+    gmx::OptionsAssigner assigner(&options, &errors);
+    ASSERT_EQ(0, assigner.finish());
+    ASSERT_EQ(0, options.finish(&errors));
+
+    EXPECT_EQ("test", value);
+    EXPECT_EQ(1, index);
+}
+
+TEST(OptionsAssignerStringTest, HandlesEnumDefaultIndex)
+{
+    gmx::Options           options(NULL, NULL);
+    std::string            value;
+    const char * const     allowed[] = { "none", "test", "value", NULL };
+    int                    index = -1;
+    using gmx::StringOption;
+    options.addOption(StringOption("p").store(&value)
+                          .enumValue(allowed)
+                          .defaultEnumIndex(1)
+                          .storeEnumIndex(&index));
+    EXPECT_EQ("test", value);
+    EXPECT_EQ(1, index);
+
+    gmx::EmptyErrorReporter errors;
+    gmx::OptionsAssigner assigner(&options, &errors);
+    ASSERT_EQ(0, assigner.finish());
+    ASSERT_EQ(0, options.finish(&errors));
+
+    EXPECT_EQ("test", value);
+    EXPECT_EQ(1, index);
+}
+
+} // namespace
diff --git a/src/gromacs/options/tests/test_gmock_main.cpp b/src/gromacs/options/tests/test_gmock_main.cpp
new file mode 100644 (file)
index 0000000..72fa89f
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * main() for unit tests that use Google C++ Mocking Framework.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ */
+#include <gmock/gmock.h>
+
+#include "gromacs/fatalerror/fatalerror.h"
+
+/*! \brief
+ * Initializes unit testing with Google C++ Mocking Framework.
+ */
+int main(int argc, char *argv[])
+{
+    ::testing::InitGoogleMock(&argc, argv);
+    ::gmx::setFatalErrorHandler(NULL);
+    return RUN_ALL_TESTS();
+}
diff --git a/src/gromacs/options/tests/test_main.cpp b/src/gromacs/options/tests/test_main.cpp
new file mode 100644 (file)
index 0000000..406a8ff
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * main() for unit tests that use Google C++ Testing Framework.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ */
+#include <gtest/gtest.h>
+
+#include "gromacs/fatalerror/fatalerror.h"
+
+/*! \brief
+ * Initializes unit testing with Google C++ Testing Framework.
+ */
+int main(int argc, char *argv[])
+{
+    ::testing::InitGoogleTest(&argc, argv);
+    ::gmx::setFatalErrorHandler(NULL);
+    return RUN_ALL_TESTS();
+}
diff --git a/src/gromacs/selection.h b/src/gromacs/selection.h
new file mode 100644 (file)
index 0000000..dcec555
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \defgroup module_selection Parsing and Evaluation of Analysis Selections
+ * \ingroup group_analysismodules
+ * \brief
+ * Provides functionality for initializing and evaluating selections.
+ *
+ * \internal
+ * Implementation details of different parts of the module are discussed on
+ * separate pages:
+ *   - \ref page_module_selection_custom
+ *   - \ref page_module_selection_parser
+ *   - \ref page_module_selection_compiler
+ *   - \ref page_module_selection_insolidangle
+ */
+/*! \ingroup group_analysismodules
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ */
+/*! \file
+ * \brief
+ * Public API convenience header for selection handling.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \inpublicapi
+ * \ingroup module_selection
+ */
+#ifndef GMX_SELECTION_H
+#define GMX_SELECTION_H
+
+#include "selection/selection.h"
+#include "selection/selectionoption.h"
+
+#endif
diff --git a/src/gromacs/selection/CMakeLists.txt b/src/gromacs/selection/CMakeLists.txt
new file mode 100644 (file)
index 0000000..b7df5bc
--- /dev/null
@@ -0,0 +1,22 @@
+file(GLOB SELECTION_SOURCES *.cpp)
+set(LIBGROMACS_SOURCES ${LIBGROMACS_SOURCES} ${SELECTION_SOURCES} PARENT_SCOPE)
+
+set(SELECTION_PUBLIC_HEADERS
+    centerofmass.h
+    nbsearch.h
+    poscalc.h
+    indexutil.h
+    position.h
+    selection.h
+    selectionenums.h
+    selectionoption.h
+    selparam.h
+    selmethod.h
+    selvalue.h)
+install(FILES ${SELECTION_PUBLIC_HEADERS}
+        DESTINATION ${INCL_INSTALL_DIR}/gromacs/selection
+        COMPONENT development)
+
+if (BUILD_TESTING)
+    add_subdirectory(tests)
+endif (BUILD_TESTING)
diff --git a/src/gromacs/selection/centerofmass.cpp b/src/gromacs/selection/centerofmass.cpp
new file mode 100644 (file)
index 0000000..9a21ab9
--- /dev/null
@@ -0,0 +1,581 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * Implements functions in centerofmass.h.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_selection
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <typedefs.h>
+#include <pbc.h>
+#include <vec.h>
+
+#include "gromacs/selection/centerofmass.h"
+
+/*!
+ * \param[in]  top    Topology structure (unused, can be NULL).
+ * \param[in]  x      Position vectors of all atoms.
+ * \param[in]  nrefat Number of atoms in the index.
+ * \param[in]  index  Indices of atoms.
+ * \param[out] xout   COG position for the indexed atoms.
+ * \returns    0 on success.
+ */
+int
+gmx_calc_cog(t_topology *top, rvec x[], int nrefat, atom_id index[], rvec xout)
+{
+    int                 m, j, ai;
+
+    clear_rvec(xout);
+    for (m = 0; m < nrefat; ++m)
+    {
+        ai = index[m];
+        rvec_inc(xout, x[ai]);
+    }
+    svmul(1.0/nrefat, xout, xout);
+    return 0;
+}
+
+/*!
+ * \param[in]  top    Topology structure with masses.
+ * \param[in]  x      Position vectors of all atoms.
+ * \param[in]  nrefat Number of atoms in the index.
+ * \param[in]  index  Indices of atoms.
+ * \param[out] xout   COM position for the indexed atoms.
+ * \returns    0 on success, EINVAL if \p top is NULL.
+ *
+ * Works exactly as gmx_calc_cog() with the exception that a center of
+ * mass are calculated, and hence a topology with masses is required.
+ */
+int
+gmx_calc_com(t_topology *top, rvec x[], int nrefat, atom_id index[], rvec xout)
+{
+    int                 m, j, ai;
+    real                mass, mtot;
+
+    if (!top)
+    {
+        gmx_incons("no masses available while mass weighting was requested");
+        return EINVAL;
+    }
+    clear_rvec(xout);
+    mtot = 0;
+    for (m = 0; m < nrefat; ++m)
+    {
+        ai = index[m];
+        mass = top->atoms.atom[ai].m;
+        for (j = 0; j < DIM; ++j)
+        {
+            xout[j] += mass * x[ai][j];
+        }
+        mtot += mass;
+    }
+    svmul(1.0/mtot, xout, xout);
+    return 0;
+}
+
+/*!
+ * \param[in]  top    Topology structure with masses.
+ * \param[in]  f      Forces on all atoms.
+ * \param[in]  nrefat Number of atoms in the index.
+ * \param[in]  index  Indices of atoms.
+ * \param[out] fout   Force on the COG position for the indexed atoms.
+ * \returns    0 on success, EINVAL if \p top is NULL.
+ *
+ * No special function is provided for calculating the force on the center of
+ * mass, because this can be achieved with gmx_calc_cog().
+ */
+int
+gmx_calc_cog_f(t_topology *top, rvec f[], int nrefat, atom_id index[], rvec fout)
+{
+    int                 m, j, ai;
+    real                mass, mtot;
+
+    if (!top)
+    {
+        gmx_incons("no masses available while mass weighting was needed");
+        return EINVAL;
+    }
+    clear_rvec(fout);
+    mtot = 0;
+    for (m = 0; m < nrefat; ++m)
+    {
+        ai = index[m];
+        mass = top->atoms.atom[ai].m;
+        for (j = 0; j < DIM; ++j)
+        {
+            fout[j] += f[ai][j] / mass;
+        }
+        mtot += mass;
+    }
+    svmul(mtot, fout, fout);
+    return 0;
+}
+
+/*!
+ * \param[in]  top   Topology structure with masses
+ *   (can be NULL if \p bMASS==FALSE).
+ * \param[in]  x     Position vectors of all atoms.
+ * \param[in]  nrefat Number of atoms in the index.
+ * \param[in]  index Indices of atoms.
+ * \param[in]  bMass If TRUE, mass weighting is used.
+ * \param[out] xout  COM/COG position for the indexed atoms.
+ * \returns    0 on success, EINVAL if \p top is NULL and \p bMass is TRUE.
+ *
+ * Calls either gmx_calc_com() or gmx_calc_cog() depending on the value of
+ * \p bMass.
+ * Other parameters are passed unmodified to these functions.
+ */
+int
+gmx_calc_comg(t_topology *top, rvec x[], int nrefat, atom_id index[],
+              gmx_bool bMass, rvec xout)
+{
+    if (bMass)
+    {
+        return gmx_calc_com(top, x, nrefat, index, xout);
+    }
+    else
+    {
+        return gmx_calc_cog(top, x, nrefat, index, xout);
+    }
+}
+
+/*!
+ * \param[in]  top   Topology structure with masses
+ *   (can be NULL if \p bMASS==TRUE).
+ * \param[in]  f     Forces on all atoms.
+ * \param[in]  nrefat Number of atoms in the index.
+ * \param[in]  index Indices of atoms.
+ * \param[in]  bMass If TRUE, force on COM is calculated.
+ * \param[out] fout  Force on the COM/COG position for the indexed atoms.
+ * \returns    0 on success, EINVAL if \p top is NULL and \p bMass is FALSE.
+ *
+ * Calls either gmx_calc_cog() or gmx_calc_cog_f() depending on the value of
+ * \p bMass.
+ * Other parameters are passed unmodified to these functions.
+ */
+int
+gmx_calc_comg_f(t_topology *top, rvec f[], int nrefat, atom_id index[],
+                gmx_bool bMass, rvec fout)
+{
+    if (bMass)
+    {
+        return gmx_calc_cog(top, f, nrefat, index, fout);
+    }
+    else
+    {
+        return gmx_calc_cog_f(top, f, nrefat, index, fout);
+    }
+}
+
+
+/*!
+ * \param[in]  top    Topology structure (unused, can be NULL).
+ * \param[in]  x      Position vectors of all atoms.
+ * \param[in]  pbc    Periodic boundary conditions structure.
+ * \param[in]  nrefat Number of atoms in the index.
+ * \param[in]  index  Indices of atoms.
+ * \param[out] xout   COG position for the indexed atoms.
+ * \returns    0 on success.
+ *
+ * Works exactly as gmx_calc_com_pbc(), but calculates the center of geometry.
+ */
+int
+gmx_calc_cog_pbc(t_topology *top, rvec x[], t_pbc *pbc,
+                 int nrefat, atom_id index[], rvec xout)
+{
+    const real          tol = 1e-4;
+    gmx_bool                bChanged;
+    int                 m, j, ai, iter;
+    rvec                dx, xtest;
+
+    /* First simple calculation */
+    gmx_calc_cog(top, x, nrefat, index, xout);
+    /* Now check if any atom is more than half the box from the COM */
+    if (pbc)
+    {
+        iter = 0;
+        do
+        {
+            bChanged = FALSE;
+            for (m = 0; m < nrefat; ++m)
+            {
+                ai = index[m];
+                pbc_dx(pbc, x[ai], xout, dx);
+                rvec_add(xout, dx, xtest);
+                for (j = 0; j < DIM; ++j)
+                {
+                    if (fabs(xtest[j] - x[ai][j]) > tol)
+                    {
+                        /* Here we have used the wrong image for contributing to the COM */
+                        xout[j] += (xtest[j] - x[ai][j]) / nrefat;
+                        x[ai][j] = xtest[j];
+                        bChanged = TRUE;
+                    }
+                }
+            }
+            iter++;
+        }
+        while (bChanged);
+    }
+    return 0;
+}
+
+/*!
+ * \param[in]  top    Topology structure with masses.
+ * \param[in]  x      Position vectors of all atoms.
+ * \param[in]  pbc    Periodic boundary conditions structure.
+ * \param[in]  nrefat Number of atoms in the index.
+ * \param[in]  index  Indices of atoms.
+ * \param[out] xout   COM position for the indexed atoms.
+ * \returns    0 on success, EINVAL if \p top is NULL.
+ *
+ * Works as gmx_calc_com(), but takes into account periodic boundary
+ * conditions: If any atom is more than half the box from the COM,
+ * it is wrapped around and a new COM is calculated. This is repeated
+ * until no atoms violate the condition.
+ *
+ * Modified from src/tools/gmx_sorient.c in Gromacs distribution.
+ */
+int
+gmx_calc_com_pbc(t_topology *top, rvec x[], t_pbc *pbc,
+                 int nrefat, atom_id index[], rvec xout)
+{
+    const real          tol = 1e-4;
+    gmx_bool                bChanged;
+    int                 m, j, ai, iter;
+    real                mass, mtot;
+    rvec                dx, xtest;
+
+    if (!top)
+    {
+        gmx_incons("no masses available while mass weighting was requested");
+        return EINVAL;
+    }
+    /* First simple calculation */
+    clear_rvec(xout);
+    mtot = 0;
+    for (m = 0; m < nrefat; ++m)
+    {
+        ai = index[m];
+        mass = top->atoms.atom[ai].m;
+        for (j = 0; j < DIM; ++j)
+        {
+            xout[j] += mass * x[ai][j];
+        }
+        mtot += mass;
+    }
+    svmul(1.0/mtot, xout, xout);
+    /* Now check if any atom is more than half the box from the COM */
+    if (pbc)
+    {
+        iter = 0;
+        do
+        {
+            bChanged = FALSE;
+            for (m = 0; m < nrefat; ++m)
+            {
+                ai = index[m];
+                mass = top->atoms.atom[ai].m / mtot;
+                pbc_dx(pbc, x[ai], xout, dx);
+                rvec_add(xout, dx, xtest);
+                for (j = 0; j < DIM; ++j)
+                {
+                    if (fabs(xtest[j] - x[ai][j]) > tol)
+                    {
+                        /* Here we have used the wrong image for contributing to the COM */
+                        xout[j] += mass * (xtest[j] - x[ai][j]);
+                        x[ai][j] = xtest[j];
+                        bChanged = TRUE;
+                    }
+                }
+            }
+            iter++;
+        }
+        while (bChanged);
+    }
+    return 0;
+}
+
+/*!
+ * \param[in]  top   Topology structure with masses
+ *   (can be NULL if \p bMASS==FALSE).
+ * \param[in]  x     Position vectors of all atoms.
+ * \param[in]  pbc    Periodic boundary conditions structure.
+ * \param[in]  nrefat Number of atoms in the index.
+ * \param[in]  index Indices of atoms.
+ * \param[in]  bMass If TRUE, mass weighting is used.
+ * \param[out] xout  COM/COG position for the indexed atoms.
+ * \returns    0 on success, EINVAL if \p top is NULL and \p bMass is TRUE.
+ *
+ * Calls either gmx_calc_com() or gmx_calc_cog() depending on the value of
+ * \p bMass.
+ * Other parameters are passed unmodified to these functions.
+ */
+int
+gmx_calc_comg_pbc(t_topology *top, rvec x[], t_pbc *pbc,
+                  int nrefat, atom_id index[], gmx_bool bMass, rvec xout)
+{
+    if (bMass)
+    {
+        return gmx_calc_com_pbc(top, x, pbc, nrefat, index, xout);
+    }
+    else
+    {
+        return gmx_calc_cog_pbc(top, x, pbc, nrefat, index, xout);
+    }
+}
+
+
+/*!
+ * \param[in]  top   Topology structure (unused, can be NULL).
+ * \param[in]  x     Position vectors of all atoms.
+ * \param[in]  block t_block structure that divides \p index into blocks.
+ * \param[in]  index Indices of atoms.
+ * \param[out] xout  \p block->nr COG positions.
+ * \returns    0 on success.
+ */
+int
+gmx_calc_cog_block(t_topology *top, rvec x[], t_block *block, atom_id index[],
+                   rvec xout[])
+{
+    int                 b, i, ai;
+    rvec                xb;
+
+    for (b = 0; b < block->nr; ++b)
+    {
+        clear_rvec(xb);
+        for (i = block->index[b]; i < block->index[b+1]; ++i)
+        {
+            ai = index[i];
+            rvec_inc(xb, x[ai]);
+        }
+        svmul(1.0/(block->index[b+1] - block->index[b]), xb, xout[b]);
+    }
+    return 0;
+}
+
+/*!
+ * \param[in]  top   Topology structure with masses.
+ * \param[in]  x     Position vectors of all atoms.
+ * \param[in]  block t_block structure that divides \p index into blocks.
+ * \param[in]  index Indices of atoms.
+ * \param[out] xout  \p block->nr COM positions.
+ * \returns    0 on success, EINVAL if \p top is NULL.
+ *
+ * Works exactly as gmx_calc_cog_block() with the exception that centers of
+ * mass are calculated, and hence a topology with masses is required.
+ */
+int
+gmx_calc_com_block(t_topology *top, rvec x[], t_block *block, atom_id index[],
+                   rvec xout[])
+{
+    int                 b, i, ai, d;
+    rvec                xb;
+    real                mass, mtot;
+
+    if (!top)
+    {
+        gmx_incons("no masses available while mass weighting was requested");
+        return EINVAL;
+    }
+    for (b = 0; b < block->nr; ++b)
+    {
+        clear_rvec(xb);
+        mtot = 0;
+        for (i = block->index[b]; i < block->index[b+1]; ++i)
+        {
+            ai = index[i];
+            mass = top->atoms.atom[ai].m;
+            for (d = 0; d < DIM; ++d)
+            {
+                xb[d] += mass * x[ai][d];
+            }
+            mtot += mass;
+        }
+        svmul(1.0/mtot, xb, xout[b]);
+    }
+    return 0;
+}
+
+/*!
+ * \param[in]  top   Topology structure with masses.
+ * \param[in]  f     Forces on all atoms.
+ * \param[in]  block t_block structure that divides \p index into blocks.
+ * \param[in]  index Indices of atoms.
+ * \param[out] fout  \p block->nr Forces on COG positions.
+ * \returns    0 on success, EINVAL if \p top is NULL.
+ */
+int
+gmx_calc_cog_f_block(t_topology *top, rvec f[], t_block *block, atom_id index[],
+                     rvec fout[])
+{
+    int                 b, i, ai, d;
+    rvec                fb;
+    real                mass, mtot;
+
+    if (!top)
+    {
+        gmx_incons("no masses available while mass weighting was needed");
+        return EINVAL;
+    }
+    for (b = 0; b < block->nr; ++b)
+    {
+        clear_rvec(fb);
+        mtot = 0;
+        for (i = block->index[b]; i < block->index[b+1]; ++i)
+        {
+            ai = index[i];
+            mass = top->atoms.atom[ai].m;
+            for (d = 0; d < DIM; ++d)
+            {
+                fb[d] += f[ai][d] / mass;
+            }
+            mtot += mass;
+        }
+        svmul(mtot, fb, fout[b]);
+    }
+    return 0;
+}
+
+/*!
+ * \param[in]  top   Topology structure with masses
+ *   (can be NULL if \p bMASS==FALSE).
+ * \param[in]  x     Position vectors of all atoms.
+ * \param[in]  block t_block structure that divides \p index into blocks.
+ * \param[in]  index Indices of atoms.
+ * \param[in]  bMass If TRUE, mass weighting is used.
+ * \param[out] xout  \p block->nr COM/COG positions.
+ * \returns    0 on success, EINVAL if \p top is NULL and \p bMass is TRUE.
+ *
+ * Calls either gmx_calc_com_block() or gmx_calc_cog_block() depending on the
+ * value of \p bMass.
+ * Other parameters are passed unmodified to these functions.
+ */
+int
+gmx_calc_comg_block(t_topology *top, rvec x[], t_block *block, atom_id index[],
+                    gmx_bool bMass, rvec xout[])
+{
+    if (bMass)
+    {
+        return gmx_calc_com_block(top, x, block, index, xout);
+    }
+    else
+    {
+        return gmx_calc_cog_block(top, x, block, index, xout);
+    }
+}
+
+/*!
+ * \param[in]  top   Topology structure with masses
+ *   (can be NULL if \p bMASS==FALSE).
+ * \param[in]  f     Forces on all atoms.
+ * \param[in]  block t_block structure that divides \p index into blocks.
+ * \param[in]  index Indices of atoms.
+ * \param[in]  bMass If TRUE, force on COM is calculated.
+ * \param[out] fout  \p block->nr forces on the COM/COG positions.
+ * \returns    0 on success, EINVAL if \p top is NULL and \p bMass is TRUE.
+ *
+ * Calls either gmx_calc_com_block() or gmx_calc_cog_block() depending on the
+ * value of \p bMass.
+ * Other parameters are passed unmodified to these functions.
+ */
+int
+gmx_calc_comg_f_block(t_topology *top, rvec f[], t_block *block, atom_id index[],
+                      gmx_bool bMass, rvec fout[])
+{
+    if (bMass)
+    {
+        return gmx_calc_cog_block(top, f, block, index, fout);
+    }
+    else
+    {
+        return gmx_calc_cog_f_block(top, f, block, index, fout);
+    }
+}
+
+/*!
+ * \param[in]  top   Topology structure with masses
+ *   (can be NULL if \p bMASS==FALSE).
+ * \param[in]  x     Position vectors of all atoms.
+ * \param[in]  block Blocks for calculation.
+ * \param[in]  bMass If TRUE, mass weighting is used.
+ * \param[out] xout  \p block->nr COM/COG positions.
+ * \returns    0 on success, EINVAL if \p top is NULL and \p bMass is TRUE.
+ *
+ * Calls gmx_calc_comg_block(), converting the \p t_blocka structure into
+ * a \p t_block and an index. Other parameters are passed unmodified.
+ *
+ * \attention
+ * This function assumes that a pointer to \c t_blocka can be safely typecast
+ * into \c t_block such that the index fields can still be referenced.
+ * With the present Gromacs defitions of these types, this is the case,
+ * but if the layout of these structures is changed, this may lead to strange
+ * crashes.
+ */
+int
+gmx_calc_comg_blocka(t_topology *top, rvec x[], t_blocka *block,
+                     gmx_bool bMass, rvec xout[])
+{
+    /* TODO: It would probably be better to do this without the type cast */
+    return gmx_calc_comg_block(top, x, (t_block *)block, block->a, bMass, xout);
+}
+
+/*!
+ * \param[in]  top   Topology structure with masses
+ *   (can be NULL if \p bMASS==TRUE).
+ * \param[in]  f     Forces on all atoms.
+ * \param[in]  block Blocks for calculation.
+ * \param[in]  bMass If TRUE, force on COM is calculated.
+ * \param[out] fout  \p block->nr forces on the COM/COG positions.
+ * \returns    0 on success, EINVAL if \p top is NULL and \p bMass is FALSE.
+ *
+ * Calls gmx_calc_comg_f_block(), converting the \p t_blocka structure into
+ * a \p t_block and an index. Other parameters are passed unmodified.
+ *
+ * \attention
+ * This function assumes that a pointer to \c t_blocka can be safely typecast
+ * into \c t_block such that the index fields can still be referenced.
+ * With the present Gromacs defitions of these types, this is the case,
+ * but if the layout of these structures is changed, this may lead to strange
+ * crashes.
+ */
+int
+gmx_calc_comg_f_blocka(t_topology *top, rvec f[], t_blocka *block,
+                       gmx_bool bMass, rvec fout[])
+{
+    /* TODO: It would probably be better to do this without the type cast */
+    return gmx_calc_comg_f_block(top, f, (t_block *)block, block->a, bMass, fout);
+}
diff --git a/src/gromacs/selection/centerofmass.h b/src/gromacs/selection/centerofmass.h
new file mode 100644 (file)
index 0000000..52226e9
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \file
+ * \brief API for calculation of centers of mass/geometry.
+ *
+ * This header defines a few functions that can be used to calculate
+ * centers of mass/geometry for a group of atoms.
+ * These routines can be used independently of the other parts of the
+ * library, but they are also used internally by the selection engine.
+ * In most cases, it should not be necessary to call these functions
+ * directly.
+ * Instead, one should write an analysis tool such that it gets all
+ * positions through selections.
+ *
+ * The functions in the header can be divided into a few groups based on the
+ * parameters they take. The simplest group of functions calculates the center
+ * of a single group of atoms:
+ *  - gmx_calc_cog(): Calculates the center of geometry (COG) of a given
+ *    group of atoms.
+ *  - gmx_calc_com(): Calculates the center of mass (COM) of a given group
+ *    of atoms.
+ *  - gmx_calc_comg(): Calculates either the COM or COG, based on a
+ *    gmx_boolean flag.
+ *
+ * A second set of routines is provided for calculating the centers for groups
+ * that wrap over periodic boundaries (gmx_calc_cog_pbc(), gmx_calc_com_pbc(),
+ * gmx_calc_comg_pbc()). These functions are slower, because they need to
+ * adjust the center iteratively.
+ *
+ * It is also possible to calculate centers for several groups of atoms in
+ * one call. The functions gmx_calc_cog_block(), gmx_calc_com_block() and
+ * gmx_calc_comg_block() take an index group and a partitioning of that index
+ * group (as a \c t_block structure), and calculate the centers for
+ * each group defined by the \c t_block structure separately.
+ *
+ * Finally, there is a function gmx_calc_comg_blocka() that takes both the
+ * index group and the partitioning as a single \c t_blocka structure.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_selection
+ */
+#ifndef GMX_SELECTION_CENTEROFMASS_H
+#define GMX_SELECTION_CENTEROFMASS_H
+
+#include "../legacyheaders/typedefs.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/** Calculate a single center of geometry. */
+int
+gmx_calc_cog(t_topology *top, rvec x[], int nrefat, atom_id index[], rvec xout);
+/** Calculate a single center of mass. */
+int
+gmx_calc_com(t_topology *top, rvec x[], int nrefat, atom_id index[], rvec xout);
+/** Calculate force on a single center of geometry. */
+int
+gmx_calc_cog_f(t_topology *top, rvec f[], int nrefat, atom_id index[], rvec fout);
+/** Calculate a single center of mass/geometry. */
+int
+gmx_calc_comg(t_topology *top, rvec x[], int nrefat, atom_id index[],
+              gmx_bool bMass, rvec xout);
+/** Calculate force on a single center of mass/geometry. */
+int
+gmx_calc_comg_f(t_topology *top, rvec f[], int nrefat, atom_id index[],
+                gmx_bool bMass, rvec fout);
+
+/** Calculate a single center of geometry iteratively, taking PBC into account. */
+int
+gmx_calc_cog_pbc(t_topology *top, rvec x[], t_pbc *pbc,
+                 int nrefat, atom_id index[], rvec xout);
+/** Calculate a single center of mass iteratively, taking PBC into account. */
+int
+gmx_calc_com_pbc(t_topology *top, rvec x[], t_pbc *pbc,
+                 int nrefat, atom_id index[], rvec xout);
+/** Calculate a single center of mass/geometry iteratively with PBC. */
+int
+gmx_calc_comg_pbc(t_topology *top, rvec x[], t_pbc *pbc,
+                  int nrefat, atom_id index[], gmx_bool bMass, rvec xout);
+
+/** Calculate centers of geometry for a blocked index. */
+int
+gmx_calc_cog_block(t_topology *top, rvec x[], t_block *block,
+                   atom_id index[], rvec xout[]);
+/** Calculate centers of mass for a blocked index. */
+int
+gmx_calc_com_block(t_topology *top, rvec x[], t_block *block,
+                   atom_id index[], rvec xout[]);
+/** Calculate forces on centers of geometry for a blocked index. */
+int
+gmx_calc_cog_f_block(t_topology *top, rvec f[], t_block *block,
+                     atom_id index[], rvec fout[]);
+/** Calculate centers of mass/geometry for a blocked index. */
+int
+gmx_calc_comg_block(t_topology *top, rvec x[], t_block *block,
+                    atom_id index[], gmx_bool bMass, rvec xout[]);
+/** Calculate forces on centers of mass/geometry for a blocked index. */
+int
+gmx_calc_comg_f_block(t_topology *top, rvec f[], t_block *block,
+                      atom_id index[], gmx_bool bMass, rvec fout[]);
+/** Calculate centers of mass/geometry for a set of blocks; */
+int
+gmx_calc_comg_blocka(t_topology *top, rvec x[], t_blocka *block,
+                     gmx_bool bMass, rvec xout[]);
+/** Calculate forces on centers of mass/geometry for a set of blocks; */
+int
+gmx_calc_comg_f_blocka(t_topology *top, rvec x[], t_blocka *block,
+                       gmx_bool bMass, rvec xout[]);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/gromacs/selection/compiler.cpp b/src/gromacs/selection/compiler.cpp
new file mode 100644 (file)
index 0000000..6c336ee
--- /dev/null
@@ -0,0 +1,2901 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief Selection compilation and optimization.
+ *
+ * \todo
+ * Better error handling and memory management in error situations.
+ * At least, the main compilation function leaves the selection collection in
+ * a bad state if an error occurs.
+ *
+ * \todo
+ * The memory usage could still be optimized.
+ * Use of memory pooling could still be extended, and a lot of redundant
+ * gmin/gmax data could be eliminated for complex arithmetic expressions.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_selection
+ */
+/*! \internal
+ * \page page_module_selection_compiler Selection compilation
+ *
+ * The compiler takes the selection element tree from the selection parser
+ * (see \ref page_module_selection_parser) as input.
+ * The selection parser is quite independent of selection evaluation details,
+ * and the compiler processes the tree to conform to what the evaluation
+ * functions expect.
+ * For better control and optimization possibilities, the compilation is
+ * done on all selections simultaneously.
+ * Hence, all the selections should be parsed before the compiler can be
+ * called.
+ *
+ * The compiler initializes all fields in \c t_selelem not initialized by
+ * the parser: \c t_selelem::v (some fields have already been initialized by
+ * the parser), \c t_selelem::evaluate, and \c t_selelem::u (again, some
+ * elements have been initialized in the parser).
+ * The \c t_selelem::cdata field is used during the compilation to store
+ * internal data, but the data is freed when the compiler returns.
+ *
+ * In addition to initializing the elements, the compiler reorganizes the tree
+ * to simplify and optimize evaluation. The compiler also evaluates the static
+ * parts of the selection: in the end of the compilation, static parts have
+ * been replaced by the result of the evaluation.
+ *
+ * The compiler is called by calling gmx_ana_selcollection_compile().
+ * This functions then does the compilation in several passes over the
+ * \c t_selelem tree.
+ *  -# Defaults are set for the position type and flags of position calculation
+ *     methods that were not explicitly specified in the user input.
+ *  -# Subexpressions are extracted: a separate root is created for each
+ *     subexpression, and placed before the expression is first used.
+ *     Currently, only variables and expressions used to evaluate parameter
+ *     values are extracted, but common subexpression could also be detected
+ *     here.
+ *  -# A second pass with simple reordering and initialization is done:
+ *    -# Boolean expressions are combined such that one element can evaluate,
+ *       e.g., "A and B and C". The subexpressions in gmx_boolean expression are
+ *       reordered such that static expressions come first without otherwise
+ *       altering the relative order of the expressions.
+ *    -# The \c t_selelem::evaluate field is set to the correct evaluation
+ *       function from evaluate.h.
+ *    -# The compiler data structure is allocated for each element, and
+ *       the fields are initialized, with the exception of the contents of
+ *       \c gmax and \c gmin fields.  In reality, several passes are made
+ *       to completely initialize the structure, because some flags are set
+ *       recursively based on which elements refer to an element, and these
+ *       flags need to be set to initialize other fields.
+ *    .
+ *  -# The evaluation function of all elements is replaced with the
+ *     analyze_static() function to be able to initialize the element before
+ *     the actual evaluation function is called.
+ *     The evaluation machinery is then called to initialize the whole tree,
+ *     while simultaneously evaluating the static expressions.
+ *     During the evaluation, track is kept of the smallest and largest
+ *     possible selections, and these are stored in the internal compiler
+ *     data structure for each element.
+ *     To be able to do this for all possible values of dynamical expressions,
+ *     special care needs to be taken with gmx_boolean expressions because they
+ *     are short-circuiting. This is done through the
+ *     \c SEL_CDATA_EVALMAX flag, which makes dynamic child expressions
+ *     of \c BOOL_OR expressions evaluate to empty groups, while subexpressions
+ *     of \c BOOL_AND are evaluated to largest possible groups.
+ *     Memory is also allocated to store the results of the evaluation.
+ *     For each element, analyze_static() calls the actual evaluation function
+ *     after the element has been properly initialized.
+ *  -# Another evaluation pass is done over subexpressions with more than
+ *     one reference to them. These cannot be completely processed during the
+ *     first pass, because it is not known whether later references require
+ *     additional evaluation of static expressions.
+ *  -# Unused subexpressions are removed. For efficiency reasons (and to avoid
+ *     some checks), this is actually done several times already earlier in
+ *     the compilation process.
+ *  -# Most of the processing is now done, and the next pass simply sets the
+ *     evaluation group of root elements to the largest selection as determined
+ *     in pass 4.  For root elements of subexpressions that should not be
+ *     evaluated before they are referred to, the evaluation group/function is
+ *     cleared.  At the same time, position calculation data is initialized for
+ *     for selection method elements that require it.  Compiler data is also
+ *     freed as it is no longer needed.
+ *  -# A final pass initializes the total masses and charges in the
+ *     \c gmx_ana_selection_t data structures.
+ *
+ * The actual evaluation of the selection is described in the documentation
+ * of the functions in evaluate.h.
+ *
+ * \todo
+ * Some combinations of method parameter flags are not yet properly treated by
+ * the compiler or the evaluation functions in evaluate.cpp. All the ones used by
+ * currently implemented methods should work, but new combinations might not.
+ *
+ *
+ * \section selcompiler_tree Element tree after compilation
+ *
+ * After the compilation, the selection element tree is suitable for
+ * gmx_ana_selcollection_evaluate().
+ * Enough memory has been allocated for \ref t_selelem::v
+ * (and \ref t_selelem::cgrp for \ref SEL_SUBEXPR elements) to allow the
+ * selection to be evaluated without allocating any memory.
+ *
+ *
+ * \subsection selcompiler_tree_root Root elements
+ *
+ * The top level of the tree consists of a chain of \ref SEL_ROOT elements.
+ * These are used for two purposes:
+ *  -# A selection that should be evaluated.
+ *     These elements appear in the same order as the selections in the input.
+ *     For these elements, \ref t_selelem::v has been set to the maximum
+ *     possible group that the selection can evaluate to (only for dynamic
+ *     selections), and \ref t_selelem::cgrp has been set to use a NULL group
+ *     for evaluation.
+ *  -# A subexpression that appears in one or more selections.
+ *     Each selection that gives a value for a method parameter is a
+ *     potential subexpression, as is any variable value.
+ *     Only subexpressions that require evaluation for each frame are left
+ *     after the selection is compiled.
+ *     Each subexpression appears in the chain before any references to it.
+ *     For these elements, \c t_selelem::cgrp has been set to the group
+ *     that should be used to evaluate the subexpression.
+ *     If \c t_selelem::cgrp is empty, the total evaluation group is not known
+ *     in advance or it is more efficient to evaluate the subexpression only
+ *     when it is referenced.  If this is the case, \c t_selelem::evaluate is
+ *     also NULL.
+ *
+ * The children of the \ref SEL_ROOT elements can be used to distinguish
+ * the two types of root elements from each other; the rules are the same
+ * as for the parsed tree (see \ref selparser_tree_root).
+ * Subexpressions are treated as if they had been provided through variables.
+ *
+ * Selection names are stored as after parsing (see \ref selparser_tree_root).
+ *
+ *
+ * \subsection selcompiler_tree_const Constant elements
+ *
+ * All (sub)selections that do not require particle positions have been
+ * replaced with \ref SEL_CONST elements.
+ * Constant elements from the parser are also retained if present in
+ * dynamic parts of the selections.
+ * Several constant elements with a NULL \c t_selelem::evaluate are left for
+ * debugging purposes; of these, only the ones for \ref BOOL_OR expressions are
+ * used during evaluation.
+ *
+ * The value is stored in \c t_selelem::v, and for group values with an
+ * evaluation function set, also in \c t_selelem::cgrp.
+ * For \ref GROUP_VALUE elements, unnecessary atoms (i.e., atoms that
+ * could never be selected) have been removed from the value.
+ *
+ * \ref SEL_CONST elements have no children.
+ *
+ *
+ * \subsection selcompiler_tree_method Method evaluation elements
+ *
+ * All selection methods that need to be evaluated dynamically are described
+ * by a \ref SEL_EXPRESSION element. The \c t_selelem::method and
+ * \c t_selelem::mdata fields have already been initialized by the parser,
+ * and the compiler only calls the initialization functions in the method
+ * data structure to do some additional initialization of these fields at
+ * appropriate points. If the \c t_selelem::pc data field has been created by
+ * the parser, the compiler initializes the data structure properly once the
+ * required positions are known. If the \c t_selelem::pc field is NULL after
+ * the parser, but the method provides only sel_updatefunc_pos(), an
+ * appropriate position calculation data structure is created.
+ * If \c t_selelem::pc is not NULL, \c t_selelem::pos is also initialized
+ * to hold the positions calculated.
+ *
+ * Children of these elements are of type \ref SEL_SUBEXPRREF, and describe
+ * parameter values that need to be evaluated for each frame. See the next
+ * section for more details.
+ * \ref SEL_CONST children can also appear, and stand for parameters that get
+ * their value from a static expression. These elements are present only for
+ * debugging purposes: they always have a NULL evaluation function.
+ *
+ *
+ * \subsection selcompiler_tree_subexpr Subexpression elements
+ *
+ * As described in \ref selcompiler_tree_root, subexpressions are created
+ * for each variable and each expression that gives a value to a selection
+ * method parameter. As the only child of the \ref SEL_ROOT element,
+ * these elements have a \ref SEL_SUBEXPR element. The \ref SEL_SUBEXPR
+ * element has a single child, which evaluates the actual expression.
+ * After compilation, only subexpressions that require particle positions
+ * for evaluation are left.
+ * For non-variable subexpression, automatic names have been generated to
+ * help in debugging.
+ *
+ * For \ref SEL_SUBEXPR elements, memory has been allocated for
+ * \c t_selelem::cgrp to store the group for which the expression has been
+ * evaluated during the current frame.  This is only done if full subexpression
+ * evaluation by _gmx_sel_evaluate_subexpr() is needed; the other evaluation
+ * functions do not require this memory.
+ *
+ * \ref SEL_SUBEXPRREF elements are used to describe references to
+ * subexpressions. They have always a single child, which is the
+ * \ref SEL_SUBEXPR element being referenced.
+ *
+ * If a subexpression is used only once, the evaluation has been optimized by
+ * setting the child of the \ref SEL_SUBEXPR element to evaluate the value of
+ * \ref SEL_SUBEXPRREF directly (in the case of memory pooling, this is managed
+ * by the evaluation functions).  In such cases, the evaluation routines for the
+ * \ref SEL_SUBEXPRREF and \ref SEL_SUBEXPR elements only propagate some status
+ * information, but do not unnecessarily copy the values.
+ *
+ *
+ * \subsection selcompiler_tree_gmx_bool Boolean elements
+ *
+ * \ref SEL_BOOLEAN elements have been merged such that one element
+ * may carry out evaluation of more than one operation of the same type.
+ * The static parts of the expressions have been evaluated, and are placed
+ * in the first child. These are followed by the dynamic expressions, in the
+ * order provided by the user.
+ *
+ *
+ * \subsection selcompiler_tree_arith Arithmetic elements
+ *
+ * Constant and static expressions in \ref SEL_ARITHMETIC elements have been
+ * calculated.
+ * Currently, no other processing is done.
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <math.h>
+#include <stdarg.h>
+
+#include <smalloc.h>
+#include <string2.h>
+#include <vec.h>
+
+#include "gromacs/selection/indexutil.h"
+#include "gromacs/selection/poscalc.h"
+#include "gromacs/selection/selection.h"
+#include "gromacs/selection/selmethod.h"
+
+#include "evaluate.h"
+#include "keywords.h"
+#include "mempool.h"
+#include "selectioncollection-impl.h"
+#include "selelem.h"
+
+static int min(int a, int b)
+{
+    return (a < b) ? a : b;
+}
+
+/*! \internal \brief
+ * Compiler flags.
+ */
+enum
+{
+    /*! \brief
+     * Whether a subexpression needs to evaluated for all atoms.
+     *
+     * This flag is set for \ref SEL_SUBEXPR elements that are used to
+     * evaluate non-atom-valued selection method parameters, as well as
+     * those that are used directly as values of selections.
+     */
+    SEL_CDATA_FULLEVAL    =  1,
+    /*! \brief
+     * Whether the whole subexpression should be treated as static.
+     *
+     * This flag is always FALSE if \ref SEL_DYNAMIC is set for the element,
+     * but it is also FALSE for static elements within common subexpressions.
+     */
+    SEL_CDATA_STATIC      =  2,
+    /** Whether the subexpression will always be evaluated in the same group. */
+    SEL_CDATA_STATICEVAL  =  4,
+    /** Whether the compiler evaluation routine should return the maximal selection. */
+    SEL_CDATA_EVALMAX     =  8,
+    /** Whether memory has been allocated for \p gmin and \p gmax. */
+    SEL_CDATA_MINMAXALLOC = 16,
+    /** Whether subexpressions use simple pass evaluation functions. */
+    SEL_CDATA_SIMPLESUBEXPR = 32,
+    /** Whether this expressions is a part of a common subexpression. */
+    SEL_CDATA_COMMONSUBEXPR = 64 
+};
+
+/*! \internal \brief
+ * Internal data structure used by the compiler.
+ */
+typedef struct t_compiler_data
+{
+    /** The real evaluation method. */
+    sel_evalfunc     evaluate;
+    /** Flags for specifying how to treat this element during compilation. */
+    int              flags;
+    /** Smallest selection that can be selected by the subexpression. */
+    gmx_ana_index_t *gmin;
+    /** Largest selection that can be selected by the subexpression. */
+    gmx_ana_index_t *gmax;
+} t_compiler_data;
+
+
+/********************************************************************
+ * COMPILER UTILITY FUNCTIONS
+ ********************************************************************/
+
+static void
+print_group_info(FILE *fp, const char *name, t_selelem *sel, gmx_ana_index_t *g)
+{
+    fprintf(fp, " %s=", name);
+    if (!g)
+    {
+        fprintf(fp, "(null)");
+    }
+    else if (sel->cdata->flags & SEL_CDATA_MINMAXALLOC)
+    {
+        fprintf(fp, "(%d atoms, %p)", g->isize, (void*)g);
+    }
+    else if (sel->v.type == GROUP_VALUE && g == sel->v.u.g)
+    {
+        fprintf(fp, "(static, %p)", (void*)g);
+    }
+    else
+    {
+        fprintf(fp, "%p", (void*)g);
+    }
+}
+
+/*!
+ * \param[in] fp      File handle to receive the output.
+ * \param[in] sel     Selection element to print.
+ * \param[in] level   Indentation level, starting from zero.
+ */
+void
+_gmx_selelem_print_compiler_info(FILE *fp, t_selelem *sel, int level)
+{
+    if (!sel->cdata)
+    {
+        return;
+    }
+    fprintf(fp, "%*c cdata: flg=", level*2+1, ' ');
+    if (sel->cdata->flags & SEL_CDATA_FULLEVAL)
+    {
+        fprintf(fp, "F");
+    }
+    if (!(sel->cdata->flags & SEL_CDATA_STATIC))
+    {
+        fprintf(fp, "D");
+    }
+    if (sel->cdata->flags & SEL_CDATA_STATICEVAL)
+    {
+        fprintf(fp, "S");
+    }
+    if (sel->cdata->flags & SEL_CDATA_EVALMAX)
+    {
+        fprintf(fp, "M");
+    }
+    if (sel->cdata->flags & SEL_CDATA_MINMAXALLOC)
+    {
+        fprintf(fp, "A");
+    }
+    if (sel->cdata->flags & SEL_CDATA_SIMPLESUBEXPR)
+    {
+        fprintf(fp, "Ss");
+    }
+    if (sel->cdata->flags & SEL_CDATA_COMMONSUBEXPR)
+    {
+        fprintf(fp, "Sc");
+    }
+    if (!sel->cdata->flags)
+    {
+        fprintf(fp, "0");
+    }
+    fprintf(fp, " eval=");
+    _gmx_sel_print_evalfunc_name(fp, sel->cdata->evaluate);
+    print_group_info(fp, "gmin", sel, sel->cdata->gmin);
+    print_group_info(fp, "gmax", sel, sel->cdata->gmax);
+    fprintf(fp, "\n");
+}
+
+/*!
+ * \param  sel Selection to free.
+ *
+ * This function only frees the data for the given selection, not its children.
+ * It is safe to call the function when compiler data has not been allocated
+ * or has already been freed; in such a case, nothing is done.
+ */
+void
+_gmx_selelem_free_compiler_data(t_selelem *sel)
+{
+    if (sel->cdata)
+    {
+        sel->evaluate = sel->cdata->evaluate;
+        if (sel->cdata->flags & SEL_CDATA_MINMAXALLOC)
+        {
+            sel->cdata->gmin->name = NULL;
+            sel->cdata->gmax->name = NULL;
+            gmx_ana_index_deinit(sel->cdata->gmin);
+            gmx_ana_index_deinit(sel->cdata->gmax);
+            sfree(sel->cdata->gmin);
+            sfree(sel->cdata->gmax);
+        }
+        sfree(sel->cdata);
+    }
+    sel->cdata = NULL;
+}
+
+/*! \brief
+ * Allocates memory for storing the evaluated value of a selection element.
+ *
+ * \param     sel   Selection element to initialize
+ * \param[in] isize Maximum evaluation group size.
+ * \param[in] bChildEval TRUE if children have already been processed.
+ * \returns   TRUE if the memory was allocated, FALSE if children need to
+ *   be processed first.
+ *
+ * If called more than once, memory is (re)allocated to ensure that the
+ * maximum of the \p isize values can be stored.
+ */
+static gmx_bool
+alloc_selection_data(t_selelem *sel, int isize, gmx_bool bChildEval)
+{
+    int        nalloc;
+
+    if (sel->mempool)
+    {
+        return TRUE;
+    }
+    /* Find out the number of elements to allocate */
+    if (sel->flags & SEL_SINGLEVAL)
+    {
+        nalloc = 1;
+    }
+    else if (sel->flags & SEL_ATOMVAL)
+    {
+        nalloc = isize;
+    }
+    else /* sel->flags should contain SEL_VARNUMVAL */
+    {
+        t_selelem *child;
+
+        if (!bChildEval)
+        {
+            return FALSE;
+        }
+        child = (sel->type == SEL_SUBEXPRREF ? sel->child : sel);
+        if (child->type == SEL_SUBEXPR)
+        {
+            child = child->child;
+        }
+        nalloc = (sel->v.type == POS_VALUE) ? child->v.u.p->nr : child->v.nr;
+    }
+    /* For positions, we actually want to allocate just a single structure
+     * for nalloc positions. */
+    if (sel->v.type == POS_VALUE)
+    {
+        isize  = nalloc;
+        nalloc = 1;
+    }
+    /* Allocate memory for sel->v.u if needed */
+    if (sel->flags & SEL_ALLOCVAL)
+    {
+        _gmx_selvalue_reserve(&sel->v, nalloc);
+    }
+    /* Reserve memory inside group and position structures if
+     * SEL_ALLOCDATA is set. */
+    if (sel->flags & SEL_ALLOCDATA)
+    {
+        if (sel->v.type == GROUP_VALUE)
+        {
+            gmx_ana_index_reserve(sel->v.u.g, isize);
+        }
+        else if (sel->v.type == POS_VALUE)
+        {
+            gmx_ana_pos_reserve(sel->v.u.p, isize, 0);
+        }
+    }
+    return TRUE;
+}
+
+/*! \brief
+ * Replace the evaluation function of each element in the subtree.
+ *
+ * \param     sel  Root of the selection subtree to process.
+ * \param[in] eval The new evaluation function.
+ */
+static void
+set_evaluation_function(t_selelem *sel, sel_evalfunc eval)
+{
+    sel->evaluate = eval;
+    if (sel->type != SEL_SUBEXPRREF)
+    {
+        t_selelem *child = sel->child;
+        while (child)
+        {
+            set_evaluation_function(child, eval);
+            child = child->next;
+        }
+    }
+}
+
+
+/********************************************************************
+ * POSITION KEYWORD DEFAULT INITIALIZATION
+ ********************************************************************/
+
+/*! \brief
+ * Initializes default values for position keyword evaluation.
+ *
+ * \param[in,out] root       Root of the element tree to initialize.
+ * \param[in]     spost      Default output position type.
+ * \param[in]     rpost      Default reference position type.
+ * \param[in]     sel        Selection that the element evaluates the positions
+ *      for, or NULL if the element is an internal element.
+ */
+static void
+init_pos_keyword_defaults(t_selelem *root, const char *spost,
+                          const char *rpost, const gmx::Selection *sel)
+{
+    /* Selections use largest static group by default, while
+     * reference positions use the whole residue/molecule. */
+    if (root->type == SEL_EXPRESSION)
+    {
+        bool bSelection = (sel != NULL);
+        int flags = bSelection ? POS_COMPLMAX : POS_COMPLWHOLE;
+        if (bSelection)
+        {
+            if (sel->hasFlag(gmx::efDynamicMask))
+            {
+                flags |= POS_MASKONLY;
+            }
+            if (sel->hasFlag(gmx::efEvaluateVelocities))
+            {
+                flags |= POS_VELOCITIES;
+            }
+            if (sel->hasFlag(gmx::efEvaluateForces))
+            {
+                flags |= POS_FORCES;
+            }
+        }
+        _gmx_selelem_set_kwpos_type(root, bSelection ? spost : rpost);
+        _gmx_selelem_set_kwpos_flags(root, flags);
+    }
+    /* Change the defaults once we are no longer processing modifiers */
+    if (root->type != SEL_ROOT && root->type != SEL_MODIFIER
+        && root->type != SEL_SUBEXPRREF && root->type != SEL_SUBEXPR)
+    {
+        sel = NULL;
+    }
+    /* Recurse into children */
+    t_selelem *child = root->child;
+    while (child)
+    {
+        init_pos_keyword_defaults(child, spost, rpost, sel);
+        child = child->next;
+    }
+}
+
+
+/********************************************************************
+ * SUBEXPRESSION PROCESSING
+ ********************************************************************/
+
+/*! \brief
+ * Reverses the chain of selection elements starting at \p root.
+ *
+ * \param   root First selection in the whole selection chain.
+ * \returns The new first element for the chain.
+ */
+static t_selelem *
+reverse_selelem_chain(t_selelem *root)
+{
+    t_selelem *item;
+    t_selelem *prev;
+    t_selelem *next;
+
+    prev = NULL;
+    item = root;
+    while (item)
+    {
+        next = item->next;
+        item->next = prev;
+        prev = item;
+        item = next;
+    }
+    return prev;
+}
+
+/*! \brief
+ * Removes subexpressions that don't have any references.
+ *
+ * \param     root First selection in the whole selection chain.
+ * \returns   The new first element for the chain.
+ *
+ * The elements are processed in reverse order to correctly detect
+ * subexpressions only referred to by other subexpressions.
+ */
+static t_selelem *
+remove_unused_subexpressions(t_selelem *root)
+{
+    t_selelem *item;
+    t_selelem *prev;
+    t_selelem *next;
+
+    if (root == NULL)
+    {
+        return NULL;
+    }
+    root = reverse_selelem_chain(root);
+    while (root->child->type == SEL_SUBEXPR && root->child->refcount == 1)
+    {
+        next = root->next;
+        _gmx_selelem_free(root);
+        root = next;
+    }
+    prev = root;
+    item = root->next;
+    while (item)
+    {
+        next = item->next;
+        if (item->child->type == SEL_SUBEXPR && item->child->refcount == 1)
+        {
+            prev->next = next;
+            _gmx_selelem_free(item);
+        }
+        else
+        {
+            prev = item;
+        }
+        item = next;
+    }
+    return reverse_selelem_chain(root);
+}
+
+/*! \brief
+ * Creates a name with a running number for a subexpression.
+ *
+ * \param[in,out] sel The subexpression to be named.
+ * \param[in]     i   Running number for the subexpression.
+ *
+ * The name of the selection becomes "SubExpr N", where N is \p i;
+ * Memory is allocated for the name and the name is stored both in
+ * \c t_selelem::name and \c t_selelem::u::cgrp::name; the latter
+ * is freed by _gmx_selelem_free().
+ */
+static void
+create_subexpression_name(t_selelem *sel, int i)
+{
+    int   len, ret;
+    char *name;
+
+    len = 8 + (int)log10(abs(i)) + 3;
+    snew(name, len+1);
+    /* FIXME: snprintf used to be used here for extra safety, but this
+     * requires extra checking on Windows since it only provides a
+     * non-C99-conforming implementation as _snprintf()... */
+    ret = sprintf(name, "SubExpr %d", i);
+    if (ret < 0 || ret > len)
+    {
+        sfree(name);
+        name = NULL;
+    }
+    sel->name        = name;
+    sel->u.cgrp.name = name;
+}
+
+/*! \brief
+ * Processes and extracts subexpressions from a given selection subtree.
+ *
+ * \param   sel      Root of the subtree to process.
+ * \param   subexprn Pointer to a subexpression counter.
+ * \returns Pointer to a chain of subselections, or NULL if none were found.
+ *
+ * This function finds recursively all \ref SEL_SUBEXPRREF elements below
+ * the given root element and ensures that their children are within
+ * \ref SEL_SUBEXPR elements. It also creates a chain of \ref SEL_ROOT elements
+ * that contain the subexpression as their children and returns the first
+ * of these root elements.
+ */
+static t_selelem *
+extract_item_subselections(t_selelem *sel, int *subexprn)
+{
+    t_selelem *root;
+    t_selelem *subexpr;
+    t_selelem *child;
+
+    root = subexpr = NULL;
+    child = sel->child;
+    while (child)
+    {
+        if (!root)
+        {
+            root = subexpr = extract_item_subselections(child, subexprn);
+        }
+        else
+        {
+            subexpr->next = extract_item_subselections(child, subexprn);
+        }
+        while (subexpr && subexpr->next)
+        {
+            subexpr = subexpr->next;
+        }
+        /* The latter check excludes variable references.
+         * It also excludes subexpression elements that have already been
+         * processed, because they are given a name when they are first
+         * encountered.
+         * TODO: There should be a more robust mechanism (probably a dedicated
+         * flag) for detecting parser-generated subexpressions than relying on
+         * a NULL name field. */
+        if (child->type == SEL_SUBEXPRREF && (child->child->type != SEL_SUBEXPR
+                                              || child->child->name == NULL))
+        {
+            /* Create the root element for the subexpression */
+            if (!root)
+            {
+                root = subexpr = _gmx_selelem_create(SEL_ROOT);
+            }
+            else
+            {
+                subexpr->next = _gmx_selelem_create(SEL_ROOT);
+                subexpr       = subexpr->next;
+            }
+            /* Create the subexpression element and/or
+             * move the actual subexpression under the created element. */
+            if (child->child->type != SEL_SUBEXPR)
+            {
+                subexpr->child = _gmx_selelem_create(SEL_SUBEXPR);
+                _gmx_selelem_set_vtype(subexpr->child, child->v.type);
+                subexpr->child->child = child->child;
+                child->child          = subexpr->child;
+            }
+            else
+            {
+                subexpr->child = child->child;
+            }
+            create_subexpression_name(subexpr->child, ++*subexprn);
+            subexpr->child->refcount++;
+            /* Set the flags for the created elements */
+            subexpr->flags          |= (child->flags & SEL_VALFLAGMASK);
+            subexpr->child->flags   |= (child->flags & SEL_VALFLAGMASK);
+        }
+        child = child->next;
+    }
+
+    return root;
+}
+
+/*! \brief
+ * Extracts subexpressions of the selection chain.
+ * 
+ * \param   sel First selection in the whole selection chain.
+ * \returns The new first element for the chain.
+ *
+ * Finds all the subexpressions (and their subexpressions) in the
+ * selection chain starting from \p sel and creates \ref SEL_SUBEXPR
+ * elements for them.
+ * \ref SEL_ROOT elements are also created for each subexpression
+ * and inserted into the selection chain before the expressions that
+ * refer to them.
+ */
+static t_selelem *
+extract_subexpressions(t_selelem *sel)
+{
+    t_selelem   *root, *item, *next;
+    int          subexprn;
+
+    subexprn = 0;
+    root = NULL;
+    next = sel;
+    while (next)
+    {
+        item = extract_item_subselections(next, &subexprn);
+        if (item)
+        {
+            if (!root)
+            {
+                root = item;
+            }
+            else
+            {
+                sel->next = item;
+            }
+            while (item->next)
+            {
+                item = item->next;
+            }
+            item->next = next;
+        }
+        else if (!root)
+        {
+            root = next;
+        }
+        sel = next;
+        next = next->next;
+    }
+    return root;
+}
+
+
+/********************************************************************
+ * BOOLEAN OPERATION REORDERING
+ ********************************************************************/
+
+/*! \brief
+ * Removes redundant gmx_boolean selection elements.
+ *
+ * \param  sel Root of the selection subtree to optimize.
+ *
+ * This function merges similar gmx_boolean operations (e.g., (A or B) or C becomes
+ * a single OR operation with three operands).
+ */
+static void
+optimize_gmx_boolean_expressions(t_selelem *sel)
+{
+    t_selelem *child, *prev;
+
+    /* Do recursively for children */
+    if (sel->type != SEL_SUBEXPRREF)
+    {
+        prev  = NULL;
+        child = sel->child;
+        while (child)
+        {
+            optimize_gmx_boolean_expressions(child);
+            /* Remove double negations */
+            if (child->type == SEL_BOOLEAN && child->u.boolt == BOOL_NOT
+                && child->child->type == SEL_BOOLEAN && child->child->u.boolt == BOOL_NOT)
+            {
+                /* Move the doubly negated expression up two levels */
+                if (!prev)
+                {
+                    sel->child = child->child->child;
+                    prev       = sel->child;
+                }
+                else
+                {
+                    prev->next = child->child->child;
+                    prev       = prev->next;
+                }
+                child->child->child->next = child->next;
+                /* Remove the two negations */
+                child->child->child = NULL;
+                child->next         = NULL;
+                _gmx_selelem_free(child);
+                child = prev;
+            }
+            prev  = child;
+            child = child->next;
+        }
+    }
+    if (sel->type != SEL_BOOLEAN || sel->u.boolt == BOOL_NOT)
+    {
+        return;
+    }
+    /* Merge subsequent binary operations */
+    prev  = NULL;
+    child = sel->child;
+    while (child)
+    {
+        if (child->type == SEL_BOOLEAN && child->u.boolt == sel->u.boolt)
+        {
+            if (!prev)
+            {
+                sel->child = child->child;
+                prev       = sel->child;
+            }
+            else
+            {
+                prev->next = child->child;
+            }
+            while (prev->next)
+            {
+                prev = prev->next;
+            }
+            prev->next = child->next;
+            sfree(child->v.u.g);
+            sfree(child);
+            child = prev->next;
+        }
+        else
+        {
+            prev = child;
+            child = child->next;
+        }
+    }
+}
+
+/*! \brief
+ * Reorders children of gmx_boolean expressions such that static selections
+ * come first.
+ *
+ * \param  sel Root of the selection subtree to reorder.
+ *
+ * The relative order of static expressions does not change.
+ * The same is true for the dynamic expressions.
+ */
+static void
+reorder_gmx_boolean_static_children(t_selelem *sel)
+{
+    t_selelem *child, *prev, *next;
+
+    /* Do recursively for children */
+    if (sel->type != SEL_SUBEXPRREF)
+    {
+        child = sel->child;
+        while (child)
+        {
+            reorder_gmx_boolean_static_children(child);
+            child = child->next;
+        }
+    }
+
+    /* Reorder gmx_boolean expressions such that static selections come first */
+    if (sel->type == SEL_BOOLEAN && (sel->flags & SEL_DYNAMIC))
+    {
+        t_selelem  start;
+
+        start.next = sel->child;
+        prev  = &start;
+        child = &start;
+        while (child->next)
+        {
+            /* child is the last handled static expression */
+            /* prev is the last handled non-static expression */
+            next = prev->next;
+            while (next && (next->flags & SEL_DYNAMIC))
+            {
+                prev = next;
+                next = next->next;
+            }
+            /* next is now the first static expression after child */
+            if (!next)
+            {
+                break;
+            }
+            /* Reorder such that next comes after child */
+            if (prev != child)
+            {
+                prev->next  = next->next;
+                next->next  = child->next;
+                child->next = next;
+            }
+            else
+            {
+                prev = prev->next;
+            }
+            /* Advance child by one */
+            child = next;
+        }
+
+        sel->child = start.next;
+    }
+}
+
+
+/********************************************************************
+ * ARITHMETIC EXPRESSION PROCESSING
+ ********************************************************************/
+
+/*! \brief
+ * Processes arithmetic expressions to simplify and speed up evaluation.
+ *
+ * \param  sel Root of the selection subtree to process.
+ *
+ * Currently, this function only converts integer constants to reals
+ * within arithmetic expressions.
+ */
+static gmx_bool
+optimize_arithmetic_expressions(t_selelem *sel)
+{
+    t_selelem  *child;
+    gmx_bool        bOk;
+
+    /* Do recursively for children. */
+    if (sel->type != SEL_SUBEXPRREF)
+    {
+        child = sel->child;
+        while (child)
+        {
+            bOk = optimize_arithmetic_expressions(child);
+            if (!bOk)
+            {
+                return bOk;
+            }
+            child = child->next;
+        }
+    }
+
+    if (sel->type != SEL_ARITHMETIC)
+    {
+        return TRUE;
+    }
+
+    /* Convert integer constants to reals. */
+    child = sel->child;
+    while (child)
+    {
+        if (child->v.type == INT_VALUE)
+        {
+            real  *r;
+
+            if (child->type != SEL_CONST)
+            {
+                gmx_impl("Non-constant integer expressions not implemented in arithmetic evaluation");
+                return FALSE;
+            }
+            snew(r, 1);
+            r[0] = child->v.u.i[0];
+            sfree(child->v.u.i);
+            child->v.u.r = r;
+            child->v.type = REAL_VALUE;
+        }
+        else if (child->v.type != REAL_VALUE)
+        {
+            gmx_bug("Internal error");
+            return FALSE;
+        }
+        child = child->next;
+    }
+    return TRUE;
+}
+
+
+/********************************************************************
+ * EVALUATION PREPARATION COMPILER
+ ********************************************************************/
+
+/*! \brief
+ * Sets the evaluation functions for the selection (sub)tree.
+ *
+ * \param[in,out] sel Root of the selection subtree to process.
+ * \returns       TRUE on success, FALSE if any subexpression fails.
+ *
+ * This function sets the evaluation function (\c t_selelem::evaluate)
+ * for the selection elements.
+ */
+static gmx_bool
+init_item_evalfunc(t_selelem *sel)
+{
+    /* Process children. */
+    if (sel->type != SEL_SUBEXPRREF)
+    {
+        t_selelem *child;
+
+        child = sel->child;
+        while (child)
+        {
+            if (!init_item_evalfunc(child))
+            {
+                return FALSE;
+            }
+            child = child->next;
+        }
+    }
+
+    /* Set the evaluation function */
+    switch (sel->type)
+    {
+        case SEL_CONST:
+            if (sel->v.type == GROUP_VALUE)
+            {
+                sel->evaluate = &_gmx_sel_evaluate_static;
+            }
+            break;
+
+        case SEL_EXPRESSION:
+            if (!(sel->flags & SEL_DYNAMIC) && sel->u.expr.method
+                && sel->u.expr.method->init_frame)
+            {
+                sel->flags |= SEL_INITFRAME;
+            }
+            sel->evaluate = &_gmx_sel_evaluate_method;
+            break;
+
+        case SEL_ARITHMETIC:
+            sel->evaluate = &_gmx_sel_evaluate_arithmetic;
+            break;
+
+        case SEL_MODIFIER:
+            if (sel->v.type != NO_VALUE)
+            {
+                sel->evaluate = &_gmx_sel_evaluate_modifier;
+            }
+            break;
+
+        case SEL_BOOLEAN:
+            switch (sel->u.boolt)
+            {
+                case BOOL_NOT: sel->evaluate = &_gmx_sel_evaluate_not; break;
+                case BOOL_AND: sel->evaluate = &_gmx_sel_evaluate_and; break;
+                case BOOL_OR:  sel->evaluate = &_gmx_sel_evaluate_or;  break;
+                case BOOL_XOR:
+                    gmx_impl("xor expressions not implemented");
+                    return FALSE;
+            }
+            break;
+
+        case SEL_ROOT:
+            sel->evaluate = &_gmx_sel_evaluate_root;
+            break;
+
+        case SEL_SUBEXPR:
+            sel->evaluate = (sel->refcount == 2
+                             ? &_gmx_sel_evaluate_subexpr_simple
+                             : &_gmx_sel_evaluate_subexpr);
+            break;
+
+        case SEL_SUBEXPRREF:
+            sel->name     = sel->child->name;
+            sel->evaluate = (sel->child->refcount == 2
+                             ? &_gmx_sel_evaluate_subexprref_simple
+                             : &_gmx_sel_evaluate_subexprref);
+            break;
+
+        case SEL_GROUPREF:
+            gmx_incons("unresolved group reference in compilation");
+            return FALSE;
+    }
+
+    return TRUE;
+}
+
+/*! \brief
+ * Sets the memory pool for selection elements that can use it.
+ *
+ * \param     sel      Root of the selection subtree to process.
+ * \param[in] mempool  Memory pool to use.
+ */
+static void
+setup_memory_pooling(t_selelem *sel, gmx_sel_mempool_t *mempool)
+{
+    if (sel->type != SEL_SUBEXPRREF)
+    {
+        t_selelem         *child;
+
+        child = sel->child;
+        while (child)
+        {
+            if ((sel->type == SEL_BOOLEAN && (child->flags & SEL_DYNAMIC))
+                || (sel->type == SEL_ARITHMETIC && child->type != SEL_CONST
+                    && !(child->flags & SEL_SINGLEVAL))
+                || (sel->type == SEL_SUBEXPR && sel->refcount > 2))
+            {
+                child->mempool = mempool;
+                if (child->type == SEL_SUBEXPRREF
+                    && child->child->refcount == 2)
+                {
+                    child->child->child->mempool = mempool;
+                }
+            }
+            setup_memory_pooling(child, mempool);
+            child = child->next;
+        }
+    }
+}
+
+/*! \brief
+ * Prepares the selection (sub)tree for evaluation.
+ *
+ * \param[in,out] sel Root of the selection subtree to prepare.
+ *
+ * It also allocates memory for the \p sel->v.u.g or \p sel->v.u.p
+ * structure if required.
+ */
+static void
+init_item_evaloutput(t_selelem *sel)
+{
+    /* Process children. */
+    if (sel->type != SEL_SUBEXPRREF)
+    {
+        t_selelem *child;
+
+        child = sel->child;
+        while (child)
+        {
+            init_item_evaloutput(child);
+            child = child->next;
+        }
+    }
+
+    if (sel->type == SEL_SUBEXPR && sel->refcount == 2)
+    {
+        sel->flags &= ~(SEL_ALLOCVAL | SEL_ALLOCDATA);
+        if (sel->v.type == GROUP_VALUE || sel->v.type == POS_VALUE)
+        {
+            _gmx_selvalue_setstore(&sel->v, sel->child->v.u.ptr);
+        }
+    }
+    else if (sel->type == SEL_SUBEXPR
+             && (sel->cdata->flags & SEL_CDATA_FULLEVAL))
+    {
+        sel->evaluate = &_gmx_sel_evaluate_subexpr_staticeval;
+        sel->cdata->evaluate = sel->evaluate;
+        sel->child->mempool = NULL;
+        sel->flags &= ~(SEL_ALLOCVAL | SEL_ALLOCDATA);
+        if (sel->v.type == GROUP_VALUE || sel->v.type == POS_VALUE)
+        {
+            _gmx_selvalue_setstore(&sel->v, sel->child->v.u.ptr);
+        }
+    }
+    else if (sel->type == SEL_SUBEXPRREF && sel->child->refcount == 2)
+    {
+        if (sel->v.u.ptr)
+        {
+            _gmx_selvalue_setstore(&sel->child->v, sel->v.u.ptr);
+            _gmx_selelem_free_values(sel->child->child);
+            sel->child->child->flags &= ~(SEL_ALLOCVAL | SEL_ALLOCDATA);
+            sel->child->child->flags |= (sel->flags & SEL_ALLOCDATA);
+            _gmx_selvalue_setstore(&sel->child->child->v, sel->v.u.ptr);
+        }
+        else if (sel->v.type == GROUP_VALUE || sel->v.type == POS_VALUE)
+        {
+            _gmx_selvalue_setstore(&sel->v, sel->child->child->v.u.ptr);
+        }
+        sel->flags &= ~(SEL_ALLOCVAL | SEL_ALLOCDATA);
+    }
+
+    /* Make sure that the group/position structure is allocated. */
+    if (!sel->v.u.ptr && (sel->flags & SEL_ALLOCVAL))
+    {
+        if (sel->v.type == GROUP_VALUE || sel->v.type == POS_VALUE)
+        {
+            _gmx_selvalue_reserve(&sel->v, 1);
+            sel->v.nr = 1;
+        }
+    }
+}
+
+
+/********************************************************************
+ * COMPILER DATA INITIALIZATION
+ ********************************************************************/
+
+/*! \brief
+ * Allocates memory for the compiler data and initializes the structure.
+ *
+ * \param sel Root of the selection subtree to process.
+ */
+static void
+init_item_compilerdata(t_selelem *sel)
+{
+    t_selelem   *child;
+
+    /* Allocate the compiler data structure */
+    snew(sel->cdata, 1);
+
+    /* Store the real evaluation method because the compiler will replace it */
+    sel->cdata->evaluate = sel->evaluate;
+
+    /* Initialize the flags */
+    sel->cdata->flags = SEL_CDATA_STATICEVAL;
+    if (!(sel->flags & SEL_DYNAMIC))
+    {
+        sel->cdata->flags |= SEL_CDATA_STATIC;
+    }
+    if (sel->type == SEL_SUBEXPR)
+    {
+        sel->cdata->flags |= SEL_CDATA_EVALMAX;
+    }
+    /* Set the full evaluation flag for subexpressions that require it;
+     * the subexpression has already been initialized, so we can simply
+     * access its compilation flags.*/
+    if (sel->type == SEL_EXPRESSION || sel->type == SEL_MODIFIER)
+    {
+        child = sel->child;
+        while (child)
+        {
+            if (!(child->flags & SEL_ATOMVAL) && child->child)
+            {
+                child->child->cdata->flags |= SEL_CDATA_FULLEVAL;
+            }
+            child = child->next;
+        }
+    }
+    else if (sel->type == SEL_ROOT && sel->child->type == SEL_SUBEXPRREF)
+    {
+        sel->child->child->cdata->flags |= SEL_CDATA_FULLEVAL;
+    }
+
+    /* Initialize children */
+    if (sel->type != SEL_SUBEXPRREF)
+    {
+        child = sel->child;
+        while (child)
+        {
+            init_item_compilerdata(child);
+            child = child->next;
+        }
+    }
+
+    /* Determine whether we should evaluate the minimum or the maximum
+     * for the children of this element. */
+    if (sel->type == SEL_BOOLEAN)
+    {
+        gmx_bool  bEvalMax;
+
+        bEvalMax = (sel->u.boolt == BOOL_AND);
+        child = sel->child;
+        while (child)
+        {
+            if (bEvalMax)
+            {
+                child->cdata->flags |= SEL_CDATA_EVALMAX;
+            }
+            else if (child->type == SEL_BOOLEAN && child->u.boolt == BOOL_NOT)
+            {
+                child->child->cdata->flags |= SEL_CDATA_EVALMAX;
+            }
+            child = child->next;
+        }
+    }
+    else if (sel->type == SEL_EXPRESSION || sel->type == SEL_MODIFIER
+             || sel->type == SEL_SUBEXPR)
+    {
+        child = sel->child;
+        while (child)
+        {
+            child->cdata->flags |= SEL_CDATA_EVALMAX;
+            child = child->next;
+        }
+    }
+}
+
+/*! \brief
+ * Initializes the static evaluation flag for a selection subtree.
+ *
+ * \param[in,out] sel  Root of the selection subtree to process.
+ *
+ * Sets the \c bStaticEval in the compiler data structure:
+ * for any element for which the evaluation group may depend on the trajectory
+ * frame, the flag is cleared.
+ *
+ * reorder_gmx_boolean_static_children() should have been called.
+ */
+static void
+init_item_staticeval(t_selelem *sel)
+{
+    t_selelem   *child;
+
+    /* Subexpressions with full evaluation should always have bStaticEval,
+     * so don't do anything if a reference to them is encountered. */
+    if (sel->type == SEL_SUBEXPRREF
+        && (sel->child->cdata->flags & SEL_CDATA_FULLEVAL))
+    {
+        return;
+    }
+
+    /* Propagate the bStaticEval flag to children if it is not set */
+    if (!(sel->cdata->flags & SEL_CDATA_STATICEVAL))
+    {
+        child = sel->child;
+        while (child)
+        {
+            if ((sel->type != SEL_EXPRESSION && sel->type != SEL_MODIFIER)
+                || (child->flags & SEL_ATOMVAL))
+            {
+                if (child->cdata->flags & SEL_CDATA_STATICEVAL)
+                {
+                    child->cdata->flags &= ~SEL_CDATA_STATICEVAL;
+                    init_item_staticeval(child);
+                }
+            }
+            child = child->next;
+        }
+    }
+    else /* bStaticEval is set */
+    {
+        /* For gmx_boolean expressions, any expression after the first dynamic
+         * expression should not have bStaticEval. */
+        if (sel->type == SEL_BOOLEAN)
+        {
+            child = sel->child;
+            while (child && !(child->flags & SEL_DYNAMIC))
+            {
+                child = child->next;
+            }
+            if (child)
+            {
+                child = child->next;
+            }
+            while (child)
+            {
+                child->cdata->flags &= ~SEL_CDATA_STATICEVAL;
+                child = child->next;
+            }
+        }
+
+        /* Process the children */
+        child = sel->child;
+        while (child)
+        {
+            init_item_staticeval(child);
+            child = child->next;
+        }
+    }
+}
+
+/*! \brief
+ * Initializes compiler flags for subexpressions.
+ *
+ * \param sel Root of the selection subtree to process.
+ */
+static void
+init_item_subexpr_flags(t_selelem *sel)
+{
+    if (sel->type == SEL_SUBEXPR)
+    {
+        if (sel->refcount == 2)
+        {
+            sel->cdata->flags |= SEL_CDATA_SIMPLESUBEXPR;
+        }
+        else if (!(sel->cdata->flags & SEL_CDATA_FULLEVAL))
+        {
+            sel->cdata->flags |= SEL_CDATA_COMMONSUBEXPR;
+        }
+    }
+    else if (sel->type == SEL_SUBEXPRREF && sel->child->refcount == 2)
+    {
+        sel->cdata->flags |= SEL_CDATA_SIMPLESUBEXPR;
+    }
+
+    /* Process children, but only follow subexpression references if the
+     * common subexpression flag needs to be propagated. */
+    if (sel->type != SEL_SUBEXPRREF
+        || ((sel->cdata->flags & SEL_CDATA_COMMONSUBEXPR)
+            && sel->child->refcount > 2))
+    {
+        t_selelem *child = sel->child;
+
+        while (child)
+        {
+            if (!(child->cdata->flags & SEL_CDATA_COMMONSUBEXPR))
+            {
+                if (sel->type != SEL_EXPRESSION || (child->flags & SEL_ATOMVAL))
+                {
+                    child->cdata->flags |=
+                        (sel->cdata->flags & SEL_CDATA_COMMONSUBEXPR);
+                }
+                init_item_subexpr_flags(child);
+            }
+            child = child->next;
+        }
+    }
+}
+
+/*! \brief
+ * Initializes the gmin and gmax fields of the compiler data structure.
+ *
+ * \param sel Root of the selection subtree to process.
+ */
+static void
+init_item_minmax_groups(t_selelem *sel)
+{
+    /* Process children. */
+    if (sel->type != SEL_SUBEXPRREF)
+    {
+        t_selelem *child;
+
+        child = sel->child;
+        while (child)
+        {
+            init_item_minmax_groups(child);
+            child = child->next;
+        }
+    }
+
+    /* Initialize the minimum and maximum evaluation groups. */
+    if (sel->type != SEL_ROOT && sel->v.type != NO_VALUE)
+    {
+        if (sel->v.type == GROUP_VALUE
+            && (sel->cdata->flags & SEL_CDATA_STATIC))
+        {
+            sel->cdata->gmin = sel->v.u.g;
+            sel->cdata->gmax = sel->v.u.g;
+        }
+        else if (sel->type == SEL_SUBEXPR
+                 && ((sel->cdata->flags & SEL_CDATA_SIMPLESUBEXPR)
+                     || (sel->cdata->flags & SEL_CDATA_FULLEVAL)))
+        {
+            sel->cdata->gmin = sel->child->cdata->gmin;
+            sel->cdata->gmax = sel->child->cdata->gmax;
+        }
+        else
+        {
+            sel->cdata->flags |= SEL_CDATA_MINMAXALLOC;
+            snew(sel->cdata->gmin, 1);
+            snew(sel->cdata->gmax, 1);
+        }
+    }
+}
+
+
+/********************************************************************
+ * EVALUATION GROUP INITIALIZATION
+ ********************************************************************/
+
+/*! \brief
+ * Initializes evaluation groups for root items.
+ *
+ * \param[in,out] sc   Selection collection data.
+ *
+ * The evaluation group of each \ref SEL_ROOT element corresponding to a
+ * selection in \p sc is set to \p gall.  The same is done for \ref SEL_ROOT
+ * elements corresponding to subexpressions that need full evaluation.
+ */
+static void
+initialize_evalgrps(gmx_ana_selcollection_t *sc)
+{
+    t_selelem   *root;
+
+    root = sc->root;
+    while (root)
+    {
+        if (root->child->type != SEL_SUBEXPR
+            || (root->child->cdata->flags & SEL_CDATA_FULLEVAL))
+        {
+            gmx_ana_index_set(&root->u.cgrp, sc->gall.isize, sc->gall.index,
+                              root->u.cgrp.name, 0);
+        }
+        root = root->next;
+    }
+}
+
+
+/********************************************************************
+ * STATIC ANALYSIS
+ ********************************************************************/
+
+/*! \brief
+ * Marks a subtree completely dynamic or undoes such a change.
+ *
+ * \param     sel      Selection subtree to mark.
+ * \param[in] bDynamic If TRUE, the \p bStatic flag of the whole
+ *   selection subtree is cleared. If FALSE, the flag is restored to
+ *   using \ref SEL_DYNAMIC.
+ *
+ * Does not descend into parameters of methods unless the parameters
+ * are evaluated for each atom.
+ */
+static void
+mark_subexpr_dynamic(t_selelem *sel, gmx_bool bDynamic)
+{
+    t_selelem *child;
+
+    if (!bDynamic && !(sel->flags & SEL_DYNAMIC))
+    {
+        sel->cdata->flags |= SEL_CDATA_STATIC;
+    }
+    else
+    {
+        sel->cdata->flags &= ~SEL_CDATA_STATIC;
+    }
+    child = sel->child;
+    while (child)
+    {
+        if (sel->type != SEL_EXPRESSION || child->type != SEL_SUBEXPRREF
+            || (child->u.param->flags & SPAR_ATOMVAL))
+        {
+            mark_subexpr_dynamic(child, bDynamic);
+        }
+        child = child->next;
+    }
+}
+
+/*! \brief
+ * Frees memory for subexpressions that are no longer needed.
+ *
+ * \param     sel      Selection subtree to check.
+ *
+ * Checks whether the subtree rooted at \p sel refers to any \ref SEL_SUBEXPR
+ * elements that are not referred to by anything else except their own root
+ * element. If such elements are found, all memory allocated for them is freed
+ * except the actual element. The element is left because otherwise a dangling
+ * pointer would be left at the root element, which is not traversed by this
+ * function. Later compilation passes remove the stub elements.
+ */
+static void
+release_subexpr_memory(t_selelem *sel)
+{
+    if (sel->type == SEL_SUBEXPR)
+    {
+        if (sel->refcount == 2)
+        {
+            release_subexpr_memory(sel->child);
+            sel->name = NULL;
+            _gmx_selelem_free_chain(sel->child);
+            _gmx_selelem_free_values(sel);
+            _gmx_selelem_free_exprdata(sel);
+            _gmx_selelem_free_compiler_data(sel);
+            sel->child = NULL;
+        }
+    }
+    else
+    {
+        t_selelem *child;
+
+        child = sel->child;
+        while (child)
+        {
+            release_subexpr_memory(child);
+            child = child->next;
+        }
+    }
+}
+
+/*! \brief
+ * Makes an evaluated selection element static.
+ *
+ * \param     sel   Selection element to make static.
+ *
+ * The evaluated value becomes the value of the static element.
+ * The element type is changed to SEL_CONST and the children are
+ * deleted.
+ */
+static void
+make_static(t_selelem *sel)
+{
+    /* If this is a subexpression reference and the data is stored in the
+     * child, we transfer data ownership before doing anything else. */
+    if (sel->type == SEL_SUBEXPRREF
+        && (sel->cdata->flags & SEL_CDATA_SIMPLESUBEXPR))
+    {
+        if (sel->child->child->flags & SEL_ALLOCDATA)
+        {
+            sel->flags |= SEL_ALLOCDATA;
+            sel->child->child->flags &= ~SEL_ALLOCDATA;
+        }
+        if (sel->child->child->flags & SEL_ALLOCVAL)
+        {
+            sel->flags |= SEL_ALLOCVAL;
+            sel->v.nalloc = sel->child->child->v.nalloc;
+            sel->child->child->flags &= ~SEL_ALLOCVAL;
+            sel->child->child->v.nalloc = -1;
+        }
+    }
+    /* Free the children. */
+    release_subexpr_memory(sel);
+    _gmx_selelem_free_chain(sel->child);
+    sel->child           = NULL;
+    /* Free the expression data as it is no longer needed */
+    _gmx_selelem_free_exprdata(sel);
+    /* Make the item static */
+    sel->name            = NULL;
+    sel->type            = SEL_CONST;
+    sel->evaluate        = NULL;
+    sel->cdata->evaluate = NULL;
+    /* Set the group value.
+     * free_exprdata above frees the cgrp group, so we can just override it. */
+    if (sel->v.type == GROUP_VALUE)
+    {
+        gmx_ana_index_set(&sel->u.cgrp, sel->v.u.g->isize, sel->v.u.g->index, NULL, 0);
+    }
+}
+
+/*! \brief
+ * Evaluates a constant expression during analyze_static().
+ *
+ * \param[in]     data Evaluation data.
+ * \param[in,out] sel Selection to process.
+ * \param[in]     g   The evaluation group.
+ * \returns       0 on success, a non-zero error code on error.
+ */
+static int
+process_const(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g)
+{
+    int  rc;
+
+    rc = 0;
+    if (sel->v.type == GROUP_VALUE)
+    {
+        if (sel->cdata->evaluate)
+        {
+            rc = sel->cdata->evaluate(data, sel, g);
+        }
+    }
+    /* Other constant expressions do not need evaluation */
+    return rc;
+}
+
+/*! \brief
+ * Sets the parameter value pointer for \ref SEL_SUBEXPRREF params.
+ *
+ * \param[in,out] sel Selection to process.
+ *
+ * Copies the value pointer of \p sel to \c sel->u.param if one is present
+ * and should receive the value from the compiler
+ * (most parameter values are handled during parsing).
+ * If \p sel is not of type \ref SEL_SUBEXPRREF, or if \c sel->u.param is NULL,
+ * the function does nothing.
+ * Also, if the \c sel->u.param does not have \ref SPAR_VARNUM or
+ * \ref SPAR_ATOMVAL, the function returns immediately.
+ */
+static void
+store_param_val(t_selelem *sel)
+{
+    /* Return immediately if there is no parameter. */
+    if (sel->type != SEL_SUBEXPRREF || !sel->u.param)
+    {
+        return;
+    }
+
+    /* Or if the value does not need storing. */
+    if (!(sel->u.param->flags & (SPAR_VARNUM | SPAR_ATOMVAL)))
+    {
+        return;
+    }
+
+    if (sel->v.type == INT_VALUE || sel->v.type == REAL_VALUE
+        || sel->v.type == STR_VALUE)
+    {
+        _gmx_selvalue_setstore(&sel->u.param->val, sel->v.u.ptr);
+    }
+}
+
+/*! \brief
+ * Handles the initialization of a selection method during analyze_static() pass.
+ *
+ * \param[in,out] sel Selection element to process.
+ * \param[in]     top Topology structure.
+ * \param[in]     isize Size of the evaluation group for the element.
+ * \returns       0 on success, a non-zero error code on return.
+ *
+ * Calls sel_initfunc() (and possibly sel_outinitfunc()) to initialize the
+ * method.
+ * If no \ref SPAR_ATOMVAL parameters are present, multiple initialization
+ * is prevented by using \ref SEL_METHODINIT and \ref SEL_OUTINIT flags.
+ */
+static int
+init_method(t_selelem *sel, t_topology *top, int isize)
+{
+    t_selelem *child;
+    gmx_bool       bAtomVal;
+    int        rc;
+
+    /* Find out whether there are any atom-valued parameters */
+    bAtomVal = FALSE;
+    child = sel->child;
+    while (child)
+    {
+        if (child->flags & SEL_ATOMVAL)
+        {
+            bAtomVal = TRUE;
+        }
+        child = child->next;
+    }
+
+    /* Initialize the method */
+    if (sel->u.expr.method->init
+        && (bAtomVal || !(sel->flags & SEL_METHODINIT)))
+    {
+        sel->flags |= SEL_METHODINIT;
+        rc = sel->u.expr.method->init(top, sel->u.expr.method->nparams,
+                sel->u.expr.method->param, sel->u.expr.mdata);
+        if (rc != 0)
+        {
+            return rc;
+        }
+    }
+    if (bAtomVal || !(sel->flags & SEL_OUTINIT))
+    {
+        sel->flags |= SEL_OUTINIT;
+        if (sel->u.expr.method->outinit)
+        {
+            rc = sel->u.expr.method->outinit(top, &sel->v, sel->u.expr.mdata);
+            if (rc != 0)
+            {
+                return rc;
+            }
+            if (sel->v.type != POS_VALUE && sel->v.type != GROUP_VALUE)
+            {
+                alloc_selection_data(sel, isize, TRUE);
+            }
+        }
+        else
+        {
+            alloc_selection_data(sel, isize, TRUE);
+            if ((sel->flags & SEL_DYNAMIC)
+                && sel->v.type != GROUP_VALUE && sel->v.type != POS_VALUE)
+            {
+                sel->v.nr = isize;
+            }
+            /* If the method is char-valued, pre-allocate the strings. */
+            if (sel->u.expr.method->flags & SMETH_CHARVAL)
+            {
+                int  i;
+
+                /* A sanity check */
+                if (sel->v.type != STR_VALUE)
+                {
+                    gmx_bug("internal error");
+                    return -1;
+                }
+                sel->flags |= SEL_ALLOCDATA;
+                for (i = 0; i < isize; ++i)
+                {
+                    if (sel->v.u.s[i] == NULL)
+                    {
+                        snew(sel->v.u.s[i], 2);
+                    }
+                }
+            }
+        }
+        /* Clear the values for dynamic output to avoid valgrind warnings. */
+        if ((sel->flags & SEL_DYNAMIC) && sel->v.type == REAL_VALUE)
+        {
+            int i;
+
+            for (i = 0; i < sel->v.nr; ++i)
+            {
+                sel->v.u.r[i] = 0.0;
+            }
+        }
+    }
+
+    return 0;
+}
+
+/*! \brief
+ * Evaluates the static part of a gmx_boolean expression.
+ *
+ * \param[in]     data Evaluation data.
+ * \param[in,out] sel Boolean selection element whose children should be
+ *   processed.
+ * \param[in]     g   The evaluation group.
+ * \returns       0 on success, a non-zero error code on error.
+ *
+ * reorder_item_static_children() should have been called.
+ */
+static int
+evaluate_gmx_boolean_static_part(gmx_sel_evaluate_t *data, t_selelem *sel,
+                             gmx_ana_index_t *g)
+{
+    t_selelem *child, *next;
+    int        rc;
+
+    /* Find the last static subexpression */
+    child = sel->child;
+    while (child->next && (child->next->cdata->flags & SEL_CDATA_STATIC))
+    {
+        child = child->next;
+    }
+    if (!(child->cdata->flags & SEL_CDATA_STATIC))
+    {
+        return 0;
+    }
+
+    /* Evalute the static part if there is more than one expression */
+    if (child != sel->child)
+    {
+        next  = child->next;
+        child->next = NULL;
+        rc = sel->cdata->evaluate(data, sel, g);
+        if (rc != 0)
+        {
+            return rc;
+        }
+        /* Replace the subexpressions with the result */
+        _gmx_selelem_free_chain(sel->child);
+        snew(child, 1);
+        child->type       = SEL_CONST;
+        child->flags      = SEL_FLAGSSET | SEL_SINGLEVAL | SEL_ALLOCVAL | SEL_ALLOCDATA;
+        _gmx_selelem_set_vtype(child, GROUP_VALUE);
+        child->evaluate   = NULL;
+        _gmx_selvalue_reserve(&child->v, 1);
+        gmx_ana_index_copy(child->v.u.g, sel->v.u.g, TRUE);
+        init_item_compilerdata(child);
+        init_item_minmax_groups(child);
+        child->cdata->flags &= ~SEL_CDATA_STATICEVAL;
+        child->cdata->flags |= sel->cdata->flags & SEL_CDATA_STATICEVAL;
+        child->next = next;
+        sel->child = child;
+    }
+    else if (child->evaluate)
+    {
+        rc = child->evaluate(data, child, g);
+        if (rc != 0)
+        {
+            return rc;
+        }
+    }
+    /* Set the evaluation function for the constant element.
+     * We never need to evaluate the element again during compilation,
+     * but we may need to evaluate the static part again if the
+     * expression is not an OR with a static evaluation group.
+     * If we reach here with a NOT expression, the NOT expression
+     * is also static, and will be made a constant later, so don't waste
+     * time copying the group. */
+    child->evaluate = NULL;
+    if (sel->u.boolt == BOOL_NOT
+        || ((sel->cdata->flags & SEL_CDATA_STATICEVAL)
+            && sel->u.boolt == BOOL_OR))
+    {
+        child->cdata->evaluate = NULL;
+    }
+    else
+    {
+        child->cdata->evaluate = &_gmx_sel_evaluate_static;
+        /* The cgrp has only been allocated if it originated from an
+         * external index group. In that case, we need special handling
+         * to preserve the name of the group and to not leak memory.
+         * If cgrp has been set in make_static(), it is not allocated,
+         * and hence we can overwrite it safely. */
+        if (child->u.cgrp.nalloc_index > 0)
+        {
+            char *name = child->u.cgrp.name;
+            gmx_ana_index_copy(&child->u.cgrp, child->v.u.g, FALSE);
+            gmx_ana_index_squeeze(&child->u.cgrp);
+            child->u.cgrp.name = name;
+        }
+        else
+        {
+            gmx_ana_index_copy(&child->u.cgrp, child->v.u.g, TRUE);
+        }
+    }
+    return 0;
+}
+
+/*! \brief
+ * Evaluates the minimum and maximum groups for a gmx_boolean expression.
+ *
+ * \param[in]  sel  \ref SEL_BOOLEAN element currently being evaluated.
+ * \param[in]  g    Group for which \p sel has been evaluated.
+ * \param[out] gmin Largest subset of the possible values of \p sel.
+ * \param[out] gmax Smallest superset of the possible values of \p sel.
+ *
+ * This is a helper function for analyze_static() that is called for
+ * dynamic \ref SEL_BOOLEAN elements after they have been evaluated.
+ * It uses the minimum and maximum groups of the children to calculate
+ * the minimum and maximum groups for \p sel, and also updates the static
+ * part of \p sel (which is in the first child) if the children give
+ * cause for this.
+ *
+ * This function may allocate some extra memory for \p gmin and \p gmax,
+ * but as these groups are freed at the end of analyze_static() (which is
+ * reached shortly after this function returns), this should not be a major
+ * problem.
+ */
+static void
+evaluate_gmx_boolean_minmax_grps(t_selelem *sel, gmx_ana_index_t *g,
+                             gmx_ana_index_t *gmin, gmx_ana_index_t *gmax)
+{
+    t_selelem *child;
+
+    switch (sel->u.boolt)
+    {
+        case BOOL_NOT:
+            gmx_ana_index_reserve(gmin, g->isize);
+            gmx_ana_index_reserve(gmax, g->isize);
+            gmx_ana_index_difference(gmax, g, sel->child->cdata->gmin);
+            gmx_ana_index_difference(gmin, g, sel->child->cdata->gmax);
+            break;
+
+        case BOOL_AND:
+            gmx_ana_index_copy(gmin, sel->child->cdata->gmin, TRUE);
+            gmx_ana_index_copy(gmax, sel->child->cdata->gmax, TRUE);
+            child = sel->child->next;
+            while (child && gmax->isize > 0)
+            {
+                gmx_ana_index_intersection(gmin, gmin, child->cdata->gmin);
+                gmx_ana_index_intersection(gmax, gmax, child->cdata->gmax);
+                child = child->next;
+            }
+            /* Update the static part if other expressions limit it */
+            if ((sel->child->cdata->flags & SEL_CDATA_STATIC)
+                && sel->child->v.u.g->isize > gmax->isize)
+            {
+                gmx_ana_index_copy(sel->child->v.u.g, gmax, FALSE);
+                gmx_ana_index_squeeze(sel->child->v.u.g);
+                if (sel->child->u.cgrp.isize > 0)
+                {
+                    gmx_ana_index_copy(&sel->child->u.cgrp, gmax, FALSE);
+                    gmx_ana_index_squeeze(&sel->child->u.cgrp);
+                }
+            }
+            break;
+
+        case BOOL_OR:
+            /* We can assume here that the gmin of children do not overlap
+             * because of the way _gmx_sel_evaluate_or() works. */
+            gmx_ana_index_reserve(gmin, g->isize);
+            gmx_ana_index_reserve(gmax, g->isize);
+            gmx_ana_index_copy(gmin, sel->child->cdata->gmin, FALSE);
+            gmx_ana_index_copy(gmax, sel->child->cdata->gmax, FALSE);
+            child = sel->child->next;
+            while (child && gmin->isize < g->isize)
+            {
+                gmx_ana_index_merge(gmin, gmin, child->cdata->gmin);
+                gmx_ana_index_union(gmax, gmax, child->cdata->gmax);
+                child = child->next;
+            }
+            /* Update the static part if other expressions have static parts
+             * that are not included. */
+            if ((sel->child->cdata->flags & SEL_CDATA_STATIC)
+                && sel->child->v.u.g->isize < gmin->isize)
+            {
+                gmx_ana_index_reserve(sel->child->v.u.g, gmin->isize);
+                gmx_ana_index_copy(sel->child->v.u.g, gmin, FALSE);
+                if (sel->child->u.cgrp.isize > 0)
+                {
+                    gmx_ana_index_reserve(&sel->child->u.cgrp, gmin->isize);
+                    gmx_ana_index_copy(&sel->child->u.cgrp, gmin, FALSE);
+                }
+            }
+            break;
+
+        case BOOL_XOR: /* Should not be reached */
+            gmx_impl("xor expressions not implemented");
+            break;
+    }
+}
+
+/*! \brief
+ * Evaluates the static parts of \p sel and analyzes the structure.
+ * 
+ * \param[in]     data Evaluation data.
+ * \param[in,out] sel  Selection currently being evaluated.
+ * \param[in]     g    Group for which \p sel should be evaluated.
+ * \returns       0 on success, a non-zero error code on error.
+ *
+ * This function is used as the replacement for the \c t_selelem::evaluate
+ * function pointer.
+ * It does the single most complex task in the compiler: after all elements
+ * have been processed, the \p gmin and \p gmax fields of \p t_compiler_data
+ * have been properly initialized, enough memory has been allocated for
+ * storing the value of each expression, and the static parts of the 
+ * expressions have been evaluated.
+ * The above is exactly true only for elements other than subexpressions:
+ * another pass is required for subexpressions that are referred to more than
+ * once and whose evaluation group is not known in advance.
+ */
+static int
+analyze_static(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g)
+{
+    t_selelem       *child, *next;
+    gmx_bool             bDoMinMax;
+    int              rc;
+
+    if (sel->type != SEL_ROOT && g)
+    {
+        alloc_selection_data(sel, g->isize, FALSE);
+    }
+
+    bDoMinMax = (sel->cdata->flags & SEL_CDATA_MINMAXALLOC);
+    if (sel->type != SEL_SUBEXPR && bDoMinMax)
+    {
+        gmx_ana_index_deinit(sel->cdata->gmin);
+        gmx_ana_index_deinit(sel->cdata->gmax);
+    }
+
+    /* TODO: This switch is awfully long... */
+    rc = 0;
+    switch (sel->type)
+    {
+        case SEL_CONST:
+            rc = process_const(data, sel, g);
+            break;
+
+        case SEL_EXPRESSION:
+        case SEL_MODIFIER:
+            rc = _gmx_sel_evaluate_method_params(data, sel, g);
+            if (rc != 0)
+            {
+                return rc;
+            }
+            rc = init_method(sel, data->top, g->isize);
+            if (rc != 0)
+            {
+                return rc;
+            }
+            if (!(sel->flags & SEL_DYNAMIC))
+            {
+                rc = sel->cdata->evaluate(data, sel, g);
+                if (rc == 0 && (sel->cdata->flags & SEL_CDATA_STATIC))
+                {
+                    make_static(sel);
+                }
+            }
+            else
+            {
+                /* Modifiers need to be evaluated even though they process
+                 * positions to get the modified output groups from the
+                 * maximum possible selections. */
+                if (sel->type == SEL_MODIFIER)
+                {
+                    rc = sel->cdata->evaluate(data, sel, g);
+                }
+                if (bDoMinMax)
+                {
+                    gmx_ana_index_copy(sel->cdata->gmax, g, TRUE);
+                }
+            }
+            break;
+
+        case SEL_BOOLEAN:
+            if (!(sel->flags & SEL_DYNAMIC))
+            {
+                rc = sel->cdata->evaluate(data, sel, g);
+                if (rc == 0 && (sel->cdata->flags & SEL_CDATA_STATIC))
+                {
+                    make_static(sel);
+                }
+            }
+            else
+            {
+                /* Evalute the static part if there is more than one expression */
+                rc = evaluate_gmx_boolean_static_part(data, sel, g);
+                if (rc != 0)
+                {
+                    return rc;
+                }
+
+                /* Evaluate the selection.
+                 * If the type is gmx_boolean, we must explicitly handle the
+                 * static part evaluated in evaluate_gmx_boolean_static_part()
+                 * here because g may be larger. */
+                if (sel->u.boolt == BOOL_AND && sel->child->type == SEL_CONST)
+                {
+                    rc = sel->cdata->evaluate(data, sel, sel->child->v.u.g);
+                }
+                else
+                {
+                    rc = sel->cdata->evaluate(data, sel, g);
+                }
+                if (rc != 0)
+                {
+                    return rc;
+                }
+
+                /* Evaluate minimal and maximal selections */
+                evaluate_gmx_boolean_minmax_grps(sel, g, sel->cdata->gmin,
+                                             sel->cdata->gmax);
+            }
+            break;
+
+        case SEL_ARITHMETIC:
+            rc = sel->cdata->evaluate(data, sel, g);
+            if (rc != 0)
+            {
+                return rc;
+            }
+            if (!(sel->flags & SEL_DYNAMIC))
+            {
+                if (sel->cdata->flags & SEL_CDATA_STATIC)
+                {
+                    make_static(sel);
+                }
+            }
+            else if (bDoMinMax)
+            {
+                gmx_ana_index_copy(sel->cdata->gmax, g, TRUE);
+            }
+            break;
+
+        case SEL_ROOT:
+            rc = sel->cdata->evaluate(data, sel, g);
+            break;
+
+        case SEL_SUBEXPR:
+            if (sel->cdata->flags & (SEL_CDATA_SIMPLESUBEXPR | SEL_CDATA_FULLEVAL))
+            {
+                rc = sel->cdata->evaluate(data, sel, g);
+                _gmx_selvalue_setstore(&sel->v, sel->child->v.u.ptr);
+            }
+            else if (sel->u.cgrp.isize == 0)
+            {
+                gmx_ana_index_reserve(&sel->u.cgrp, g->isize);
+                rc = sel->cdata->evaluate(data, sel, g);
+                if (bDoMinMax)
+                {
+                    gmx_ana_index_copy(sel->cdata->gmin, sel->child->cdata->gmin, TRUE);
+                    gmx_ana_index_copy(sel->cdata->gmax, sel->child->cdata->gmax, TRUE);
+                }
+            }
+            else
+            {
+                int isize = gmx_ana_index_difference_size(g, &sel->u.cgrp);
+                if (isize > 0)
+                {
+                    isize += sel->u.cgrp.isize;
+                    gmx_ana_index_reserve(&sel->u.cgrp, isize);
+                    alloc_selection_data(sel, isize, FALSE);
+                }
+                rc = sel->cdata->evaluate(data, sel, g);
+                if (isize > 0 && bDoMinMax)
+                {
+                    gmx_ana_index_reserve(sel->cdata->gmin,
+                                          sel->cdata->gmin->isize
+                                          + sel->child->cdata->gmin->isize);
+                    gmx_ana_index_reserve(sel->cdata->gmax,
+                                          sel->cdata->gmax->isize
+                                          + sel->child->cdata->gmax->isize);
+                    gmx_ana_index_merge(sel->cdata->gmin, sel->cdata->gmin,
+                                        sel->child->cdata->gmin);
+                    gmx_ana_index_merge(sel->cdata->gmax, sel->cdata->gmax,
+                                        sel->child->cdata->gmax);
+                }
+            }
+            break;
+
+        case SEL_SUBEXPRREF:
+            if (!g && !(sel->cdata->flags & SEL_CDATA_SIMPLESUBEXPR))
+            {
+                /* The subexpression should have been evaluated if g is NULL
+                 * (i.e., this is a method parameter or a direct value of a
+                 * selection). */
+                alloc_selection_data(sel, sel->child->cdata->gmax->isize, TRUE);
+            }
+            rc = sel->cdata->evaluate(data, sel, g);
+            if (rc != 0)
+            {
+                return rc;
+            }
+            if ((sel->cdata->flags & SEL_CDATA_SIMPLESUBEXPR)
+                && (sel->child->child->flags & SEL_ALLOCVAL))
+            {
+                _gmx_selvalue_setstore(&sel->v, sel->child->child->v.u.ptr);
+            }
+            /* Store the parameter value if required */
+            store_param_val(sel);
+            if (!(sel->flags & SEL_DYNAMIC))
+            {
+                if (sel->cdata->flags & SEL_CDATA_STATIC)
+                {
+                    make_static(sel);
+                }
+            }
+            else if (bDoMinMax)
+            {
+                if ((sel->cdata->flags & SEL_CDATA_SIMPLESUBEXPR) || !g)
+                {
+                    gmx_ana_index_copy(sel->cdata->gmin, sel->child->cdata->gmin, TRUE);
+                    gmx_ana_index_copy(sel->cdata->gmax, sel->child->cdata->gmax, TRUE);
+                }
+                else
+                {
+                    gmx_ana_index_reserve(sel->cdata->gmin,
+                                          min(g->isize, sel->child->cdata->gmin->isize));
+                    gmx_ana_index_reserve(sel->cdata->gmax,
+                                          min(g->isize, sel->child->cdata->gmax->isize));
+                    gmx_ana_index_intersection(sel->cdata->gmin,
+                                               sel->child->cdata->gmin, g);
+                    gmx_ana_index_intersection(sel->cdata->gmax,
+                                               sel->child->cdata->gmax, g);
+                }
+            }
+            break;
+
+        case SEL_GROUPREF:
+            gmx_incons("unresolved group reference in compilation");
+            return -1;
+    }
+    /* Exit if there was some problem */
+    if (rc != 0)
+    {
+        return rc;
+    }
+
+    /* Update the minimal and maximal evaluation groups */
+    if (bDoMinMax)
+    {
+        gmx_ana_index_squeeze(sel->cdata->gmin);
+        gmx_ana_index_squeeze(sel->cdata->gmax);
+        sfree(sel->cdata->gmin->name);
+        sfree(sel->cdata->gmax->name);
+        sel->cdata->gmin->name = NULL;
+        sel->cdata->gmax->name = NULL;
+    }
+
+    /* Replace the result of the evaluation */
+    /* This is not necessary for subexpressions or for gmx_boolean negations
+     * because the evaluation function already has done it properly. */
+    if (sel->v.type == GROUP_VALUE && (sel->flags & SEL_DYNAMIC)
+        && sel->type != SEL_SUBEXPR
+        && !(sel->type == SEL_BOOLEAN && sel->u.boolt == BOOL_NOT))
+    {
+        if (sel->cdata->flags & SEL_CDATA_EVALMAX)
+        {
+            gmx_ana_index_copy(sel->v.u.g, sel->cdata->gmax, FALSE);
+        }
+        else
+        {
+            gmx_ana_index_copy(sel->v.u.g, sel->cdata->gmin, FALSE);
+        }
+    }
+
+    return 0;
+}
+
+
+/********************************************************************
+ * EVALUATION GROUP INITIALIZATION
+ ********************************************************************/
+
+/*! \brief
+ * Initializes the evaluation group for a \ref SEL_ROOT element.
+ *
+ * \param     root Root element to initialize.
+ * \param[in] gall Group of all atoms.
+ *
+ * Checks whether it is necessary to evaluate anything through the root
+ * element, and either clears the evaluation function or initializes the
+ * evaluation group.
+ */
+static void
+init_root_item(t_selelem *root, gmx_ana_index_t *gall)
+{
+    t_selelem   *expr;
+    char        *name;
+
+    expr = root->child;
+    /* Subexpressions with non-static evaluation group should not be
+     * evaluated by the root, and neither should be single-reference
+     * subexpressions that don't evaluate for all atoms. */
+    if (expr->type == SEL_SUBEXPR
+        && (!(root->child->cdata->flags & SEL_CDATA_STATICEVAL)
+            || ((root->child->cdata->flags & SEL_CDATA_SIMPLESUBEXPR)
+                && !(root->child->cdata->flags & SEL_CDATA_FULLEVAL))))
+    {
+        root->evaluate = NULL;
+        if (root->cdata)
+        {
+            root->cdata->evaluate = NULL;
+        }
+    }
+
+    /* Set the evaluation group */
+    name = root->u.cgrp.name;
+    if (root->evaluate)
+    {
+        /* Non-atom-valued non-group expressions don't care about the group, so
+         * don't allocate any memory for it. */
+        if ((expr->flags & SEL_VARNUMVAL)
+            || ((expr->flags & SEL_SINGLEVAL) && expr->v.type != GROUP_VALUE))
+        {
+            gmx_ana_index_set(&root->u.cgrp, -1, NULL, NULL, 0);
+        }
+        else if (expr->cdata->gmax->isize == gall->isize)
+        {
+            /* Save some memory by only referring to the global group. */
+            gmx_ana_index_set(&root->u.cgrp, gall->isize, gall->index, NULL, 0);
+        }
+        else
+        {
+            gmx_ana_index_copy(&root->u.cgrp, expr->cdata->gmax, TRUE);
+        }
+        /* For selections, store the maximum group for
+         * gmx_ana_selcollection_evaluate_fin() as the value of the root
+         * element (unused otherwise). */
+        if (expr->type != SEL_SUBEXPR && expr->v.u.p->g)
+        {
+            t_selelem *child = expr;
+
+            /* TODO: This code is copied from parsetree.c; it would be better
+             * to have this hardcoded only in one place. */
+            while (child->type == SEL_MODIFIER)
+            {
+                child = child->child;
+                if (child->type == SEL_SUBEXPRREF)
+                {
+                    child = child->child->child;
+                }
+            }
+            if (child->type == SEL_SUBEXPRREF)
+            {
+                child = child->child->child;
+            }
+            if (child->child->flags & SEL_DYNAMIC)
+            {
+                _gmx_selelem_set_vtype(root, GROUP_VALUE);
+                root->flags  |= (SEL_ALLOCVAL | SEL_ALLOCDATA);
+                _gmx_selvalue_reserve(&root->v, 1);
+                gmx_ana_index_copy(root->v.u.g, expr->v.u.p->g, TRUE);
+            }
+        }
+    }
+    else
+    {
+        gmx_ana_index_clear(&root->u.cgrp);
+    }
+    root->u.cgrp.name = name;
+}
+
+
+/********************************************************************
+ * FINAL SUBEXPRESSION OPTIMIZATION
+ ********************************************************************/
+
+/*! \brief
+ * Optimizes subexpression evaluation.
+ *
+ * \param     sel Root of the selection subtree to process.
+ *
+ * Optimizes away some unnecessary evaluation of subexpressions that are only
+ * referenced once.
+ */
+static void
+postprocess_item_subexpressions(t_selelem *sel)
+{
+    /* Process children. */
+    if (sel->type != SEL_SUBEXPRREF)
+    {
+        t_selelem *child;
+
+        child = sel->child;
+        while (child)
+        {
+            postprocess_item_subexpressions(child);
+            child = child->next;
+        }
+    }
+
+    /* Replace the evaluation function of statically evaluated subexpressions
+     * for which the static group was not known in advance. */
+    if (sel->type == SEL_SUBEXPR && sel->refcount > 2
+        && (sel->cdata->flags & SEL_CDATA_STATICEVAL)
+        && !(sel->cdata->flags & SEL_CDATA_FULLEVAL))
+    {
+        char *name;
+
+        /* We need to free memory allocated for the group, because it is no
+         * longer needed (and would be lost on next call to the evaluation
+         * function). But we need to preserve the name. */
+        name = sel->u.cgrp.name;
+        gmx_ana_index_deinit(&sel->u.cgrp);
+        sel->u.cgrp.name = name;
+
+        sel->evaluate = &_gmx_sel_evaluate_subexpr_staticeval;
+        if (sel->cdata)
+        {
+            sel->cdata->evaluate = sel->evaluate;
+        }
+        _gmx_selelem_free_values(sel->child);
+        sel->child->mempool = NULL;
+        _gmx_selvalue_setstore(&sel->child->v, sel->v.u.ptr);
+        sel->child->flags &= ~(SEL_ALLOCVAL | SEL_ALLOCDATA);
+    }
+
+    /* Adjust memory allocation flags for subexpressions that are used only
+     * once.  This is not strictly necessary, but we do it to have the memory
+     * managed consistently for all types of subexpressions. */
+    if (sel->type == SEL_SUBEXPRREF
+        && (sel->cdata->flags & SEL_CDATA_SIMPLESUBEXPR))
+    {
+        if (sel->child->child->flags & SEL_ALLOCVAL)
+        {
+            sel->flags |= SEL_ALLOCVAL;
+            sel->flags |= (sel->child->child->flags & SEL_ALLOCDATA);
+            sel->v.nalloc = sel->child->child->v.nalloc;
+            sel->child->child->flags &= ~(SEL_ALLOCVAL | SEL_ALLOCDATA);
+            sel->child->child->v.nalloc = -1;
+        }
+    }
+
+    /* Do the same for subexpressions that are evaluated at once for all atoms. */
+    if (sel->type == SEL_SUBEXPR
+        && !(sel->cdata->flags & SEL_CDATA_SIMPLESUBEXPR)
+        && (sel->cdata->flags & SEL_CDATA_FULLEVAL))
+    {
+        sel->flags |= SEL_ALLOCVAL;
+        sel->flags |= (sel->child->flags & SEL_ALLOCDATA);
+        sel->v.nalloc = sel->child->v.nalloc;
+        sel->child->flags &= ~(SEL_ALLOCVAL | SEL_ALLOCDATA);
+        sel->child->v.nalloc = -1;
+    }
+}
+
+
+/********************************************************************
+ * COM CALCULATION INITIALIZATION
+ ********************************************************************/
+
+/*! \brief
+ * Initializes COM/COG calculation for method expressions that require it.
+ *
+ * \param     sel    Selection subtree to process.
+ * \param[in,out] pcc   Position calculation collection to use.
+ * \param[in] type   Default position calculation type.
+ * \param[in] flags  Flags for default position calculation.
+ * \returns   0 on success, a non-zero error code on error.
+ *
+ * Searches recursively through the selection tree for dynamic
+ * \ref SEL_EXPRESSION elements that define the \c gmx_ana_selmethod_t::pupdate
+ * function.
+ * For each such element found, position calculation is initialized
+ * for the maximal evaluation group.
+ * The type of the calculation is determined by \p type and \p flags.
+ * No calculation is initialized if \p type equals \ref POS_ATOM and
+ * the method also defines the \c gmx_ana_selmethod_t::update method.
+ */
+static int
+init_item_comg(t_selelem *sel, gmx_ana_poscalc_coll_t *pcc,
+               e_poscalc_t type, int flags)
+{
+    t_selelem *child;
+    int        rc;
+
+    /* Initialize COM calculation for dynamic selections now that we know the maximal evaluation group */
+    if (sel->type == SEL_EXPRESSION && sel->u.expr.method
+        && sel->u.expr.method->pupdate)
+    {
+        if (!sel->u.expr.method->update || type != POS_ATOM)
+        {
+            /* Create a default calculation if one does not yet exist */
+            int cflags;
+            cflags = 0;
+            if (!(sel->cdata->flags & SEL_CDATA_STATICEVAL))
+            {
+                cflags |= POS_DYNAMIC;
+            }
+            if (!sel->u.expr.pc)
+            {
+                cflags |= flags;
+                rc = gmx_ana_poscalc_create(&sel->u.expr.pc, pcc, type, cflags);
+                if (rc != 0)
+                {
+                    return rc;
+                }
+            }
+            else
+            {
+                gmx_ana_poscalc_set_flags(sel->u.expr.pc, cflags);
+            }
+            gmx_ana_poscalc_set_maxindex(sel->u.expr.pc, sel->cdata->gmax);
+            snew(sel->u.expr.pos, 1);
+            gmx_ana_poscalc_init_pos(sel->u.expr.pc, sel->u.expr.pos);
+        }
+    }
+
+    /* Call recursively for all children unless the children have already been processed */
+    if (sel->type != SEL_SUBEXPRREF)
+    {
+        child = sel->child;
+        while (child)
+        {
+            rc = init_item_comg(child, pcc, type, flags);
+            if (rc != 0)
+            {
+                return rc;
+            }
+            child = child->next;
+        }
+    }
+    return 0;
+}
+
+
+/********************************************************************
+ * COMPILER DATA FREEING
+ ********************************************************************/
+
+/*! \brief
+ * Frees the allocated compiler data recursively.
+ *
+ * \param     sel Root of the selection subtree to process.
+ *
+ * Frees the data allocated for the compilation process.
+ */
+static void
+free_item_compilerdata(t_selelem *sel)
+{
+    t_selelem *child;
+
+    /* Free compilation data */
+    _gmx_selelem_free_compiler_data(sel);
+
+    /* Call recursively for all children unless the children have already been processed */
+    if (sel->type != SEL_SUBEXPRREF)
+    {
+        child = sel->child;
+        while (child)
+        {
+            free_item_compilerdata(child);
+            child = child->next;
+        }
+    }
+}
+
+
+/********************************************************************
+ * MASS AND CHARGE CALCULATION
+ ********************************************************************/
+
+/*! \brief
+ * Initializes total masses and charges for selections.
+ *
+ * \param[in,out] selections Array of selections to update.
+ * \param[in]     top   Topology information.
+ */
+static void
+calculate_mass_charge(std::vector<gmx::Selection *> *selections,
+                      t_topology *top)
+{
+    int   b, i;
+
+    for (size_t g = 0; g < selections->size(); ++g)
+    {
+        gmx_ana_selection_t *sel = &selections->at(g)->_sel;
+        bool bMaskOnly = selections->at(g)->hasFlag(gmx::efDynamicMask);
+
+        sel->g = sel->p.g;
+        snew(sel->orgm, sel->p.nr);
+        snew(sel->orgq, sel->p.nr);
+        for (b = 0; b < sel->p.nr; ++b)
+        {
+            sel->orgq[b] = 0;
+            if (top)
+            {
+                sel->orgm[b] = 0;
+                for (i = sel->p.m.mapb.index[b]; i < sel->p.m.mapb.index[b+1]; ++i)
+                {
+                    sel->orgm[b] += top->atoms.atom[sel->g->index[i]].m;
+                    sel->orgq[b] += top->atoms.atom[sel->g->index[i]].q;
+                }
+            }
+            else
+            {
+                sel->orgm[b] = 1;
+            }
+        }
+        if (sel->bDynamic && !bMaskOnly)
+        {
+            snew(sel->m, sel->p.nr);
+            snew(sel->q, sel->p.nr);
+            for (b = 0; b < sel->p.nr; ++b)
+            {
+                sel->m[b] = sel->orgm[b];
+                sel->q[b] = sel->orgq[b];
+            }
+        }
+        else
+        {
+            sel->m = sel->orgm;
+            sel->q = sel->orgq;
+        }
+    }
+}
+
+
+/********************************************************************
+ * MAIN COMPILATION FUNCTION
+ ********************************************************************/
+
+/*!
+ * \param[in,out] coll Selection collection to be compiled.
+ * \returns       0 on successful compilation, a non-zero error code on error.
+ *
+ * Before compilation, the selection collection should have been initialized
+ * with gmx_ana_selcollection_parse_*().
+ * The compiled selection collection can be passed to
+ * gmx_ana_selcollection_evaluate() to evaluate the selection for a frame.
+ * If an error occurs, \p sc is cleared.
+ *
+ * The covered fraction information in \p sc is initialized to
+ * \ref CFRAC_NONE.
+ */
+int
+gmx_ana_selcollection_compile(gmx::SelectionCollection *coll)
+{
+    gmx_ana_selcollection_t *sc = &coll->_impl->_sc;
+    gmx_sel_evaluate_t  evaldata;
+    t_selelem   *item;
+    e_poscalc_t  post;
+    size_t       i;
+    int          flags;
+    int          rc;
+    bool         bDebug = (coll->_impl->_debugLevel >= 2
+                           && coll->_impl->_debugLevel != 3);
+
+    rc = _gmx_sel_mempool_create(&sc->mempool);
+    if (rc != 0)
+    {
+        return rc;
+    }
+    _gmx_sel_evaluate_init(&evaldata, sc->mempool, &sc->gall,
+                           sc->top, NULL, NULL);
+
+    /* Clear the symbol table because it is not possible to parse anything
+     * after compilation, and variable references in the symbol table can
+     * also mess up the compilation and/or become invalid.
+     */
+    coll->_impl->clearSymbolTable();
+
+    /* Loop through selections and initialize position keyword defaults if no
+     * other value has been provided.
+     */
+    for (i = 0; i < sc->sel.size(); ++i)
+    {
+        gmx::Selection *sel = sc->sel[i];
+        init_pos_keyword_defaults(sel->_sel.selelem,
+                                  coll->_impl->_spost.c_str(),
+                                  coll->_impl->_rpost.c_str(),
+                                  sel);
+    }
+
+    /* Remove any unused variables. */
+    sc->root = remove_unused_subexpressions(sc->root);
+    /* Extract subexpressions into separate roots */
+    sc->root = extract_subexpressions(sc->root);
+
+    /* Initialize the evaluation callbacks and process the tree structure
+     * to conform to the expectations of the callback functions. */
+    /* Also, initialize and allocate the compiler data structure */
+    item = sc->root;
+    while (item)
+    {
+        /* Process gmx_boolean and arithmetic expressions. */
+        optimize_gmx_boolean_expressions(item);
+        reorder_gmx_boolean_static_children(item);
+        if (!optimize_arithmetic_expressions(item))
+        {
+            /* FIXME: Clean up the collection */
+            return -1;
+        }
+        /* Initialize evaluation function. */
+        if (!init_item_evalfunc(item))
+        {
+            /* FIXME: Clean up the collection */
+            return -1;
+        }
+        setup_memory_pooling(item, sc->mempool);
+        /* Initialize the compiler data */
+        init_item_compilerdata(item);
+        init_item_staticeval(item);
+        item = item->next;
+    }
+    /* Initialize subexpression flags and evaluation output.
+     * Requires compiler flags for the full tree. */
+    item = sc->root;
+    while (item)
+    {
+        init_item_subexpr_flags(item);
+        init_item_evaloutput(item);
+        item = item->next;
+    }
+    /* Initialize minimum/maximum index groups.
+     * Requires evaluation output for the full tree. */
+    item = sc->root;
+    while (item)
+    {
+        init_item_minmax_groups(item);
+        item = item->next;
+    }
+    /* Initialize the evaluation index groups */
+    initialize_evalgrps(sc);
+
+    if (bDebug)
+    {
+        fprintf(stderr, "\nTree after initial compiler processing:\n");
+        coll->printTree(stderr, false);
+    }
+
+    /* Evaluate all static parts of the selection and analyze the tree
+     * to allocate enough memory to store the value of each dynamic subtree. */
+    item = sc->root;
+    while (item)
+    {
+        if (item->child->cdata->flags & SEL_CDATA_COMMONSUBEXPR)
+        {
+            mark_subexpr_dynamic(item->child, TRUE);
+        }
+        set_evaluation_function(item, &analyze_static);
+        rc = item->evaluate(&evaldata, item, NULL);
+        if (rc != 0)
+        {
+            /* FIXME: Clean up the collection */
+            return rc;
+        }
+        item = item->next;
+    }
+
+    /* At this point, static subexpressions no longer have references to them,
+     * so they can be removed. */
+    sc->root = remove_unused_subexpressions(sc->root);
+
+    if (bDebug)
+    {
+        fprintf(stderr, "\nTree after first analysis pass:\n");
+        coll->printTree(stderr, false);
+    }
+
+    /* Do a second pass to evaluate static parts of common subexpressions */
+    item = sc->root;
+    while (item)
+    {
+        if (item->child->cdata->flags & SEL_CDATA_COMMONSUBEXPR)
+        {
+            gmx_bool bMinMax = item->child->cdata->flags & SEL_CDATA_MINMAXALLOC;
+
+            mark_subexpr_dynamic(item->child, FALSE);
+            item->child->u.cgrp.isize = 0;
+            /* We won't clear item->child->v.u.g here, because it may
+             * be static, and hence actually point to item->child->cdata->gmax,
+             * which is used below. We could also check whether this is the
+             * case and only clear the group otherwise, but because the value
+             * is actually overwritten immediately in the evaluate call, we
+             * won't, because similar problems may arise if gmax handling ever
+             * changes and the check were not updated.
+             * For the same reason, we clear the min/max flag so that the
+             * evaluation group doesn't get messed up. */
+            set_evaluation_function(item, &analyze_static);
+            item->child->cdata->flags &= ~SEL_CDATA_MINMAXALLOC;
+            rc = item->evaluate(&evaldata, item->child, item->child->cdata->gmax);
+            if (bMinMax)
+            {
+                item->child->cdata->flags |= SEL_CDATA_MINMAXALLOC;
+            }
+            if (rc != 0)
+            {
+                /* FIXME: Clean up the collection */
+                return rc;
+            }
+        }
+        item = item->next;
+    }
+
+    /* We need a yet another pass of subexpression removal to remove static
+     * subexpressions referred to by common dynamic subexpressions. */
+    sc->root = remove_unused_subexpressions(sc->root);
+
+    if (bDebug)
+    {
+        fprintf(stderr, "\nTree after second analysis pass:\n");
+        coll->printTree(stderr, false);
+    }
+
+    /* Initialize evaluation groups, position calculations for methods, perform
+     * some final optimization, and free the memory allocated for the
+     * compilation. */
+    /* By default, use whole residues/molecules. */
+    flags = POS_COMPLWHOLE;
+    rc = gmx_ana_poscalc_type_from_enum(coll->_impl->_rpost.c_str(), &post, &flags);
+    if (rc != 0)
+    {
+        gmx_bug("invalid default reference position type");
+        /* FIXME: Clean up the collection */
+        return rc;
+    }
+    item = sc->root;
+    while (item)
+    {
+        init_root_item(item, &sc->gall);
+        postprocess_item_subexpressions(item);
+        rc = init_item_comg(item, sc->pcc, post, flags);
+        if (rc != 0)
+        {
+            /* FIXME: Clean up the collection */
+            return rc;
+        }
+        free_item_compilerdata(item);
+        item = item->next;
+    }
+
+    /* Allocate memory for the evaluation memory pool. */
+    rc = _gmx_sel_mempool_reserve(sc->mempool, 0);
+    if (rc != 0)
+    {
+        return rc;
+    }
+
+    /* Finish up by calculating total masses and charges. */
+    calculate_mass_charge(&sc->sel, sc->top);
+
+    return 0;
+}
diff --git a/src/gromacs/selection/evaluate.cpp b/src/gromacs/selection/evaluate.cpp
new file mode 100644 (file)
index 0000000..d54f92d
--- /dev/null
@@ -0,0 +1,1143 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * Implements functions in evaluate.h.
+ *
+ * \todo
+ * One of the major bottlenecks for selection performance is that all the
+ * evaluation is carried out for atoms.
+ * There are several cases when the evaluation could be done for residues
+ * or molecules instead, including keywords that select by residue and
+ * cases where residue centers are used as reference positions.
+ * Implementing this would require a mechanism for recognizing whether
+ * something can be evaluated by residue/molecule instead by atom, and
+ * converting selections by residue/molecule into selections by atom
+ * when necessary.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_selection
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#include <maths.h>
+#include <smalloc.h>
+#include <vec.h>
+
+#include "gromacs/selection/indexutil.h"
+#include "gromacs/selection/poscalc.h"
+#include "gromacs/selection/selection.h"
+#include "gromacs/selection/selmethod.h"
+
+#include "evaluate.h"
+#include "mempool.h"
+#include "selectioncollection-impl.h"
+#include "selelem.h"
+
+/*!
+ * \param[in] fp       File handle to receive the output.
+ * \param[in] evalfunc Function pointer to print.
+ */
+void
+_gmx_sel_print_evalfunc_name(FILE *fp, sel_evalfunc evalfunc)
+{
+    if (!evalfunc)
+        fprintf(fp, "none");
+    else if (evalfunc == &_gmx_sel_evaluate_root)
+        fprintf(fp, "root");
+    else if (evalfunc == &_gmx_sel_evaluate_static)
+        fprintf(fp, "static");
+    else if (evalfunc == &_gmx_sel_evaluate_subexpr_simple)
+        fprintf(fp, "subexpr_simple");
+    else if (evalfunc == &_gmx_sel_evaluate_subexpr_staticeval)
+        fprintf(fp, "subexpr_staticeval");
+    else if (evalfunc == &_gmx_sel_evaluate_subexpr)
+        fprintf(fp, "subexpr");
+    else if (evalfunc == &_gmx_sel_evaluate_subexprref_simple)
+        fprintf(fp, "ref_simple");
+    else if (evalfunc == &_gmx_sel_evaluate_subexprref)
+        fprintf(fp, "ref");
+    else if (evalfunc == &_gmx_sel_evaluate_method)
+        fprintf(fp, "method");
+    else if (evalfunc == &_gmx_sel_evaluate_modifier)
+        fprintf(fp, "mod");
+    else if (evalfunc == &_gmx_sel_evaluate_not)
+        fprintf(fp, "not");
+    else if (evalfunc == &_gmx_sel_evaluate_and)
+        fprintf(fp, "and");
+    else if (evalfunc == &_gmx_sel_evaluate_or)
+        fprintf(fp, "or");
+    else if (evalfunc == &_gmx_sel_evaluate_arithmetic)
+        fprintf(fp, "arithmetic");
+    else
+        fprintf(fp, "%p", (void*)(evalfunc));
+}
+
+/*!
+ * \param[out] data Evaluation data structure to initialize.
+ * \param[in]  mp   Memory pool for intermediate evaluation values.
+ * \param[in]  gall Index group with all the atoms.
+ * \param[in]  top  Topology structure for evaluation.
+ * \param[in]  fr   New frame for evaluation.
+ * \param[in]  pbc  New PBC information for evaluation.
+ */
+void
+_gmx_sel_evaluate_init(gmx_sel_evaluate_t *data,
+                       gmx_sel_mempool_t *mp, gmx_ana_index_t *gall,
+                       t_topology *top, t_trxframe *fr, t_pbc *pbc)
+{
+    data->mp   = mp;
+    data->gall = gall;
+    data->top  = top;
+    data->fr   = fr;
+    data->pbc  = pbc;
+}
+
+/*! \brief
+ * Recursively initializes the flags for evaluation.
+ *
+ * \param[in,out] sel Selection element to clear.
+ *
+ * The \ref SEL_INITFRAME flag is set for \ref SEL_EXPRESSION elements whose
+ * method defines the \p init_frame callback (see sel_framefunc()), and
+ * cleared for other elements.
+ *
+ * The \ref SEL_EVALFRAME flag is cleared for all elements.
+ */
+static void
+init_frame_eval(t_selelem *sel)
+{
+    while (sel)
+    {
+        sel->flags &= ~(SEL_INITFRAME | SEL_EVALFRAME);
+        if (sel->type == SEL_EXPRESSION)
+        {
+            if (sel->u.expr.method && sel->u.expr.method->init_frame)
+            {
+                sel->flags |= SEL_INITFRAME;
+            }
+        }
+        if (sel->child && sel->type != SEL_SUBEXPRREF)
+        {
+            init_frame_eval(sel->child);
+        }
+        sel = sel->next;
+    }
+}
+
+/*!
+ * \param[in,out] sc  The selection collection to evaluate.
+ * \param[in] fr  Frame for which the evaluation should be carried out.
+ * \param[in] pbc PBC data, or NULL if no PBC should be used.
+ * \returns   0 on successful evaluation, a non-zero error code on error.
+ *
+ * This functions sets the global variables for topology, frame and PBC,
+ * clears some information in the selection to initialize the evaluation
+ * for a new frame, and evaluates \p sel and all the selections pointed by
+ * the \p next pointers of \p sel.
+ *
+ * This is the only function that user code should call if they want to
+ * evaluate a selection for a new frame.
+ */
+int
+gmx_ana_selcollection_evaluate(gmx_ana_selcollection_t *sc,
+                               t_trxframe *fr, t_pbc *pbc)
+{
+    gmx_sel_evaluate_t  data;
+    t_selelem          *sel;
+    int                 rc;
+
+    _gmx_sel_evaluate_init(&data, sc->mempool, &sc->gall, sc->top, fr, pbc);
+    init_frame_eval(sc->root);
+    sel = sc->root;
+    while (sel)
+    {
+        /* Clear the evaluation group of subexpressions */
+        if (sel->child && sel->child->type == SEL_SUBEXPR)
+        {
+            sel->child->u.cgrp.isize = 0;
+            /* Not strictly necessary, because the value will be overwritten
+             * during first evaluation of the subexpression anyways, but we
+             * clear the group for clarity. Note that this is _not_ done during
+             * compilation because of some additional complexities involved
+             * (see compiler.c), so it should not be relied upon in
+             * _gmx_sel_evaluate_subexpr(). */
+            if (sel->child->v.type == GROUP_VALUE)
+            {
+                sel->child->v.u.g->isize = 0;
+            }
+        }
+        if (sel->evaluate)
+        {
+            rc = sel->evaluate(&data, sel, NULL);
+            if (rc != 0)
+            {
+                return rc;
+            }
+        }
+        sel = sel->next;
+    }
+    /* Update selection information */
+    for (size_t g = 0; g < sc->sel.size(); ++g)
+    {
+        gmx_ana_selection_t *sel = &sc->sel[g]->_sel;
+
+        if (sel->m != sel->orgm)
+        {
+            for (int i = 0; i < sel->p.nr; ++i)
+            {
+                sel->m[i] = sel->orgm[sel->p.m.refid[i]];
+                sel->q[i] = sel->orgq[sel->p.m.refid[i]];
+            }
+        }
+        if (sel->bCFracDyn)
+        {
+            sel->cfrac = _gmx_selelem_estimate_coverfrac(sel->selelem);
+            sel->avecfrac += sel->cfrac;
+        }
+    }
+    return 0;
+}
+
+/*!
+ * \param[in,out] sc  The selection collection to evaluate.
+ * \param[in]     nframes Total number of frames.
+ * \returns       0 on successful evaluation, a non-zero error code on error.
+ */
+int
+gmx_ana_selcollection_evaluate_fin(gmx_ana_selcollection_t *sc, int nframes)
+{
+    t_selelem          *sel;
+
+    for (size_t g = 0; g < sc->sel.size(); ++g)
+    {
+        gmx_ana_selection_t *sel = &sc->sel[g]->_sel;
+        bool bMaskOnly = sc->sel[g]->hasFlag(gmx::efDynamicMask);
+        t_selelem *elem = sel->selelem;
+        if (sel->bDynamic)
+        {
+            gmx_ana_index_copy(sel->g, elem->v.u.g, FALSE);
+            sel->g->name = NULL;
+            gmx_ana_indexmap_update(&sel->p.m, sel->g, bMaskOnly);
+            sel->p.nr = sel->p.m.nr;
+        }
+
+        if (sel->bCFracDyn)
+        {
+            sel->avecfrac /= nframes;
+        }
+    }
+    return 0;
+}
+
+/*!
+ * \param[in] data Data for the current frame.
+ * \param[in] sel  Selection element being evaluated.
+ * \param[in] g    Group for which \p sel should be evaluated.
+ * \returns   0 on success, a non-zero error code on error.
+ *
+ * Evaluates each child of \p sel in \p g.
+ */
+int
+_gmx_sel_evaluate_children(gmx_sel_evaluate_t *data, t_selelem *sel,
+                           gmx_ana_index_t *g)
+{
+    t_selelem  *child;
+    int         rc;
+
+    child = sel->child;
+    while (child)
+    {
+        if (child->evaluate)
+        {
+            rc = child->evaluate(data, child, g);
+            if (rc != 0)
+            {
+                return rc;
+            }
+        }
+        child = child->next;
+    }
+    return 0;
+}
+
+/*!
+ * \param[in] data Data for the current frame.
+ * \param[in] sel Selection element being evaluated.
+ * \param[in] g   Group for which \p sel should be evaluated
+ *   (not used, can be NULL).
+ * \returns   0 on success, a non-zero error code on error.
+ *
+ * Evaluates the first child element in the group defined by \p sel->u.cgrp.
+ * If \p sel->u.cgrp is empty, nothing is done.
+ * The value of \p sel is not touched (root elements do not evaluate to
+ * values).
+ *
+ * This function can be used as \c t_selelem::evaluate for \ref SEL_ROOT
+ * elements.
+ */
+int
+_gmx_sel_evaluate_root(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g)
+{
+    int        rc;
+
+    if (sel->u.cgrp.isize == 0 || !sel->child->evaluate)
+    {
+        return 0;
+    }
+
+    rc = sel->child->evaluate(data, sel->child,
+                              sel->u.cgrp.isize < 0 ? NULL : &sel->u.cgrp);
+
+    return rc;
+}
+
+/*!
+ * \param[in] data Data for the current frame.
+ * \param[in] sel Selection element being evaluated.
+ * \param[in] g   Group for which \p sel should be evaluated.
+ * \returns   0 for success.
+ *
+ * Sets the value of \p sel to the intersection of \p g and \p sel->u.cgrp.
+ *
+ * This function can be used as \c t_selelem::evaluate for \ref SEL_CONST
+ * elements with value type \ref GROUP_VALUE.
+ */
+int
+_gmx_sel_evaluate_static(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g)
+{
+    gmx_ana_index_intersection(sel->v.u.g, &sel->u.cgrp, g);
+    return 0;
+}
+
+
+/*********************************************************************
+ * SUBEXPRESSION EVALUATION
+ *********************************************************************/
+
+/*!
+ * \param[in] data Data for the current frame.
+ * \param[in] sel  Selection element being evaluated.
+ * \param[in] g    Group for which \p sel should be evaluated.
+ * \returns   0 on success, a non-zero error code on error.
+ *
+ * Evaluates the child element (there should be exactly one) in \p g.
+ * The compiler has taken care that the child actually stores the evaluated
+ * value in the value pointer of this element.
+ *
+ * This function is used as \c t_selelem::evaluate for \ref SEL_SUBEXPR
+ * elements that are used only once, and hence do not need full subexpression
+ * handling.
+ */
+int
+_gmx_sel_evaluate_subexpr_simple(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g)
+{
+    int        rc;
+
+    if (sel->child->evaluate)
+    {
+        rc = sel->child->evaluate(data, sel->child, g);
+        if (rc != 0)
+        {
+            return rc;
+        }
+    }
+    sel->v.nr = sel->child->v.nr;
+    return 0;
+}
+
+/*!
+ * \param[in] data Data for the current frame.
+ * \param[in] sel  Selection element being evaluated.
+ * \param[in] g    Group for which \p sel should be evaluated.
+ * \returns   0 on success, a non-zero error code on error.
+ *
+ * If this is the first call for this frame, evaluates the child element
+ * there should be exactly one in \p g.
+ * The compiler has taken care that the child actually stores the evaluated
+ * value in the value pointer of this element.
+ * Assumes that \p g is persistent for the duration of the whole evaluation.
+ *
+ * This function is used as \c t_selelem::evaluate for \ref SEL_SUBEXPR
+ * elements that have a static evaluation group, and hence do not need full
+ * subexpression handling.
+ */
+int
+_gmx_sel_evaluate_subexpr_staticeval(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g)
+{
+    if (sel->u.cgrp.isize == 0)
+    {
+        int  rc;
+
+        rc = sel->child->evaluate(data, sel->child, g);
+        if (rc != 0)
+        {
+            return rc;
+        }
+        sel->v.nr = sel->child->v.nr;
+        gmx_ana_index_set(&sel->u.cgrp, g->isize, g->index, sel->u.cgrp.name, 0);
+    }
+    return 0;
+}
+
+/*!
+ * \param[in]  data  Data for the current frame.
+ * \param[in]  sel   Selection element being evaluated.
+ * \param[in]  g     Group for which \p sel should be evaluated.
+ * \returns    0 on success, a non-zero error code on error.
+ *
+ * Finds the part of \p g for which the subexpression
+ * has not yet been evaluated by comparing \p g to \p sel->u.cgrp.
+ * If the part is not empty, the child expression is evaluated for this
+ * part, and the results merged to the old values of the child.
+ * The value of \p sel itself is undefined after the call.
+ *
+ * \todo
+ * The call to gmx_ana_index_difference() can take quite a lot of unnecessary
+ * time if the subexpression is evaluated either several times for the same
+ * group or for completely distinct groups.
+ * However, in the majority of cases, these situations occur when
+ * _gmx_sel_evaluate_subexpr_staticeval() can be used, so this should not be a
+ * major problem.
+ */
+int
+_gmx_sel_evaluate_subexpr(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g)
+{
+    gmx_ana_index_t  gmiss;
+    int              rc;
+
+    if (sel->u.cgrp.isize == 0)
+    {
+        char *name;
+        void *old_ptr    = sel->child->v.u.ptr;
+        int   old_nalloc = sel->child->v.nalloc;
+        _gmx_selvalue_setstore(&sel->child->v, sel->v.u.ptr);
+        rc = sel->child->evaluate(data, sel->child, g);
+        _gmx_selvalue_setstore_alloc(&sel->child->v, old_ptr, old_nalloc);
+        if (rc != 0)
+        {
+            return rc;
+        }
+        /* We need to keep the name for the cgrp across the copy to avoid
+         * problems if g has a name set. */
+        name = sel->u.cgrp.name;
+        gmx_ana_index_copy(&sel->u.cgrp, g, FALSE);
+        sel->u.cgrp.name = name;
+        gmiss.isize = 0;
+    }
+    else
+    {
+        /* We allocate some extra memory here to avoid some computation. */
+        rc = _gmx_sel_mempool_alloc_group(data->mp, &gmiss, g->isize);
+        if (rc != 0)
+        {
+            return rc;
+        }
+        gmx_ana_index_difference(&gmiss, g, &sel->u.cgrp);
+        if (gmiss.isize == 0)
+        {
+            _gmx_sel_mempool_free_group(data->mp, &gmiss);
+        }
+    }
+    if (gmiss.isize > 0)
+    {
+        rc = _gmx_selelem_mempool_reserve(sel->child, gmiss.isize);
+        if (rc != 0)
+        {
+            return rc;
+        }
+        /* Evaluate the missing values for the child */
+        rc = sel->child->evaluate(data, sel->child, &gmiss);
+        if (rc != 0)
+        {
+            return rc;
+        }
+        /* Merge the missing values to the existing ones. */
+        if (sel->v.type == GROUP_VALUE)
+        {
+            gmx_ana_index_merge(sel->v.u.g, sel->child->v.u.g, sel->v.u.g);
+        }
+        else
+        {
+            int  i, j, k;
+
+            i = sel->u.cgrp.isize - 1;
+            j = gmiss.isize - 1;
+            /* TODO: This switch is kind of ugly, but it may be difficult to
+             * do this portably without C++ templates. */
+            switch (sel->v.type)
+            {
+                case INT_VALUE:
+                    for (k = sel->u.cgrp.isize + gmiss.isize - 1; k >= 0; k--)
+                    {
+                        if (i < 0 || (j >= 0 && sel->u.cgrp.index[i] < gmiss.index[j]))
+                        {
+                            sel->v.u.i[k] = sel->v.u.i[j--];
+                        }
+                        else
+                        {
+                            sel->v.u.i[k] = sel->child->v.u.i[i--];
+                        }
+                    }
+                    break;
+
+                case REAL_VALUE:
+                    for (k = sel->u.cgrp.isize + gmiss.isize - 1; k >= 0; k--)
+                    {
+                        if (i < 0 || (j >= 0 && sel->u.cgrp.index[i] < gmiss.index[j]))
+                        {
+                            sel->v.u.r[k] = sel->v.u.r[j--];
+                        }
+                        else
+                        {
+                            sel->v.u.r[k] = sel->child->v.u.r[i--];
+                        }
+                    }
+                    break;
+
+                case STR_VALUE:
+                    for (k = sel->u.cgrp.isize + gmiss.isize - 1; k >= 0; k--)
+                    {
+                        if (i < 0 || (j >= 0 && sel->u.cgrp.index[i] < gmiss.index[j]))
+                        {
+                            sel->v.u.s[k] = sel->v.u.s[j--];
+                        }
+                        else
+                        {
+                            sel->v.u.s[k] = sel->child->v.u.s[i--];
+                        }
+                    }
+                    break;
+
+                case POS_VALUE:
+                    /* TODO: Implement this */
+                    gmx_impl("position subexpressions not implemented properly");
+                    return -1;
+
+                case NO_VALUE:
+                case GROUP_VALUE:
+                    gmx_bug("internal error");
+                    return -1;
+            }
+        }
+        gmx_ana_index_merge(&sel->u.cgrp, &sel->u.cgrp, &gmiss);
+        _gmx_selelem_mempool_release(sel->child);
+        _gmx_sel_mempool_free_group(data->mp, &gmiss);
+    }
+    return 0;
+}
+
+/*!
+ * \param[in] data Data for the current frame.
+ * \param[in] sel Selection element being evaluated.
+ * \param[in] g   Group for which \p sel should be evaluated.
+ * \returns   0 for success.
+ *
+ * Sets the value pointers of the child and its child to point to the same
+ * memory as the value pointer of this element to avoid copying, and then
+ * evaluates evaluates the child.
+ *
+ * This function is used as \c t_selelem:evaluate for \ref SEL_SUBEXPRREF
+ * elements for which the \ref SEL_SUBEXPR does not have other references.
+ */
+int
+_gmx_sel_evaluate_subexprref_simple(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g)
+{
+    if (g)
+    {
+        int rc;
+
+        _gmx_selvalue_setstore(&sel->child->v, sel->v.u.ptr);
+        _gmx_selvalue_setstore_alloc(&sel->child->child->v, sel->v.u.ptr,
+                                     sel->child->child->v.nalloc);
+        rc = sel->child->evaluate(data, sel->child, g);
+        if (rc != 0)
+        {
+            return rc;
+        }
+    }
+    sel->v.nr = sel->child->v.nr;
+    if (sel->u.param)
+    {
+        sel->u.param->val.nr = sel->v.nr;
+        if (sel->u.param->nvalptr)
+        {
+            *sel->u.param->nvalptr = sel->u.param->val.nr;
+        }
+    }
+    return 0;
+}
+
+/*!
+ * \param[in] data Data for the current frame.
+ * \param[in] sel Selection element being evaluated.
+ * \param[in] g   Group for which \p sel should be evaluated.
+ * \returns   0 on success, a non-zero error code on error.
+ *
+ * If the value type is \ref POS_VALUE, the value of the child is simply
+ * copied to set the value of \p sel (the child subexpression should
+ * already have been evaluated by its root).
+ * If the value type is something else, the child is evaluated for the
+ * group \p g, and the value of the child is then copied.
+ * There should be only one child element.
+ *
+ * This function is used as \c t_selelem::evaluate for \ref SEL_SUBEXPRREF
+ * elements.
+ */
+int
+_gmx_sel_evaluate_subexprref(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g)
+{
+    t_selelem *expr;
+    int        i, j;
+
+    if (g)
+    {
+        int rc;
+
+        rc = sel->child->evaluate(data, sel->child, g);
+        if (rc != 0)
+        {
+            return rc;
+        }
+    }
+    expr = sel->child;
+    switch (sel->v.type)
+    {
+        case INT_VALUE:
+            if (!g)
+            {
+                sel->v.nr = expr->v.nr;
+                memcpy(sel->v.u.i, expr->v.u.i, sel->v.nr*sizeof(*sel->v.u.i));
+            }
+            else
+            {
+                sel->v.nr = g->isize;
+                /* Extract the values corresponding to g */
+                for (i = j = 0; i < g->isize; ++i, ++j)
+                {
+                    while (sel->child->u.cgrp.index[j] < g->index[i])
+                    {
+                        ++j;
+                    }
+                    sel->v.u.i[i] = expr->v.u.i[j];
+                }
+            }
+            break;
+
+        case REAL_VALUE:
+            if (!g)
+            {
+                sel->v.nr = expr->v.nr;
+                memcpy(sel->v.u.r, expr->v.u.r, sel->v.nr*sizeof(*sel->v.u.r));
+            }
+            else
+            {
+                sel->v.nr = g->isize;
+                /* Extract the values corresponding to g */
+                for (i = j = 0; i < g->isize; ++i, ++j)
+                {
+                    while (sel->child->u.cgrp.index[j] < g->index[i])
+                    {
+                        ++j;
+                    }
+                    sel->v.u.r[i] = expr->v.u.r[j];
+                }
+            }
+            break;
+
+        case STR_VALUE:
+            if (!g)
+            {
+                sel->v.nr = expr->v.nr;
+                memcpy(sel->v.u.s, expr->v.u.s, sel->v.nr*sizeof(*sel->v.u.s));
+            }
+            else
+            {
+                sel->v.nr = g->isize;
+                /* Extract the values corresponding to g */
+                for (i = j = 0; i < g->isize; ++i, ++j)
+                {
+                    while (sel->child->u.cgrp.index[j] < g->index[i])
+                    {
+                        ++j;
+                    }
+                    sel->v.u.s[i] = expr->v.u.s[j];
+                }
+            }
+            break;
+
+        case POS_VALUE:
+            /* Currently, there is no need to do anything fancy here,
+             * but some future extensions may need a more flexible
+             * implementation. */
+            gmx_ana_pos_copy(sel->v.u.p, expr->v.u.p, FALSE);
+            break;
+
+        case GROUP_VALUE:
+            if (!g)
+            {
+                gmx_ana_index_copy(sel->v.u.g, expr->v.u.g, FALSE);
+            }
+            else
+            {
+                gmx_ana_index_intersection(sel->v.u.g, expr->v.u.g, g);
+            }
+            break;
+
+        default: /* should not be reached */
+            gmx_bug("invalid subexpression reference type");
+            return -1;
+    }
+    /* Store the number of values if needed */
+    if (sel->u.param)
+    {
+        sel->u.param->val.nr = sel->v.nr;
+        if (sel->u.param->nvalptr)
+        {
+            *sel->u.param->nvalptr = sel->u.param->val.nr;
+        }
+    }
+    return 0;
+}
+
+/********************************************************************
+ * METHOD EXPRESSION EVALUATION
+ ********************************************************************/
+
+/*!
+ * \param[in] data Data for the current frame.
+ * \param[in] sel Selection element being evaluated.
+ * \param[in] g   Group for which \p sel should be evaluated.
+ * \returns   0 on success, a non-zero error code on error.
+ *
+ * Evaluates each child of a \ref SEL_EXPRESSION element.
+ * The value of \p sel is not touched.
+ *
+ * This function is not used as \c t_selelem::evaluate,
+ * but is used internally.
+ */
+int
+_gmx_sel_evaluate_method_params(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g)
+{
+    t_selelem *child;
+    int        rc;
+
+    child = sel->child;
+    while (child)
+    {
+        if (child->evaluate && !(child->flags & SEL_EVALFRAME))
+        {
+            if (child->flags & SEL_ATOMVAL)
+            {
+                rc = child->evaluate(data, child, g);
+            }
+            else
+            {
+                rc = child->evaluate(data, child, NULL);
+                child->flags |= SEL_EVALFRAME;
+            }
+            if (rc != 0)
+            {
+                return rc;
+            }
+        }
+        child = child->next;
+    }
+    return 0;
+}
+
+/*!
+ * \param[in] data Data for the current frame.
+ * \param[in] sel Selection element being evaluated.
+ * \param[in] g   Group for which \p sel should be evaluated.
+ * \returns   0 on success, a non-zero error code on error.
+ *
+ * Evaluates all child selections (using _gmx_sel_evaluate_method_params())
+ * to evaluate any parameter values.
+ * If this is the first time this expression is evaluated for
+ * the frame, sel_framefunc() callback is called if one is provided.
+ * If a reference position calculation has been initialized for this element,
+ * the positions are also updated, and sel_updatefunc_pos() is used to
+ * evaluate the value. Otherwise, sel_updatefunc() is used.
+ *
+ * This function is used as \c t_selelem::evaluate for \ref SEL_EXPRESSION
+ * elements.
+ */
+int
+_gmx_sel_evaluate_method(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g)
+{
+    int rc;
+
+    rc = _gmx_sel_evaluate_method_params(data, sel, g);
+    if (rc != 0)
+    {
+        return rc;
+    }
+    if (sel->flags & SEL_INITFRAME)
+    {
+        rc = sel->u.expr.method->init_frame(data->top, data->fr, data->pbc,
+                                            sel->u.expr.mdata);
+        sel->flags &= ~SEL_INITFRAME;
+        if (rc != 0)
+        {
+            return rc;
+        }
+    }
+    if (sel->u.expr.pc)
+    {
+        gmx_ana_poscalc_update(sel->u.expr.pc, sel->u.expr.pos, g,
+                               data->fr, data->pbc);
+        rc = sel->u.expr.method->pupdate(data->top, data->fr, data->pbc,
+                                         sel->u.expr.pos, &sel->v,
+                                         sel->u.expr.mdata);
+    }
+    else
+    {
+        rc = sel->u.expr.method->update(data->top, data->fr, data->pbc, g,
+                                        &sel->v, sel->u.expr.mdata);
+    }
+    return rc;
+}
+
+/*!
+ * \param[in] data Data for the current frame.
+ * \param[in] sel Selection element being evaluated.
+ * \param[in] g   Group for which \p sel should be evaluated.
+ * \returns   0 on success, a non-zero error code on error.
+ *
+ * Evaluates all child selections (using _gmx_sel_evaluate_method_params())
+ * to evaluate any parameter values.
+ * If this is the first time this expression is evaluated for
+ * the frame, sel_framefunc() callback is called if one is provided.
+ * The modifier is then evaluated using sel_updatefunc_pos().
+ *
+ * This function is used as \c t_selelem::evaluate for \ref SEL_MODIFIER
+ * elements.
+ */
+int
+_gmx_sel_evaluate_modifier(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g)
+{
+    int rc;
+
+    rc = _gmx_sel_evaluate_method_params(data, sel, g);
+    if (rc != 0)
+    {
+        return rc;
+    }
+    if (sel->flags & SEL_INITFRAME)
+    {
+        rc = sel->u.expr.method->init_frame(data->top, data->fr, data->pbc,
+                                            sel->u.expr.mdata);
+        sel->flags &= ~SEL_INITFRAME;
+        if (rc != 0)
+        {
+            return rc;
+        }
+    }
+    if (sel->child->v.type != POS_VALUE)
+    {
+        gmx_bug("non-position valued modifiers not implemented");
+        return -1;
+    }
+    rc = sel->u.expr.method->pupdate(data->top, data->fr, data->pbc,
+                                    sel->child->v.u.p,
+                                    &sel->v, sel->u.expr.mdata);
+    return rc;
+}
+
+
+/********************************************************************
+ * BOOLEAN EXPRESSION EVALUATION
+ ********************************************************************/
+
+/*!
+ * \param[in] data Data for the current frame.
+ * \param[in] sel Selection element being evaluated.
+ * \param[in] g   Group for which \p sel should be evaluated.
+ * \returns   0 on success, a non-zero error code on error.
+ *
+ * Evaluates the child element (there should be only one) in the group
+ * \p g, and then sets the value of \p sel to the complement of the 
+ * child value.
+ *
+ * This function is used as \c t_selelem::evaluate for \ref SEL_BOOLEAN
+ * elements with \ref BOOL_NOT.
+ */
+int
+_gmx_sel_evaluate_not(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g)
+{
+    int rc;
+
+    rc = _gmx_selelem_mempool_reserve(sel->child, g->isize);
+    if (rc == 0)
+    {
+        rc = sel->child->evaluate(data, sel->child, g);
+    }
+    if (rc != 0)
+    {
+        return rc;
+    }
+    gmx_ana_index_difference(sel->v.u.g, g, sel->child->v.u.g);
+    _gmx_selelem_mempool_release(sel->child);
+    return 0;
+}
+
+/*!
+ * \param[in] data Data for the current frame.
+ * \param[in] sel Selection element being evaluated.
+ * \param[in] g   Group for which \p sel should be evaluated.
+ * \returns   0 on success, a non-zero error code on error.
+ *
+ * Short-circuiting evaluation of logical AND expressions.
+ *
+ * Starts by evaluating the first child element in the group \p g.
+ * The each following child element is evaluated in the intersection
+ * of all the previous values until all children have been evaluated
+ * or the intersection becomes empty.
+ * The value of \p sel is set to the intersection of all the (evaluated)
+ * child values.
+ *
+ * If the first child does not have an evaluation function, it is skipped
+ * and the evaluation is started at the second child.
+ * This happens if the first child is a constant expression and during
+ * compilation it was detected that the evaluation group is always a subset
+ * of the constant group
+ * (currently, the compiler never detects this).
+ *
+ * This function is used as \c t_selelem::evaluate for \ref SEL_BOOLEAN
+ * elements with \ref BOOL_AND.
+ */
+int
+_gmx_sel_evaluate_and(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g)
+{
+    t_selelem *child;
+    int        rc;
+
+    child = sel->child;
+    /* Skip the first child if it does not have an evaluation function. */
+    if (!child->evaluate)
+    {
+        child = child->next;
+    }
+    rc = _gmx_selelem_mempool_reserve(child, g->isize);
+    if (rc == 0)
+    {
+        rc = child->evaluate(data, child, g);
+    }
+    if (rc != 0)
+    {
+        return rc;
+    }
+    gmx_ana_index_copy(sel->v.u.g, child->v.u.g, FALSE);
+    _gmx_selelem_mempool_release(child);
+    child = child->next;
+    while (child && sel->v.u.g->isize > 0)
+    {
+        rc = _gmx_selelem_mempool_reserve(child, sel->v.u.g->isize);
+        if (rc == 0)
+        {
+            rc = child->evaluate(data, child, sel->v.u.g);
+        }
+        if (rc != 0)
+        {
+            return rc;
+        }
+        gmx_ana_index_intersection(sel->v.u.g, sel->v.u.g, child->v.u.g);
+        _gmx_selelem_mempool_release(child);
+        child = child->next;
+    }
+    return 0;
+}
+
+/*!
+ * \param[in] data Data for the current frame.
+ * \param[in] sel Selection element being evaluated.
+ * \param[in] g   Group for which \p sel should be evaluated.
+ * \returns   0 on success, a non-zero error code on error.
+ *
+ * Short-circuiting evaluation of logical OR expressions.
+ *
+ * Starts by evaluating the first child element in the group \p g.
+ * For each subsequent child, finds the part of \p g that is not
+ * included the value of any previous child, and evaluates the child
+ * in that group until the last child is evaluated or all of \p g
+ * is included in some child value.
+ * The value of \p sel is set to the union of all the (evaluated)
+ * child values.
+ *
+ * If the first child does not have an evaluation function, its value is
+ * used without evaluation.
+ * This happens if the first child is a constant expression, the selection
+ * has been compiled, and the evaluation group is the same for each frame.
+ * In this case, the compiler has taken care of that the child value is a
+ * subset of \p g, making it unnecessary to evaluate it.
+ *
+ * This function is used as \c t_selelem::evaluate for \ref SEL_BOOLEAN
+ * elements with \ref BOOL_OR.
+ */
+int
+_gmx_sel_evaluate_or(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g)
+{
+    t_selelem     *child;
+    gmx_ana_index_t  tmp, tmp2;
+    int              rc;
+
+    child = sel->child;
+    if (child->evaluate)
+    {
+        rc = _gmx_selelem_mempool_reserve(child, g->isize);
+        if (rc == 0)
+        {
+            rc = child->evaluate(data, child, g);
+        }
+        if (rc != 0)
+        {
+            return rc;
+        }
+        gmx_ana_index_partition(sel->v.u.g, &tmp, g, child->v.u.g);
+        _gmx_selelem_mempool_release(child);
+    }
+    else
+    {
+        gmx_ana_index_partition(sel->v.u.g, &tmp, g, child->v.u.g);
+    }
+    child = child->next;
+    while (child && tmp.isize > 0)
+    {
+        tmp.name = NULL;
+        rc = _gmx_selelem_mempool_reserve(child, tmp.isize);
+        if (rc == 0)
+        {
+            rc = child->evaluate(data, child, &tmp);
+        }
+        if (rc != 0)
+        {
+            return rc;
+        }
+        gmx_ana_index_partition(&tmp, &tmp2, &tmp, child->v.u.g);
+        _gmx_selelem_mempool_release(child);
+        sel->v.u.g->isize += tmp.isize;
+        tmp.isize = tmp2.isize;
+        tmp.index = tmp2.index;
+        child = child->next;
+    }
+    gmx_ana_index_sort(sel->v.u.g);
+    return 0;
+}
+
+
+/********************************************************************
+ * ARITHMETIC EVALUATION
+ ********************************************************************/
+
+/*!
+ * \param[in] data Data for the current frame.
+ * \param[in] sel  Selection element being evaluated.
+ * \param[in] g    Group for which \p sel should be evaluated.
+ * \returns   0 on success, a non-zero error code on error.
+ */
+int
+_gmx_sel_evaluate_arithmetic(gmx_sel_evaluate_t *data, t_selelem *sel,
+                             gmx_ana_index_t *g)
+{
+    t_selelem  *left, *right;
+    int         n, i, i1, i2;
+    real        lval, rval=0., val=0.;
+    int         rc;
+
+    left  = sel->child;
+    right = left->next;
+
+    if (left->mempool)
+    {
+        _gmx_selvalue_setstore(&left->v, sel->v.u.ptr);
+        if (right)
+        {
+            rc = _gmx_selelem_mempool_reserve(right, g->isize);
+            if (rc != 0)
+            {
+                return rc;
+            }
+        }
+    }
+    else if (right && right->mempool)
+    {
+        _gmx_selvalue_setstore(&right->v, sel->v.u.ptr);
+    }
+    rc = _gmx_sel_evaluate_children(data, sel, g);
+
+    n = (sel->flags & SEL_SINGLEVAL) ? 1 : g->isize;
+    sel->v.nr = n;
+    for (i = i1 = i2 = 0; i < n; ++i)
+    {
+        lval = left->v.u.r[i1];
+        if (sel->u.arith.type != ARITH_NEG)
+        {
+            rval = right->v.u.r[i2];
+        }
+        switch (sel->u.arith.type)
+        {
+            case ARITH_PLUS:    val = lval + rval;     break;
+            case ARITH_MINUS:   val = lval - rval;     break;
+            case ARITH_NEG:     val = -lval;           break;
+            case ARITH_MULT:    val = lval * rval;     break;
+            case ARITH_DIV:     val = lval / rval;     break;
+            case ARITH_EXP:     val = pow(lval, rval); break;
+        }
+        sel->v.u.r[i] = val;
+        if (!(left->flags & SEL_SINGLEVAL))
+        {
+            ++i1;
+        }
+        if (sel->u.arith.type != ARITH_NEG && !(right->flags & SEL_SINGLEVAL))
+        {
+            ++i2;
+        }
+    }
+
+    if (left->mempool)
+    {
+        _gmx_selvalue_setstore(&left->v, NULL);
+        if (right)
+        {
+            _gmx_selelem_mempool_release(right);
+        }
+    }
+    else if (right && right->mempool)
+    {
+        _gmx_selvalue_setstore(&right->v, NULL);
+    }
+    return 0;
+}
diff --git a/src/gromacs/selection/evaluate.h b/src/gromacs/selection/evaluate.h
new file mode 100644 (file)
index 0000000..d0c25df
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief Evaluation functions for sel_evalfunc().
+ *
+ * This is an implementation header: there should be no need to use it outside
+ * this directory.
+ * Users should only use SelectionCollection::evaluate() to evaluate
+ * selections.
+ *
+ * The functions defined in this header file are all the possible values
+ * for the \c t_selelem::evaluate field (in addition to NULL).
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_selection
+ */
+#ifndef GMX_SELECTION_EVALUATE_H
+#define GMX_SELECTION_EVALUATE_H
+
+#include <typedefs.h>
+
+#include "gromacs/selection/indexutil.h"
+
+#include "selelem.h"
+
+struct gmx_sel_mempool_t;
+
+/*! \internal \brief
+ * Data structure for passing information required during evaluation.
+ */
+typedef struct gmx_sel_evaluate_t
+{
+    /** Memory pool for intermediate values. */
+    struct gmx_sel_mempool_t *mp;
+    /** Index group that contains all the atoms. */
+    gmx_ana_index_t         *gall;
+    /** Topology information. */
+    t_topology              *top;
+    /** Current frame. */
+    t_trxframe              *fr;
+    /** PBC data. */
+    t_pbc                   *pbc;
+} gmx_sel_evaluate_t;
+
+/*! \name Utility functions
+ */
+/*@{*/
+/** Initializes an evaluation data structure. */
+void
+_gmx_sel_evaluate_init(gmx_sel_evaluate_t *data,
+                       struct gmx_sel_mempool_t *mp, gmx_ana_index_t *gall,
+                       t_topology *top, t_trxframe *fr, t_pbc *pbc);
+/** Evaluates the children of a general selection element. */
+int
+_gmx_sel_evaluate_children(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g);
+/** Evaluates the children of a \ref SEL_EXPRESSION element. */
+int
+_gmx_sel_evaluate_method_params(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g);
+/*@}*/
+
+/*! \name Misc. evaluation functions
+ */
+/*@{*/
+/** Evaluates a root selection element. */
+int
+_gmx_sel_evaluate_root(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g);
+/** Evaluates a static group selection element. */
+int
+_gmx_sel_evaluate_static(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g);
+/** Evaluates an arithmetic expression element. */
+int
+_gmx_sel_evaluate_arithmetic(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g);
+/*@}*/
+
+/*! \name Subexpression evaluation functions
+ */
+/*@{*/
+/** Evaluates a subexpression when there is only one reference. */
+int
+_gmx_sel_evaluate_subexpr_simple(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g);
+/** Evaluates a subexpression when the evaluation group is static. */
+int
+_gmx_sel_evaluate_subexpr_staticeval(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g);
+/** Evaluates a subexpression. */
+int
+_gmx_sel_evaluate_subexpr(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g);
+/** Evaluates a subexpression reference when there are no other references. */
+int
+_gmx_sel_evaluate_subexprref_simple(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g);
+/** Evaluates a subexpression reference. */
+int
+_gmx_sel_evaluate_subexprref(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g);
+/*@}*/
+
+/*! \name Method evaluation functions
+ */
+/*@{*/
+
+/** Evaluates a method expression. */
+int
+_gmx_sel_evaluate_method(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g);
+/** Evaluates a modifier expression. */
+int
+_gmx_sel_evaluate_modifier(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g);
+/*@}*/
+
+/*! \name Boolean evaluation functions
+ */
+/*@{*/
+/** Evaluates a boolean NOT element. */
+int
+_gmx_sel_evaluate_not(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g);
+/** Evaluates a boolean AND element with short-circuiting. */
+int
+_gmx_sel_evaluate_and(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g);
+/** Evaluates a boolean OR element with short-circuiting. */
+int
+_gmx_sel_evaluate_or(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g);
+/*@}*/
+
+#endif
diff --git a/src/gromacs/selection/indexutil.cpp b/src/gromacs/selection/indexutil.cpp
new file mode 100644 (file)
index 0000000..bb1bc04
--- /dev/null
@@ -0,0 +1,1457 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * Implements functions in indexutil.h.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_selection
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <index.h>
+#include <smalloc.h>
+#include <string2.h>
+#include <typedefs.h>
+#include <gmx_fatal.h>
+
+#include "gromacs/selection/indexutil.h"
+
+/********************************************************************
+ * gmx_ana_indexgrps_t functions
+ ********************************************************************/
+
+/*! \internal \brief
+ * Stores a set of index groups.
+ */
+struct gmx_ana_indexgrps_t
+{
+    /** Number of index groups. */
+    int                 nr;
+    /** Array of index groups. */
+    gmx_ana_index_t    *g;
+};
+
+/*!
+ * \param[out] g     Index group structure.
+ * \param[in]  ngrps Number of groups for which memory is allocated.
+ */
+void
+gmx_ana_indexgrps_alloc(gmx_ana_indexgrps_t **g, int ngrps)
+{
+    snew(*g, 1);
+    (*g)->nr = ngrps;
+    snew((*g)->g,    ngrps);
+}
+
+/*!
+ * \param[out] g     Index group structure.
+ * \param[in]  ngrps Number of index groups.
+ * \param[in]  isize Array of index group sizes.
+ * \param[in]  index Array of pointers to indices of each group.
+ * \param[in]  name  Array of names of the groups.
+ * \param[in]  bFree If TRUE, the \p isize, \p index and \p name arrays
+ *   are freed after they have been copied.
+ */
+void
+gmx_ana_indexgrps_set(gmx_ana_indexgrps_t **g, int ngrps, int *isize,
+                      atom_id **index, char **name, gmx_bool bFree)
+{
+    int  i;
+
+    gmx_ana_indexgrps_alloc(g, ngrps);
+    for (i = 0; i < ngrps; ++i)
+    {
+        gmx_ana_index_set(&(*g)->g[i], isize[i], index[i], name[i], isize[i]);
+    }
+    if (bFree)
+    {
+        sfree(isize);
+        sfree(index);
+        sfree(name);
+    }
+}
+
+/*!
+ * \param[out] g     Index group structure.
+ * \param[in]  top   Topology structure.
+ * \param[in]  fnm   File name for the index file.
+ *   Memory is automatically allocated.
+ *
+ * One or both of \p top or \p fnm can be NULL.
+ * If \p top is NULL, an index file is required and the groups are read
+ * from the file (uses Gromacs routine init_index()).
+ * If \p fnm is NULL, default groups are constructed based on the
+ * topology (uses Gromacs routine analyse()).
+ * If both are null, the index group structure is initialized empty.
+ */
+void
+gmx_ana_indexgrps_init(gmx_ana_indexgrps_t **g, t_topology *top, 
+                       const char *fnm)
+{
+    t_blocka *block = NULL;
+    char    **names = NULL;
+    int       i, j;
+
+    if (fnm)
+    {
+        block = init_index(fnm, &names);
+    }
+    else if (top)
+    {
+        block = new_blocka();
+        analyse(&top->atoms, block, &names, FALSE, FALSE);
+    }
+    else
+    {
+        snew(*g, 1);
+        (*g)->nr    = 0;
+        (*g)->g     = NULL;
+        return;
+    }
+
+    gmx_ana_indexgrps_alloc(g, block->nr);
+    for (i = 0; i < block->nr; ++i)
+    {
+        gmx_ana_index_t *grp = &(*g)->g[i];
+
+        grp->isize = block->index[i+1] - block->index[i];
+        snew(grp->index, grp->isize);
+        for (j = 0; j < grp->isize; ++j)
+        {
+            grp->index[j] = block->a[block->index[i]+j];
+        }
+        grp->name = names[i];
+        grp->nalloc_index = grp->isize;
+    }
+
+    done_blocka(block);
+    sfree(block);
+    sfree(names);
+}
+
+/*!
+ * \param[out] g     Index group structure.
+ * \param[in]  top   Topology structure.
+ * \param[in]  fnm   File name for the index file.
+ * \param[in]  ngrps Number of required groups.
+ *   Memory is automatically allocated.
+ *
+ * One of \p top or \p fnm can be NULL, but not both.
+ * If \p top is NULL, an index file is required and the groups are read
+ * from the file (uses Gromacs routine rd_index()).
+ * If \p fnm is NULL, default groups are constructed based on the
+ * topology (uses Gromacs routine get_index()).
+ */
+void
+gmx_ana_indexgrps_get(gmx_ana_indexgrps_t **g, t_topology *top, 
+                      const char *fnm, int ngrps)
+{
+    int      *isize;
+    atom_id **index;
+    char    **name;
+
+    snew(isize, ngrps);
+    snew(index, ngrps);
+    snew(name,  ngrps);
+    if (!top)
+    {
+        rd_index(fnm, ngrps, isize, index, name);
+    }
+    else
+    {
+        get_index(&(top->atoms), fnm, ngrps, isize, index, name);
+    }
+    gmx_ana_indexgrps_set(g, ngrps, isize, index, name, TRUE);
+}
+
+/*!
+ * \param[out] g     Index group structure.
+ * \param[in]  fnm   File name for the index file.
+ * \param[in]  ngrps Number of required groups.
+ *   Memory is automatically allocated.
+ *
+ * This is a convenience function for calling the Gromacs routine
+ * rd_index().
+ */
+void
+gmx_ana_indexgrps_rd(gmx_ana_indexgrps_t **g, const char *fnm, int ngrps)
+{
+    gmx_ana_indexgrps_get(g, NULL, fnm, ngrps);
+}
+
+/*!
+ * \param[in] g  Index groups structure.
+ *
+ * The pointer \p g is invalid after the call.
+ */
+void
+gmx_ana_indexgrps_free(gmx_ana_indexgrps_t *g)
+{
+    int  i;
+
+    if (g->nr == 0)
+    {
+        sfree(g);
+        return;
+    }
+    for (i = 0; i < g->nr; ++i)
+    {
+        gmx_ana_index_deinit(&g->g[i]);
+    }
+    sfree(g->g);
+    g->nr    = 0;
+    g->g     = NULL;
+    sfree(g);
+}
+
+/*!
+ * \param[out] dest Destination index groups.
+ * \param[in]  src  Source index groups.
+ *
+ * A deep copy is made for all fields, including the group names.
+ */
+void
+gmx_ana_indexgrps_clone(gmx_ana_indexgrps_t **dest, gmx_ana_indexgrps_t *src)
+{
+    int g;
+
+    gmx_ana_indexgrps_alloc(dest, src->nr);
+    for (g = 0; g < src->nr; ++g)
+    {
+        gmx_ana_index_copy(&(*dest)->g[g], &src->g[g], TRUE);
+    }
+}
+
+/*!
+ * \param[out] g     Index group structure.
+ * \returns    TRUE if \p g is empty, i.e., has 0 index groups.
+ */
+gmx_bool
+gmx_ana_indexgrps_is_empty(gmx_ana_indexgrps_t *g)
+{
+    return g->nr == 0;
+}
+
+/*!
+ * \param[in]  g     Index groups structure.
+ * \param[in]  n     Index group number to get.
+ * \returns    Pointer to the \p n'th index group in \p g.
+ *
+ * The returned pointer should not be freed.
+ */
+gmx_ana_index_t *
+gmx_ana_indexgrps_get_grp(gmx_ana_indexgrps_t *g, int n)
+{
+    if (n < 0 || n >= g->nr)
+    {
+        return NULL;
+    }
+    return &g->g[n];
+}
+
+/*!
+ * \param[out] dest Output structure.
+ * \param[in]  src  Input index groups.
+ * \param[in]  n    Number of the group to extract.
+ * \returns TRUE if \p n is a valid group in \p src, FALSE otherwise.
+ */
+gmx_bool
+gmx_ana_indexgrps_extract(gmx_ana_index_t *dest, gmx_ana_indexgrps_t *src, int n)
+{
+    if (n < 0 || n >= src->nr)
+    {
+        dest->isize = 0;
+        return FALSE;
+    }
+
+    gmx_ana_index_copy(dest, &src->g[n], TRUE);
+    return TRUE;
+}
+
+/*!
+ * \param[out] dest Output structure.
+ * \param[in]  src  Input index groups.
+ * \param[in]  name Name (or part of the name) of the group to extract.
+ * \returns TRUE if \p name is a valid group in \p src, FALSE otherwise.
+ *
+ * Uses the Gromacs routine find_group() to find the actual group;
+ * the comparison is case-insensitive.
+ */
+gmx_bool
+gmx_ana_indexgrps_find(gmx_ana_index_t *dest, gmx_ana_indexgrps_t *src, char *name)
+{
+    int    i;
+    char **names;
+
+    snew(names, src->nr);
+    for (i = 0; i < src->nr; ++i)
+    {
+        names[i] = src->g[i].name;
+    }
+    i = find_group(name, src->nr, names);
+    sfree(names);
+    if (i == NOTSET)
+    {
+        dest->isize = 0;
+        return FALSE;
+    }
+
+    return gmx_ana_indexgrps_extract(dest, src, i);
+}
+
+/*!
+ * \param[in]  g      Index groups to print.
+ * \param[in]  maxn   Maximum number of indices to print
+ *      (-1 = print all, 0 = print only names).
+ */
+void
+gmx_ana_indexgrps_print(gmx_ana_indexgrps_t *g, int maxn)
+{
+    int  i;
+
+    for (i = 0; i < g->nr; ++i)
+    {
+        fprintf(stderr, " %2d: ", i);
+        gmx_ana_index_dump(&g->g[i], i, maxn);
+    }
+}
+
+/********************************************************************
+ * gmx_ana_index_t functions
+ ********************************************************************/
+
+/*!
+ * \param[in,out] g      Index group structure.
+ * \param[in]     isize  Maximum number of atoms to reserve space for.
+ */
+void
+gmx_ana_index_reserve(gmx_ana_index_t *g, int isize)
+{
+    if (g->nalloc_index < isize)
+    {
+        srenew(g->index, isize);
+        g->nalloc_index = isize;
+    }
+}
+
+/*!
+ * \param[in,out] g      Index group structure.
+ *
+ * Resizes the memory allocated for holding the indices such that the
+ * current contents fit.
+ */
+void
+gmx_ana_index_squeeze(gmx_ana_index_t *g)
+{
+    srenew(g->index, g->isize);
+    g->nalloc_index = g->isize;
+}
+
+/*!
+ * \param[out] g      Output structure.
+ *
+ * Any contents of \p g are discarded without freeing.
+ */
+void
+gmx_ana_index_clear(gmx_ana_index_t *g)
+{
+    g->isize        = 0;
+    g->index        = NULL;
+    g->name         = NULL;
+    g->nalloc_index = 0;
+}
+
+/*!
+ * \param[out] g      Output structure.
+ * \param[in]  isize  Number of atoms in the new group.
+ * \param[in]  index  Array of \p isize atoms (can be NULL if \p isize is 0).
+ * \param[in]  name   Name for the new group (can be NULL).
+ * \param[in]  nalloc Number of elements allocated for \p index
+ *   (if 0, \p index is not freed in gmx_ana_index_deinit())
+ *
+ * No copy if \p index is made.
+ */
+void
+gmx_ana_index_set(gmx_ana_index_t *g, int isize, atom_id *index, char *name,
+                  int nalloc)
+{
+    g->isize        = isize;
+    g->index        = index;
+    g->name         = name;
+    g->nalloc_index = nalloc;
+}
+
+/*!
+ * \param[out] g      Output structure.
+ * \param[in]  natoms Number of atoms.
+ * \param[in]  name   Name for the new group (can be NULL).
+ */
+void
+gmx_ana_index_init_simple(gmx_ana_index_t *g, int natoms, char *name)
+{
+    int  i;
+
+    g->isize = natoms;
+    snew(g->index, natoms);
+    for (i = 0; i < natoms; ++i)
+    {
+        g->index[i] = i;
+    }
+    g->name = name;
+    g->nalloc_index = natoms;
+}
+
+/*!
+ * \param[in] g  Index group structure.
+ *
+ * The pointer \p g is not freed.
+ */
+void
+gmx_ana_index_deinit(gmx_ana_index_t *g)
+{
+    if (g->nalloc_index > 0)
+    {
+        sfree(g->index);
+    }
+    sfree(g->name);
+    gmx_ana_index_clear(g);
+}
+
+/*!
+ * \param[out] dest   Destination index group.
+ * \param[in]  src    Source index group.
+ * \param[in]  bAlloc If TRUE, memory is allocated at \p dest; otherwise,
+ *   it is assumed that enough memory has been allocated for index.
+ *
+ * A deep copy of the name is only made if \p bAlloc is TRUE.
+ */
+void
+gmx_ana_index_copy(gmx_ana_index_t *dest, gmx_ana_index_t *src, gmx_bool bAlloc)
+{
+    dest->isize = src->isize;
+    if (dest->isize > 0)
+    {
+        if (bAlloc)
+        {
+            snew(dest->index, dest->isize);
+            dest->nalloc_index = dest->isize;
+        }
+        memcpy(dest->index, src->index, dest->isize*sizeof(*dest->index));
+    }
+    if (bAlloc && src->name)
+    {
+        dest->name = strdup(src->name);
+    }
+    else if (bAlloc || src->name)
+    {
+        dest->name = src->name;
+    }
+}
+
+/*!
+ * \param[in]  g      Index group to print.
+ * \param[in]  i      Group number to use if the name is NULL.
+ * \param[in]  maxn   Maximum number of indices to print (-1 = print all).
+ */
+void
+gmx_ana_index_dump(gmx_ana_index_t *g, int i, int maxn)
+{
+    int  j, n;
+
+    if (g->name)
+    {
+        fprintf(stderr, "\"%s\"", g->name);
+    }
+    else
+    {
+        fprintf(stderr, "Group %d", i+1);
+    }
+    fprintf(stderr, " (%d atoms)", g->isize);
+    if (maxn != 0)
+    {
+        fprintf(stderr, ":");
+        n = g->isize;
+        if (maxn >= 0 && n > maxn)
+        {
+            n = maxn;
+        }
+        for (j = 0; j < n; ++j)
+        {
+            fprintf(stderr, " %d", g->index[j]+1);
+        }
+        if (n < g->isize)
+        {
+            fprintf(stderr, " ...");
+        }
+    }
+    fprintf(stderr, "\n");
+}
+
+/*!
+ * \param[in]  g      Input index group.
+ * \param[in]  natoms Number of atoms to check against.
+ *
+ * If any atom index in the index group is less than zero or >= \p natoms,
+ * gmx_fatal() is called.
+ */
+void
+gmx_ana_index_check(gmx_ana_index_t *g, int natoms)
+{
+    int  j;
+
+    for (j = 0; j < g->isize; ++j)
+    {
+        if (g->index[j] >= natoms)
+        {
+            gmx_fatal(FARGS,"Atom index (%d) in index group %s (%d atoms) "
+              "larger than number of atoms in trajectory (%d atoms)",
+              g->index[j], g->name, g->isize, natoms);
+        }
+        else if (g->index[j] < 0)
+        {
+            gmx_fatal(FARGS,"Atom index (%d) in index group %s (%d atoms) "
+              "is less than zero",
+              g->index[j], g->name, g->isize);
+        }
+    }
+}
+
+/*!
+ * \param[in]  g      Index group to check.
+ * \returns    TRUE if the index group is sorted and has no duplicates,
+ *   FALSE otherwise.
+ */
+gmx_bool
+gmx_ana_index_check_sorted(gmx_ana_index_t *g)
+{
+    int  i;
+
+    for (i = 0; i < g->isize-1; ++i)
+    {
+        if (g->index[i+1] <= g->index[i])
+        {
+            return FALSE;
+        }
+    }
+    return TRUE;
+}
+
+/********************************************************************
+ * Set operations
+ ********************************************************************/
+
+/** Helper function for gmx_ana_index_sort(). */
+static int
+cmp_atomid(const void *a, const void *b)
+{
+    if (*(atom_id *)a < *(atom_id *)b) return -1;
+    if (*(atom_id *)a > *(atom_id *)b) return 1;
+    return 0;
+}
+
+/*!
+ * \param[in,out] g  Index group to be sorted.
+ */
+void
+gmx_ana_index_sort(gmx_ana_index_t *g)
+{
+    qsort(g->index, g->isize, sizeof(*g->index), cmp_atomid);
+}
+
+/*!
+ * \param[in]  a      Index group to check.
+ * \param[in]  b      Index group to check.
+ * \returns    TRUE if \p a and \p b are equal, FALSE otherwise.
+ */
+gmx_bool
+gmx_ana_index_equals(gmx_ana_index_t *a, gmx_ana_index_t *b)
+{
+    int  i;
+
+    if (a->isize != b->isize)
+    {
+        return FALSE;
+    }
+    for (i = 0; i < a->isize; ++i)
+    {
+        if (a->index[i] != b->index[i])
+        {
+            return FALSE;
+        }
+    }
+    return TRUE;
+}
+
+/*!
+ * \param[in]  a      Index group to check against.
+ * \param[in]  b      Index group to check.
+ * \returns    TRUE if \p b is contained in \p a,
+ *   FALSE otherwise.
+ *
+ * If the elements are not in the same order in both groups, the function
+ * fails. However, the groups do not need to be sorted.
+ */
+gmx_bool
+gmx_ana_index_contains(gmx_ana_index_t *a, gmx_ana_index_t *b)
+{
+    int  i, j;
+
+    for (i = j = 0; j < b->isize; ++i, ++j) {
+        while (i < a->isize && a->index[i] != b->index[j])
+        {
+            ++i;
+        }
+        if (i == a->isize)
+        {
+            return FALSE;
+        }
+    }
+    return TRUE;
+}
+
+/*!
+ * \param[out] dest Output index group (the intersection of \p a and \p b).
+ * \param[in]  a    First index group.
+ * \param[in]  b    Second index group.
+ *
+ * \p dest can be the same as \p a or \p b.
+ */
+void
+gmx_ana_index_intersection(gmx_ana_index_t *dest,
+                           gmx_ana_index_t *a, gmx_ana_index_t *b)
+{
+    int i, j, k;
+
+    for (i = j = k = 0; i < a->isize && j < b->isize; ++i) {
+        while (j < b->isize && b->index[j] < a->index[i])
+        {
+            ++j;
+        }
+        if (j < b->isize && b->index[j] == a->index[i])
+        {
+            dest->index[k++] = b->index[j++];
+        }
+    }
+    dest->isize = k;
+}
+
+/*!
+ * \param[out] dest Output index group (the difference \p a - \p b).
+ * \param[in]  a    First index group.
+ * \param[in]  b    Second index group.
+ *
+ * \p dest can equal \p a, but not \p b.
+ */
+void
+gmx_ana_index_difference(gmx_ana_index_t *dest,
+                         gmx_ana_index_t *a, gmx_ana_index_t *b)
+{
+    int i, j, k;
+
+    for (i = j = k = 0; i < a->isize; ++i)
+    {
+        while (j < b->isize && b->index[j] < a->index[i])
+        {
+            ++j;
+        }
+        if (j == b->isize || b->index[j] != a->index[i])
+        {
+            dest->index[k++] = a->index[i];
+        }
+    }
+    dest->isize = k;
+}
+
+/*!
+ * \param[in]  a    First index group.
+ * \param[in]  b    Second index group.
+ * \returns    Size of the difference \p a - \p b.
+ */
+int
+gmx_ana_index_difference_size(gmx_ana_index_t *a, gmx_ana_index_t *b)
+{
+    int i, j, k;
+
+    for (i = j = k = 0; i < a->isize; ++i)
+    {
+        while (j < b->isize && b->index[j] < a->index[i])
+        {
+            ++j;
+        }
+        if (j == b->isize || b->index[j] != a->index[i])
+        {
+            ++k;
+        }
+    }
+    return k;
+}
+
+/*!
+ * \param[out] dest1 Output group 1 (will equal \p g).
+ * \param[out] dest2 Output group 2 (will equal \p src - \p g).
+ * \param[in]  src   Group to be partitioned.
+ * \param[in]  g     One partition.
+ *
+ * \pre \p g is a subset of \p src and both sets are sorted
+ * \pre \p dest1 has allocated storage to store \p src
+ * \post \p dest1 == \p g
+ * \post \p dest2 == \p src - \p g
+ *
+ * No storage should be allocated for \p dest2; after the call,
+ * \p dest2->index points to the memory allocated for \p dest1
+ * (to a part that is not used by \p dest1).
+ *
+ * The calculation can be performed in-place by setting \p dest1 equal to
+ * \p src.
+ */
+void
+gmx_ana_index_partition(gmx_ana_index_t *dest1, gmx_ana_index_t *dest2,
+                        gmx_ana_index_t *src, gmx_ana_index_t *g)
+                     
+{
+    int i, j, k;
+
+    dest2->index = dest1->index + g->isize;
+    dest2->isize = src->isize - g->isize;
+    for (i = g->isize-1, j = src->isize-1, k = dest2->isize-1; i >= 0; --i, --j)
+    {
+        while (j >= 0 && src->index[j] != g->index[i])
+        {
+            dest2->index[k--] = src->index[j--];
+        }
+    }
+    while (j >= 0)
+    {
+        dest2->index[k--] = src->index[j--];
+    }
+    gmx_ana_index_copy(dest1, g, FALSE);
+}
+
+/*!
+ * \param[out] dest Output index group (the union of \p a and \p b).
+ * \param[in]  a    First index group.
+ * \param[in]  b    Second index group.
+ *
+ * \p a and \p b can have common items.
+ * \p dest can equal \p a or \p b.
+ *
+ * \see gmx_ana_index_merge()
+ */
+void
+gmx_ana_index_union(gmx_ana_index_t *dest,
+                    gmx_ana_index_t *a, gmx_ana_index_t *b)
+{
+    int dsize;
+    int i, j, k;
+
+    dsize = gmx_ana_index_difference_size(b, a);
+    i = a->isize - 1;
+    j = b->isize - 1;
+    dest->isize = a->isize + dsize;
+    for (k = dest->isize - 1; k >= 0; k--)
+    {
+        if (i < 0 || (j >= 0 && a->index[i] < b->index[j]))
+        {
+            dest->index[k] = b->index[j--];
+        }
+        else
+        {
+            if (j >= 0 && a->index[i] == b->index[j])
+            {
+                --j;
+            }
+            dest->index[k] = a->index[i--];
+        }
+    }
+}
+
+/*!
+ * \param[out] dest Output index group (the union of \p a and \p b).
+ * \param[in]  a    First index group.
+ * \param[in]  b    Second index group.
+ *
+ * \p a and \p b should not have common items.
+ * \p dest can equal \p a or \p b.
+ *
+ * \see gmx_ana_index_union()
+ */
+void
+gmx_ana_index_merge(gmx_ana_index_t *dest,
+                    gmx_ana_index_t *a, gmx_ana_index_t *b)
+{
+    int i, j, k;
+
+    i = a->isize - 1;
+    j = b->isize - 1;
+    dest->isize = a->isize + b->isize;
+    for (k = dest->isize - 1; k >= 0; k--)
+    {
+        if (i < 0 || (j >= 0 && a->index[i] < b->index[j]))
+        {
+            dest->index[k] = b->index[j--];
+        }
+        else
+        {
+            dest->index[k] = a->index[i--];
+        }
+    }
+}
+
+/********************************************************************
+ * gmx_ana_indexmap_t and related things
+ ********************************************************************/
+
+/*!
+ * \param[in,out] t    Output block.
+ * \param[in]  top  Topology structure
+ *   (only used if \p type is \ref INDEX_RES or \ref INDEX_MOL, can be NULL
+ *   otherwise).
+ * \param[in]  g    Index group
+ *   (can be NULL if \p type is \ref INDEX_UNKNOWN).
+ * \param[in]  type Type of partitioning to make.
+ * \param[in]  bComplete
+ *   If TRUE, the index group is expanded to include any residue/molecule
+ *   (depending on \p type) that is partially contained in the group.
+ *   If \p type is not INDEX_RES or INDEX_MOL, this has no effect.
+ *
+ * \p m should have been initialized somehow (calloc() is enough) unless
+ * \p type is INDEX_UNKNOWN.
+ * \p g should be sorted.
+ */
+void
+gmx_ana_index_make_block(t_blocka *t, t_topology *top, gmx_ana_index_t *g,
+                         e_index_t type, gmx_bool bComplete)
+{
+    int      i, j, ai;
+    int      id, cur;
+
+    if (type == INDEX_UNKNOWN)
+    {
+        t->nr           = 1;
+        snew(t->index, 2);
+        t->nalloc_index = 2;
+        t->index[0]     = 0;
+        t->index[1]     = 0;
+        t->nra          = 0;
+        t->a            = NULL;
+        t->nalloc_a     = 0;
+        return;
+    }
+
+    /* bComplete only does something for INDEX_RES or INDEX_MOL, so turn it
+     * off otherwise. */
+    if (type != INDEX_RES && type != INDEX_MOL)
+    {
+        bComplete = FALSE;
+    }
+    /* Allocate memory for the atom array and fill it unless we are using
+     * completion. */
+    if (bComplete)
+    {
+        t->nra = 0;
+        /* We may allocate some extra memory here because we don't know in
+         * advance how much will be needed. */
+        if (t->nalloc_a < top->atoms.nr)
+        {
+            srenew(t->a, top->atoms.nr);
+            t->nalloc_a = top->atoms.nr;
+        }
+    }
+    else
+    {
+        t->nra      = g->isize;
+        if (t->nalloc_a < g->isize)
+        {
+            srenew(t->a, g->isize);
+            t->nalloc_a = g->isize;
+        }
+        memcpy(t->a, g->index, g->isize*sizeof(*(t->a)));
+    }
+
+    /* Allocate memory for the block index. We don't know in advance
+     * how much will be needed, so we allocate some extra and free it in the
+     * end. */
+    if (t->nalloc_index < g->isize + 1)
+    {
+        srenew(t->index, g->isize + 1);
+        t->nalloc_index = g->isize + 1;
+    }
+    /* Clear counters */
+    t->nr = 0;
+    j = 0; /* j is used by residue completion for the first atom not stored */
+    id = cur = -1;
+    for (i = 0; i < g->isize; ++i)
+    {
+        ai = g->index[i];
+        /* Find the ID number of the atom/residue/molecule corresponding to
+         * atom ai. */
+        switch (type)
+        {
+            case INDEX_ATOM:
+                id = ai;
+                break;
+            case INDEX_RES:
+                id = top->atoms.atom[ai].resind;
+                break;
+            case INDEX_MOL:
+                while (ai >= top->mols.index[id+1])
+                {
+                    id++;
+                }
+                break;
+            case INDEX_UNKNOWN: /* Should not occur */
+            case INDEX_ALL:
+                id = 0;
+                break;
+        }
+        /* If this is the first atom in a new block, initialize the block. */
+        if (id != cur)
+        {
+            if (bComplete)
+            {
+                /* For completion, we first set the start of the block. */
+                t->index[t->nr++] = t->nra;
+                /* And then we find all the atoms that should be included. */
+                switch (type)
+                {
+                    case INDEX_RES:
+                        while (top->atoms.atom[j].resind != id)
+                        {
+                            ++j;
+                        }
+                        while (j < top->atoms.nr && top->atoms.atom[j].resind == id)
+                        {
+                            t->a[t->nra++] = j;
+                            ++j;
+                        }
+                        break;
+
+                    case INDEX_MOL:
+                        for (j = top->mols.index[id]; j < top->mols.index[id+1]; ++j)
+                        {
+                            t->a[t->nra++] = j;
+                        }
+                        break;
+
+                    default: /* Should not be reached */
+                        gmx_bug("internal error");
+                        break;
+                }
+            }
+            else
+            {
+                /* If not using completion, simply store the start of the block. */
+                t->index[t->nr++] = i;
+            }
+            cur = id;
+        }
+    }
+    /* Set the end of the last block */
+    t->index[t->nr] = t->nra;
+    /* Free any unnecessary memory */
+    srenew(t->index, t->nr+1);
+    t->nalloc_index = t->nr+1;
+    if (bComplete)
+    {
+        srenew(t->a, t->nra);
+        t->nalloc_a = t->nra;
+    }
+}
+
+/*!
+ * \param[in] g   Index group to check.
+ * \param[in] b   Block data to check against.
+ * \returns   TRUE if \p g consists of one or more complete blocks from \p b,
+ *   FALSE otherwise.
+ *
+ * The atoms in \p g are assumed to be sorted.
+ */
+gmx_bool
+gmx_ana_index_has_full_blocks(gmx_ana_index_t *g, t_block *b)
+{
+    int  i, j, bi;
+
+    i = bi = 0;
+    /* Each round in the loop matches one block */
+    while (i < g->isize)
+    {
+        /* Find the block that begins with the first unmatched atom */
+        while (bi < b->nr && b->index[bi] != g->index[i])
+        {
+            ++bi;
+        }
+        /* If not found, or if too large, return */
+        if (bi == b->nr || i + b->index[bi+1] -  b->index[bi] > g->isize)
+        {
+            return FALSE;
+        }
+        /* Check that the block matches the index */
+        for (j = b->index[bi]; j < b->index[bi+1]; ++j, ++i)
+        {
+            if (g->index[i] != j)
+            {
+                return FALSE;
+            }
+        }
+        /* Move the search to the next block */
+        ++bi;
+    }
+    return TRUE;
+}
+
+/*!
+ * \param[in] g   Index group to check.
+ * \param[in] b   Block data to check against.
+ * \returns   TRUE if \p g consists of one or more complete blocks from \p b,
+ *   FALSE otherwise.
+ *
+ * The atoms in \p g and \p b->a are assumed to be in the same order.
+ */
+gmx_bool
+gmx_ana_index_has_full_ablocks(gmx_ana_index_t *g, t_blocka *b)
+{
+    int  i, j, bi;
+
+    i = bi = 0;
+    /* Each round in the loop matches one block */
+    while (i < g->isize)
+    {
+        /* Find the block that begins with the first unmatched atom */
+        while (bi < b->nr && b->a[b->index[bi]] != g->index[i])
+        {
+            ++bi;
+        }
+        /* If not found, or if too large, return */
+        if (bi == b->nr || i + b->index[bi+1] -  b->index[bi] > g->isize)
+        {
+            return FALSE;
+        }
+        /* Check that the block matches the index */
+        for (j = b->index[bi]; j < b->index[bi+1]; ++j, ++i)
+        {
+            if (b->a[j] != g->index[i])
+            {
+                return FALSE;
+            }
+        }
+        /* Move the search to the next block */
+        ++bi;
+    }
+    return TRUE;
+}
+
+/*!
+ * \param[in] g     Index group to check.
+ * \param[in] type  Block data to check against.
+ * \param[in] top   Topology data.
+ * \returns   TRUE if \p g consists of one or more complete elements of type
+ *   \p type, FALSE otherwise.
+ *
+ * If \p type is \ref INDEX_ATOM, the return value is always TRUE.
+ * If \p type is \ref INDEX_UNKNOWN or \ref INDEX_ALL, the return value is
+ * always FALSE.
+ */
+gmx_bool
+gmx_ana_index_has_complete_elems(gmx_ana_index_t *g, e_index_t type,
+                                 t_topology *top)
+{
+    switch (type)
+    {
+        case INDEX_UNKNOWN:
+        case INDEX_ALL:
+            return FALSE;
+
+        case INDEX_ATOM:
+            return TRUE;
+
+        case INDEX_RES:
+        {
+            int      i, ai;
+            int      id, prev;
+
+            prev = -1;
+            for (i = 0; i < g->isize; ++i)
+            {
+                ai = g->index[i];
+                id = top->atoms.atom[ai].resind;
+                if (id != prev)
+                {
+                    if (ai > 0 && top->atoms.atom[ai-1].resind == id)
+                    {
+                        return FALSE;
+                    }
+                    if (i > 0 && g->index[i-1] < top->atoms.nr - 1
+                        && top->atoms.atom[g->index[i-1]+1].resind == prev)
+                    {
+                        return FALSE;
+                    }
+                }
+                prev = id;
+            }
+            if (g->index[i-1] < top->atoms.nr - 1
+                && top->atoms.atom[g->index[i-1]+1].resind == prev)
+            {
+                return FALSE;
+            }
+            break;
+        }
+
+        case INDEX_MOL:
+            return gmx_ana_index_has_full_blocks(g, &top->mols);
+    }
+    return TRUE;
+}
+
+/*!
+ * \param[out] m      Output structure.
+ *
+ * Any contents of \p m are discarded without freeing.
+ */
+void
+gmx_ana_indexmap_clear(gmx_ana_indexmap_t *m)
+{
+    m->type              = INDEX_UNKNOWN;
+    m->nr                = 0;
+    m->refid             = NULL;
+    m->mapid             = NULL;
+    m->mapb.nr           = 0;
+    m->mapb.index        = NULL;
+    m->mapb.nalloc_index = 0;
+    m->orgid             = NULL;
+    m->b.nr              = 0;
+    m->b.index           = NULL;
+    m->b.nra             = 0;
+    m->b.a               = NULL;
+    m->b.nalloc_index    = 0;
+    m->b.nalloc_a        = 0;
+    m->bStatic           = TRUE;
+    m->bMapStatic        = TRUE;
+}
+
+/*!
+ * \param[in,out] m      Mapping structure.
+ * \param[in]     nr     Maximum number of blocks to reserve space for.
+ * \param[in]     isize  Maximum number of atoms to reserve space for.
+ */
+void
+gmx_ana_indexmap_reserve(gmx_ana_indexmap_t *m, int nr, int isize)
+{
+    if (m->mapb.nalloc_index < nr + 1)
+    {
+        srenew(m->refid,      nr);
+        srenew(m->mapid,      nr);
+        srenew(m->orgid,      nr);
+        srenew(m->mapb.index, nr + 1);
+        srenew(m->b.index,    nr + 1);
+        m->mapb.nalloc_index = nr + 1;
+        m->b.nalloc_index    = nr + 1;
+    }
+    if (m->b.nalloc_a < isize)
+    {
+        srenew(m->b.a,        isize);
+        m->b.nalloc_a = isize;
+    }
+}
+
+/*!
+ * \param[in,out] m    Mapping structure to initialize.
+ * \param[in]     g    Index group to map
+ *   (can be NULL if \p type is \ref INDEX_UNKNOWN).
+ * \param[in]     top  Topology structure
+ *   (can be NULL if \p type is not \ref INDEX_RES or \ref INDEX_MOL).
+ * \param[in]     type Type of mapping to construct.
+ *
+ * Initializes a new index group mapping.
+ * The index group provided to gmx_ana_indexmap_update() should always be a
+ * subset of the \p g given here.
+ *
+ * \p m should have been initialized somehow (calloc() is enough).
+ */
+void
+gmx_ana_indexmap_init(gmx_ana_indexmap_t *m, gmx_ana_index_t *g,
+                      t_topology *top, e_index_t type)
+{
+    int      i, ii, mi;
+
+    m->type   = type;
+    gmx_ana_index_make_block(&m->b, top, g, type, FALSE);
+    gmx_ana_indexmap_reserve(m, m->b.nr, m->b.nra);
+    m->nr = m->b.nr;
+    for (i = mi = 0; i < m->nr; ++i)
+    {
+        ii = (type == INDEX_UNKNOWN ? 0 : m->b.a[m->b.index[i]]);
+        switch (type)
+        {
+            case INDEX_ATOM:
+                m->orgid[i] = ii;
+                break;
+            case INDEX_RES:
+                m->orgid[i] = top->atoms.atom[ii].resind;
+                break;
+            case INDEX_MOL:
+                while (top->mols.index[mi+1] <= ii)
+                {
+                    ++mi;
+                }
+                m->orgid[i] = mi;
+                break;
+            case INDEX_ALL:
+            case INDEX_UNKNOWN:
+                m->orgid[i] = 0;
+                break;
+        }
+    }
+    for (i = 0; i < m->nr; ++i)
+    {
+        m->refid[i] = i;
+        m->mapid[i] = m->orgid[i];
+    }
+    m->mapb.nr = m->nr;
+    memcpy(m->mapb.index, m->b.index, (m->nr+1)*sizeof(*(m->mapb.index)));
+    m->bStatic    = TRUE;
+    m->bMapStatic = TRUE;
+}
+
+/*!
+ * \param[in,out] m    Mapping structure to initialize.
+ * \param[in]     b    Block information to use for data.
+ *
+ * Frees some memory that is not necessary for static index group mappings.
+ * Internal pointers are set to point to data in \p b; it is the responsibility
+ * of the caller to ensure that the block information matches the contents of
+ * the mapping.
+ * After this function has been called, the index group provided to
+ * gmx_ana_indexmap_update() should always be the same as \p g given here.
+ *
+ * This function breaks modularity of the index group mapping interface in an
+ * ugly way, but allows reducing memory usage of static selections by a
+ * significant amount.
+ */
+void
+gmx_ana_indexmap_set_static(gmx_ana_indexmap_t *m, t_blocka *b)
+{
+    sfree(m->mapid);
+    m->mapid = m->orgid;
+    sfree(m->b.index);
+    m->b.nalloc_index = 0;
+    m->b.index = b->index;
+    sfree(m->mapb.index);
+    m->mapb.nalloc_index = 0;
+    m->mapb.index = m->b.index;
+    sfree(m->b.a);
+    m->b.nalloc_a = 0;
+    m->b.a = b->a;
+}
+
+/*!
+ * \param[in,out] dest Destination data structure.
+ * \param[in]     src  Source mapping.
+ * \param[in]     bFirst If TRUE, memory is allocated for \p dest and a full
+ *   copy is made; otherwise, only variable parts are copied, and no memory
+ *   is allocated.
+ *
+ * \p dest should have been initialized somehow (calloc() is enough).
+ */
+void
+gmx_ana_indexmap_copy(gmx_ana_indexmap_t *dest, gmx_ana_indexmap_t *src, gmx_bool bFirst)
+{
+    if (bFirst)
+    {
+        gmx_ana_indexmap_reserve(dest, src->b.nr, src->b.nra);
+        dest->type       = src->type;
+        dest->b.nr       = src->b.nr;
+        dest->b.nra      = src->b.nra;
+        memcpy(dest->orgid,      src->orgid,      dest->b.nr*sizeof(*dest->orgid));
+        memcpy(dest->b.index,    src->b.index,   (dest->b.nr+1)*sizeof(*dest->b.index));
+        memcpy(dest->b.a,        src->b.a,        dest->b.nra*sizeof(*dest->b.a));
+    }
+    dest->nr         = src->nr;
+    dest->mapb.nr    = src->mapb.nr;
+    memcpy(dest->refid,      src->refid,      dest->nr*sizeof(*dest->refid));
+    memcpy(dest->mapid,      src->mapid,      dest->nr*sizeof(*dest->mapid));
+    memcpy(dest->mapb.index, src->mapb.index,(dest->mapb.nr+1)*sizeof(*dest->mapb.index));
+    dest->bStatic    = src->bStatic;
+    dest->bMapStatic = src->bMapStatic;
+}
+
+/*!
+ * \param[in,out] m         Mapping structure.
+ * \param[in]     g         Current index group.
+ * \param[in]     bMaskOnly TRUE if the unused blocks should be masked with
+ *   -1 instead of removing them.
+ *
+ * Updates the index group mapping with the new index group \p g.
+ *
+ * \see gmx_ana_indexmap_t
+ */
+void
+gmx_ana_indexmap_update(gmx_ana_indexmap_t *m, gmx_ana_index_t *g,
+                        gmx_bool bMaskOnly)
+{
+    int i, j, bi, bj;
+    gmx_bool bStatic;
+
+    /* Process the simple cases first */
+    if (m->type == INDEX_UNKNOWN && m->b.nra == 0)
+    {
+        return;
+    }
+    if (m->type == INDEX_ALL)
+    {
+        if (m->b.nr > 0)
+        {
+            m->mapb.index[1] = g->isize;
+        }
+        return;
+    }
+    /* Reset the reference IDs and mapping if necessary */
+    bStatic = (g->isize == m->b.nra && m->nr == m->b.nr);
+    if (bStatic || bMaskOnly)
+    {
+        if (!m->bStatic)
+        {
+            for (bj = 0; bj < m->b.nr; ++bj)
+            {
+                m->refid[bj] = bj;
+            }
+        }
+        if (!m->bMapStatic)
+        {
+            for (bj = 0; bj < m->b.nr; ++bj)
+            {
+                m->mapid[bj] = m->orgid[bj];
+            }
+            for (bj = 0; bj <= m->b.nr; ++bj)
+            {
+                m->mapb.index[bj] = m->b.index[bj];
+            }
+            m->bMapStatic = TRUE;
+        }
+    }
+    /* Exit immediately if the group is static */
+    if (bStatic)
+    {
+        m->bStatic = TRUE;
+        return;
+    }
+
+    if (bMaskOnly)
+    {
+        m->nr = m->b.nr;
+        for (i = j = bj = 0; i < g->isize; ++i, ++j)
+        {
+            /* Find the next atom in the block */
+            while (m->b.a[j] != g->index[i])
+            {
+                ++j;
+            }
+            /* Mark blocks that did not contain any atoms */
+            while (bj < m->b.nr && m->b.index[bj+1] <= j)
+            {
+                m->refid[bj++] = -1;
+            }
+            /* Advance the block index if we have reached the next block */
+            if (m->b.index[bj] <= j)
+            {
+                ++bj;
+            }
+        }
+        /* Mark the last blocks as not accessible */
+        while (bj < m->b.nr)
+        {
+            m->refid[bj++] = -1;
+        }
+    }
+    else
+    {
+        for (i = j = bi = 0, bj = -1; i < g->isize; ++i)
+        {
+            /* Find the next atom in the block */
+            while (m->b.a[j] != g->index[i])
+            {
+                ++j;
+            }
+            /* If we have reached a new block, add it */
+            if (m->b.index[bj+1] <= j)
+            {
+                /* Skip any blocks in between */
+                while (bj < m->b.nr && m->b.index[bj+1] <= j)
+                {
+                    ++bj;
+                }
+                m->refid[bi] = bj;
+                m->mapid[bi] = m->orgid[bj];
+                m->mapb.index[bi] = i;
+                bi++;
+            }
+        }
+        /* Update the number of blocks */
+        m->mapb.index[bi] = g->isize;
+        m->nr             = bi;
+        m->bMapStatic     = FALSE;
+    }
+    m->mapb.nr = m->nr;
+    m->bStatic = FALSE;
+}
+
+/*!
+ * \param[in,out] m         Mapping structure to free.
+ *
+ * All the memory allocated for the mapping structure is freed, and
+ * the pointers set to NULL.
+ * The pointer \p m is not freed.
+ */
+void
+gmx_ana_indexmap_deinit(gmx_ana_indexmap_t *m)
+{
+    sfree(m->refid);
+    if (m->mapid != m->orgid)
+    {
+        sfree(m->mapid);
+    }
+    if (m->mapb.nalloc_index > 0)
+    {
+        sfree(m->mapb.index);
+    }
+    sfree(m->orgid);
+    if (m->b.nalloc_index > 0)
+    {
+        sfree(m->b.index);
+    }
+    if (m->b.nalloc_a > 0)
+    {
+        sfree(m->b.a);
+    }
+    gmx_ana_indexmap_clear(m);
+}
diff --git a/src/gromacs/selection/indexutil.h b/src/gromacs/selection/indexutil.h
new file mode 100644 (file)
index 0000000..90d50f9
--- /dev/null
@@ -0,0 +1,360 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \file
+ * \brief API for handling index files and index groups.
+ *
+ * The API contains functions and data structures for handling index
+ * files more conveniently than as several separate variables.
+ * In addition to basic functions for initializing the data structures and
+ * making copies, functions are provided for performing (most) set operations
+ * on sorted index groups.
+ * There is also a function for partitioning a index group based on
+ * topology information such as residues or molecules.
+ * Finally, there is a set of functions for constructing mappings between
+ * an index group and its subgroups such.
+ * These can be used with dynamic index group in calculations if one
+ * needs to have a unique ID for each possible atom/residue/molecule in the
+ * selection, e.g., for analysis of dynamics or for look-up tables.
+ *
+ * Mostly, these functions are used internally by the library and the
+ * selection engine.
+ * However, some of the checking functions can be useful in user code to
+ * check the validity of input groups.
+ * Also, the mapping functions are useful when dealing with dynamic index
+ * groups.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_selection
+ */
+#ifndef GMX_SELECTION_INDEXUTIL_H
+#define GMX_SELECTION_INDEXUTIL_H
+
+#include "../legacyheaders/typedefs.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/** Stores a set of index groups. */
+typedef struct gmx_ana_indexgrps_t gmx_ana_indexgrps_t;
+
+/*! \brief
+ * Specifies the type of index partition or index mapping in several contexts.
+ *
+ * \see gmx_ana_index_make_block(), gmx_ana_indexmap_init()
+ */
+typedef enum
+{
+    INDEX_UNKNOWN, /**< Unknown index type.*/
+    INDEX_ATOM,    /**< Each atom in a separate block.*/
+    INDEX_RES,     /**< Each residue in a separate block.*/
+    INDEX_MOL,     /**< Each molecule in a separate block.*/
+    INDEX_ALL      /**< All atoms in a single block.*/
+} e_index_t;
+
+/*! \brief
+ * Stores a single index group.
+ */
+typedef struct gmx_ana_index_t
+{
+    /** Number of atoms. */
+    int                 isize;
+    /** List of atoms. */
+    atom_id            *index;
+    /** Group name. */
+    char               *name;
+    /** Number of items allocated for \p index. */
+    int                 nalloc_index;
+} gmx_ana_index_t;
+
+/*! \brief
+ * Data structure for calculating index group mappings.
+ */
+typedef struct gmx_ana_indexmap_t
+{
+    /** Type of the mapping. */
+    e_index_t           type;
+    /*! \brief
+     * Current number of mapped values.
+     *
+     * This is the current number of values in the \p refid and \p mapid
+     * arrays.
+     * If \p bMaskOnly is provided to gmx_ana_indexmap_update(), this
+     * is always equal to \p b.nr, i.e., the number of blocks in the
+     * original index group.
+     */
+    int                 nr;
+    /*! \brief
+     * Current reference IDs.
+     *
+     * This array provides a mapping from the current index group (last given
+     * to gmx_ana_indexmap_update()) to the blocks in \p b, i.e., the
+     * original index group used in gmx_ana_indexmap_init().
+     * The mapping is zero-based.
+     * If \p bMaskOnly is provided to gmx_ana_indexmap_update(), the indices
+     * for blocks not present in the current group are set to -1, otherwise
+     * they are removed completely and the \p nr field updated.
+     */
+    int                *refid;
+    /*! \brief
+     * Current mapped IDs.
+     *
+     * This array provides an arbitrary mapping from the current index group
+     * to the original index group. Instead of a zero-based mapping, the
+     * values from the \p orgid array are used. That is,
+     * \c mapid[i]=orgid[refid[i]].
+     * If \p bMaskOnly is provided to gmx_ana_indexmap_update(), this array
+     * equals \p orgid.
+     */
+    int                *mapid;
+    /*! \brief
+     * Mapped block structure.
+     *
+     * A block structure that corresponds to the current index group.
+     */
+    t_block             mapb;
+
+    /*! \brief
+     * Arbitrary ID numbers for the blocks.
+     *
+     * This array has \p b.nr elements, each defining an ID number for a
+     * block in \p b.
+     * These are initialized in gmx_ana_indexmap_init() based on the type:
+     *  - \ref INDEX_ATOM : the atom indices
+     *  - \ref INDEX_RES :  the residue numbers
+     *  - \ref INDEX_MOL :  the molecule numbers
+     *
+     * All the above numbers are zero-based.
+     * After gmx_ana_indexmap_init(), the user is free to change these values
+     * if the above are not appropriate.
+     * The mapped values can be read through \p mapid.
+     */
+    int                *orgid;
+
+    /*! \brief
+     * Block data that defines the mapping (internal use only).
+     *
+     * The data is initialized by gmx_ana_indexmap_init() and is not changed
+     * after that.
+     * Hence, it cannot be directly applied to the index group passed to
+     * gmx_ana_indexmap_update() unless \p bMaskOnly was specified or the
+     * index group is identical to the one provided to gmx_ana_indexmap_init().
+     */
+    t_blocka            b;
+    /*! \brief
+     * TRUE if the current reference IDs are for the whole group (internal use only).
+     *
+     * This is used internally to optimize the evaluation such that
+     * gmx_ana_indexmap_update() does not take any time if the group is
+     * actually static.
+     */
+    gmx_bool                bStatic;
+    /*! \brief
+     * TRUE if the current mapping is for the whole group (internal use only).
+     *
+     * This is used internally to optimize the evaluation such that
+     * gmx_ana_indexmap_update() does not take any time if the group is
+     * actually static.
+     */
+    gmx_bool                bMapStatic;
+} gmx_ana_indexmap_t;
+
+
+/*! \name Functions for handling gmx_ana_indexgrps_t
+ */
+/*@{*/
+/** Allocate memory for index groups. */
+void
+gmx_ana_indexgrps_alloc(gmx_ana_indexgrps_t **g, int ngrps);
+/** Initializes index groups from arrays. */
+void
+gmx_ana_indexgrps_set(gmx_ana_indexgrps_t **g, int ngrps, int *isize,
+                      atom_id **index, char **name, gmx_bool bFree);
+/** Reads index groups from a file or constructs them from topology. */
+void
+gmx_ana_indexgrps_init(gmx_ana_indexgrps_t **g, t_topology *top, 
+                       const char *fnm);
+/** Ask user to select index groups, possibly constructing groups from 
+ *  topology. */
+void
+gmx_ana_indexgrps_get(gmx_ana_indexgrps_t **g, t_topology *top, 
+                      const char *fnm, int ngrps);
+/** Ask user to select index groups from those specified in a file. */
+void
+gmx_ana_indexgrps_rd(gmx_ana_indexgrps_t **g, const char *fnm, int ngrps);
+/** Frees memory allocated for index groups. */
+void
+gmx_ana_indexgrps_free(gmx_ana_indexgrps_t *g);
+/** Create a deep copy of \c gmx_ana_indexgrps_t. */
+void
+gmx_ana_indexgrps_clone(gmx_ana_indexgrps_t **dest, gmx_ana_indexgrps_t *src);
+/** Returns TRUE if the index group structure is emtpy. */
+gmx_bool
+gmx_ana_indexgrps_is_empty(gmx_ana_indexgrps_t *g);
+
+/** Returns a pointer to an index group. */
+gmx_ana_index_t *
+gmx_ana_indexgrps_get_grp(gmx_ana_indexgrps_t *g, int n);
+/** Extracts a single index group. */
+gmx_bool
+gmx_ana_indexgrps_extract(gmx_ana_index_t *dest, gmx_ana_indexgrps_t *src, int n);
+/** Finds and extracts a single index group by name. */
+gmx_bool
+gmx_ana_indexgrps_find(gmx_ana_index_t *dest, gmx_ana_indexgrps_t *src, char *name);
+
+/** Writes out a list of index groups. */
+void
+gmx_ana_indexgrps_print(gmx_ana_indexgrps_t *g, int maxn);
+/*@}*/
+
+/*! \name Functions for handling gmx_ana_index_t
+ */
+/*@{*/
+/** Reserves memory to store an index group of size \p isize. */
+void
+gmx_ana_index_reserve(gmx_ana_index_t *g, int isize);
+/** Frees any memory not necessary to hold the current contents. */
+void
+gmx_ana_index_squeeze(gmx_ana_index_t *g);
+/** Initializes an empty index group. */
+void
+gmx_ana_index_clear(gmx_ana_index_t *g);
+/** Constructs a \c gmx_ana_index_t from given values. */
+void
+gmx_ana_index_set(gmx_ana_index_t *g, int isize, atom_id *index, char *name,
+                  int nalloc);
+/** Creates a simple index group from the first to the \p natoms'th atom. */
+void
+gmx_ana_index_init_simple(gmx_ana_index_t *g, int natoms, char *name);
+/** Frees memory allocated for an index group. */
+void
+gmx_ana_index_deinit(gmx_ana_index_t *g);
+/** Copies a \c gmx_ana_index_t. */
+void
+gmx_ana_index_copy(gmx_ana_index_t *dest, gmx_ana_index_t *src, gmx_bool bAlloc);
+
+/** Writes out the contents of a index group. */
+void
+gmx_ana_index_dump(gmx_ana_index_t *g, int i, int maxn);
+
+/** Checks whether all indices are between 0 and \p natoms. */
+void
+gmx_ana_index_check(gmx_ana_index_t *g, int natoms);
+/** Checks whether an index group is sorted. */
+gmx_bool
+gmx_ana_index_check_sorted(gmx_ana_index_t *g);
+/*@}*/
+
+/*! \name Functions for set operations on gmx_ana_index_t
+ */
+/*@{*/
+/** Sorts the indices within an index group. */
+void
+gmx_ana_index_sort(gmx_ana_index_t *g);
+/** Checks whether two index groups are equal. */
+gmx_bool
+gmx_ana_index_equals(gmx_ana_index_t *a, gmx_ana_index_t *b);
+/** Checks whether a sorted index group contains another sorted index group. */
+gmx_bool
+gmx_ana_index_contains(gmx_ana_index_t *a, gmx_ana_index_t *b);
+
+/** Calculates the intersection between two sorted index groups. */
+void
+gmx_ana_index_intersection(gmx_ana_index_t *dest,
+                           gmx_ana_index_t *a, gmx_ana_index_t *b);
+/** Calculates the set difference between two sorted index groups. */
+void
+gmx_ana_index_difference(gmx_ana_index_t *dest,
+                         gmx_ana_index_t *a, gmx_ana_index_t *b);
+/** Calculates the size of the difference between two sorted index groups. */
+int
+gmx_ana_index_difference_size(gmx_ana_index_t *a, gmx_ana_index_t *b);
+/** Calculates the union of two sorted index groups. */
+void
+gmx_ana_index_union(gmx_ana_index_t *dest,
+                    gmx_ana_index_t *a, gmx_ana_index_t *b);
+/** Merges two distinct sorted index groups. */
+void
+gmx_ana_index_merge(gmx_ana_index_t *dest,
+                    gmx_ana_index_t *a, gmx_ana_index_t *b);
+/** Calculates the intersection and the difference in one call. */
+void
+gmx_ana_index_partition(gmx_ana_index_t *dest1, gmx_ana_index_t *dest2,
+                        gmx_ana_index_t *src, gmx_ana_index_t *g);
+/*@}*/
+
+/*! \name Functions for handling gmx_ana_indexmap_t and related things
+ */
+/*@{*/
+/** Partition a group based on topology information. */
+void
+gmx_ana_index_make_block(t_blocka *t, t_topology *top, gmx_ana_index_t *g,
+                         e_index_t type, gmx_bool bComplete);
+/** Checks whether a group consists of full blocks. */
+gmx_bool
+gmx_ana_index_has_full_blocks(gmx_ana_index_t *g, t_block *b);
+/** Checks whether a group consists of full blocks. */
+gmx_bool
+gmx_ana_index_has_full_ablocks(gmx_ana_index_t *g, t_blocka *b);
+/** Checks whether a group consists of full residues/molecules. */
+gmx_bool
+gmx_ana_index_has_complete_elems(gmx_ana_index_t *g, e_index_t type, t_topology *top);
+
+/** Initializes an empty index group mapping. */
+void
+gmx_ana_indexmap_clear(gmx_ana_indexmap_t *m);
+/** Reserves memory for an index group mapping. */
+void
+gmx_ana_indexmap_reserve(gmx_ana_indexmap_t *m, int nr, int isize);
+/** Initializes an index group mapping. */
+void
+gmx_ana_indexmap_init(gmx_ana_indexmap_t *m, gmx_ana_index_t *g,
+                      t_topology *top, e_index_t type);
+/** Sets an index group mapping to be static. */
+void
+gmx_ana_indexmap_set_static(gmx_ana_indexmap_t *m, t_blocka *b);
+/** Frees memory allocated for index group mapping. */
+void
+gmx_ana_indexmap_deinit(gmx_ana_indexmap_t *m);
+/** Makes a deep copy of an index group mapping. */
+void
+gmx_ana_indexmap_copy(gmx_ana_indexmap_t *dest, gmx_ana_indexmap_t *src, gmx_bool bFirst);
+/** Updates an index group mapping. */
+void
+gmx_ana_indexmap_update(gmx_ana_indexmap_t *m, gmx_ana_index_t *g, gmx_bool bMaskOnly);
+/*@}*/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/gromacs/selection/keywords.h b/src/gromacs/selection/keywords.h
new file mode 100644 (file)
index 0000000..3e8e9ad
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief Definitions of generic keyword evaluation structures.
+ *
+ * This is an implementation header: there should be no need to use it outside
+ * this directory.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_selection
+ */
+#ifndef SELECTION_KEYWORDS_H
+#define SELECTION_KEYWORDS_H
+
+struct gmx_ana_selmethod_t;
+struct t_selelem;
+struct t_selexpr_param;
+
+/** Selection method data for comparison expression evaluation. */
+extern struct gmx_ana_selmethod_t sm_compare;
+
+/** Selection method data for integer keyword evaluation. */
+extern struct gmx_ana_selmethod_t sm_keyword_int;
+/** Selection method data for real keyword evaluation. */
+extern struct gmx_ana_selmethod_t sm_keyword_real;
+/** Selection method data for string keyword evaluation. */
+extern struct gmx_ana_selmethod_t sm_keyword_str;
+/** Selection method data for position keyword evaluation. */
+extern struct gmx_ana_selmethod_t sm_keyword_pos;
+
+/** Prints information about a comparison expression. */
+void
+_gmx_selelem_print_compare_info(FILE *fp, void *data);
+
+/** Sets the position type for position keyword evaluation. */
+void
+_gmx_selelem_set_kwpos_type(struct t_selelem *sel, const char *type);
+/** Sets the flags for position keyword evaluation. */
+void
+_gmx_selelem_set_kwpos_flags(struct t_selelem *sel, int flags);
+
+/** Does custom processing for parameters of the \c same selection method. */
+int
+_gmx_selelem_custom_init_same(struct gmx_ana_selmethod_t **method,
+                              struct t_selexpr_param *params, void *scanner);
+
+/** Initializes a selection element for evaluating a keyword in a given group. */
+int
+_gmx_sel_init_keyword_evaluator(struct t_selelem **sel,
+                                struct gmx_ana_selmethod_t *method,
+                                struct t_selexpr_param *param, void *scanner);
+
+#endif
diff --git a/src/gromacs/selection/mempool.cpp b/src/gromacs/selection/mempool.cpp
new file mode 100644 (file)
index 0000000..74a04cf
--- /dev/null
@@ -0,0 +1,231 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * Implements functions in mempool.h.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_selection
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <assert.h>
+#include <stdlib.h>
+
+#include <gmx_fatal.h>
+#include <smalloc.h>
+
+#include "gromacs/selection/indexutil.h"
+
+#include "mempool.h"
+
+//! Alignment in bytes for all returned blocks.
+#define ALIGN_STEP 8
+
+/*! \internal \brief
+ * Describes a single block allocated from the memory pool.
+ */
+typedef struct gmx_sel_mempool_block_t
+{
+    //! Pointer to the start of the block (as returned to the user).
+    void                       *ptr;
+    //! Size of the block, including padding required to align next block.
+    size_t                      size;
+} gmx_sel_mempool_block_t;
+
+/*! \internal \brief
+ * Describes a memory pool.
+ */
+struct gmx_sel_mempool_t
+{
+    //! Number of bytes currently allocated from the pool.
+    size_t                      currsize;
+    //! Number of bytes free in the pool, or 0 if \a buffer is NULL.
+    size_t                      freesize;
+    //! Memory area allocated for the pool, or NULL if not yet reserved.
+    char                       *buffer;
+    //! Pointer to the first free byte (aligned at ::ALIGN_STEP) in \a buffer.
+    char                       *freeptr;
+    //! Number of blocks allocated from the pool.
+    int                         nblocks;
+    //! Array describing the allocated blocks.
+    gmx_sel_mempool_block_t    *blockstack;
+    //! Number of elements allocated for the \a blockstack array.
+    int                         blockstack_nalloc;
+    /*! \brief
+     * Maximum number of bytes that have been reserved from the pool
+     * simultaneously.
+     */
+    size_t                      maxsize;
+};
+
+int
+_gmx_sel_mempool_create(gmx_sel_mempool_t **mpp)
+{
+    gmx_sel_mempool_t *mp;
+
+    snew(mp, 1);
+    mp->currsize          = 0;
+    mp->freesize          = 0;
+    mp->buffer            = NULL;
+    mp->freeptr           = NULL;
+    mp->nblocks           = 0;
+    mp->blockstack        = NULL;
+    mp->blockstack_nalloc = 0;
+    mp->maxsize           = 0;
+    *mpp = mp;
+    return 0;
+}
+
+void
+_gmx_sel_mempool_destroy(gmx_sel_mempool_t *mp)
+{
+    if (!mp->buffer)
+    {
+        int  i;
+
+        for (i = 0; i < mp->nblocks; ++i)
+        {
+            sfree(mp->blockstack[i].ptr);
+        }
+    }
+    sfree(mp->buffer);
+    sfree(mp->blockstack);
+    sfree(mp);
+}
+
+int
+_gmx_sel_mempool_alloc(gmx_sel_mempool_t *mp, void **ptrp, size_t size)
+{
+    void   *ptr = NULL;
+    size_t  size_walign;
+
+    *ptrp = NULL;
+    size_walign = ((size + ALIGN_STEP - 1) / ALIGN_STEP) * ALIGN_STEP;
+    if (mp->buffer)
+    {
+        if (mp->freesize < size)
+        {
+            gmx_bug("out of memory pool memory");
+            return ENOMEM;
+        }
+        ptr = mp->freeptr;
+        mp->freeptr  += size_walign;
+        mp->freesize -= size_walign;
+        mp->currsize += size_walign;
+    }
+    else
+    {
+        ptr = malloc(size);
+        if (!ptr)
+        {
+            gmx_mem("out of memory");
+            return ENOMEM;
+        }
+        mp->currsize += size_walign;
+        if (mp->currsize > mp->maxsize)
+        {
+            mp->maxsize = mp->currsize;
+        }
+    }
+
+    if (mp->nblocks >= mp->blockstack_nalloc)
+    {
+        mp->blockstack_nalloc = mp->nblocks + 10;
+        srenew(mp->blockstack, mp->blockstack_nalloc);
+    }
+    mp->blockstack[mp->nblocks].ptr  = ptr;
+    mp->blockstack[mp->nblocks].size = size_walign;
+    mp->nblocks++;
+
+    *ptrp = ptr;
+    return 0;
+}
+
+void
+_gmx_sel_mempool_free(gmx_sel_mempool_t *mp, void *ptr)
+{
+    int size;
+
+    if (ptr == NULL)
+    {
+        return;
+    }
+    assert(mp->nblocks > 0 && mp->blockstack[mp->nblocks - 1].ptr == ptr);
+    mp->nblocks--;
+    size = mp->blockstack[mp->nblocks].size;
+    mp->currsize -= size;
+    if (mp->buffer)
+    {
+        mp->freeptr = (char *)ptr;
+        mp->freesize += size;
+    }
+    else
+    {
+        sfree(ptr);
+    }
+}
+
+int
+_gmx_sel_mempool_reserve(gmx_sel_mempool_t *mp, size_t size)
+{
+    assert(mp->nblocks == 0 && !mp->buffer);
+    if (size == 0)
+    {
+        size = mp->maxsize;
+    }
+    mp->buffer = (char *)malloc(size);
+    if (!mp->buffer)
+    {
+        gmx_mem("out of memory");
+        return ENOMEM;
+    }
+    mp->freesize = size;
+    mp->freeptr  = mp->buffer;
+    return 0;
+}
+
+int
+_gmx_sel_mempool_alloc_group(gmx_sel_mempool_t *mp, gmx_ana_index_t *g,
+                             int isize)
+{
+    return _gmx_sel_mempool_alloc(mp, (void **)&g->index,
+                                  sizeof(*g->index)*isize);
+}
+
+void
+_gmx_sel_mempool_free_group(gmx_sel_mempool_t *mp, gmx_ana_index_t *g)
+{
+    _gmx_sel_mempool_free(mp, g->index);
+    g->index = NULL;
+}
diff --git a/src/gromacs/selection/mempool.h b/src/gromacs/selection/mempool.h
new file mode 100644 (file)
index 0000000..dfaa81a
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief Declarations for memory pooling functions.
+ *
+ * \todo
+ * Document these functions.
+ *
+ * This is an implementation header: there should be no need to use it outside
+ * this directory.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_selection
+ */
+#ifndef GMX_SELECTION_MEMPOOL_H
+#define GMX_SELECTION_MEMPOOL_H
+
+struct gmx_ana_index_t;
+
+/** Opaque struct for memory pooling. */
+typedef struct gmx_sel_mempool_t gmx_sel_mempool_t;
+
+/** Create an empty memory pool. */
+int
+_gmx_sel_mempool_create(gmx_sel_mempool_t **mpp);
+/** Destroy a memory pool. */
+void
+_gmx_sel_mempool_destroy(gmx_sel_mempool_t *mp);
+
+/** Allocate memory from a memory pool. */
+int
+_gmx_sel_mempool_alloc(gmx_sel_mempool_t *mp, void **ptrp, size_t size);
+/** Release memory allocated from a memory pool. */
+void
+_gmx_sel_mempool_free(gmx_sel_mempool_t *mp, void *ptr);
+/** Set the size of a memory pool. */
+int
+_gmx_sel_mempool_reserve(gmx_sel_mempool_t *mp, size_t size);
+
+/** Convenience function for allocating an index group from a memory pool. */
+int
+_gmx_sel_mempool_alloc_group(gmx_sel_mempool_t *mp, struct gmx_ana_index_t *g,
+                             int isize);
+/** Convenience function for freeing an index group from a memory pool. */
+void
+_gmx_sel_mempool_free_group(gmx_sel_mempool_t *mp, struct gmx_ana_index_t *g);
+
+#endif
diff --git a/src/gromacs/selection/nbsearch.cpp b/src/gromacs/selection/nbsearch.cpp
new file mode 100644 (file)
index 0000000..062c918
--- /dev/null
@@ -0,0 +1,796 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \page nbsearch Neighborhood search routines
+ *
+ * Functions to find particles within a neighborhood of a set of particles
+ * are defined in nbsearch.h.
+ * The usage is simple: a data structure is allocated with
+ * gmx_ana_nbsearch_create(), and the box shape and reference positions for a
+ * frame are set using gmx_ana_nbsearch_init() or gmx_ana_nbsearch_pos_init().
+ * Searches can then be performed with gmx_ana_nbsearch_is_within() and
+ * gmx_ana_nbsearch_mindist(), or with versions that take the \c gmx_ana_pos_t
+ * data structure.
+ * When the data structure is no longer required, it can be freed with
+ * gmx_ana_nbsearch_free().
+ *
+ * \internal
+ *
+ * \todo
+ * The grid implementation could still be optimized in several different ways:
+ *   - Triclinic grid cells are not the most efficient shape, but make PBC
+ *     handling easier.
+ *   - Precalculating the required PBC shift for a pair of cells outside the
+ *     inner loop. After this is done, it should be quite straightforward to
+ *     move to rectangular cells.
+ *   - Pruning grid cells from the search list if they are completely outside
+ *     the sphere that is being considered.
+ *   - A better heuristic could be added for falling back to simple loops for a
+ *     small number of reference particles.
+ *   - A better heuristic for selecting the grid size.
+ *   - A multi-level grid implementation could be used to be able to use small
+ *     grids for short cutoffs with very inhomogeneous particle distributions
+ *     without a memory cost.
+ */
+/*! \internal \file
+ * \brief
+ * Implements functions in nbsearch.h.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_selection
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <math.h>
+
+#include <smalloc.h>
+#include <typedefs.h>
+#include <pbc.h>
+#include <vec.h>
+
+#include "gromacs/selection/nbsearch.h"
+#include "gromacs/selection/position.h"
+
+/*! \internal \brief
+ * Data structure for neighborhood searches.
+ */
+struct gmx_ana_nbsearch_t
+{
+    /** The cutoff. */
+    real           cutoff;
+    /** The cutoff squared. */
+    real           cutoff2;
+    /** Maximum number of reference points. */
+    int            maxnref;
+
+    /** Number of reference points for the current frame. */
+    int            nref;
+    /** Reference point positions. */
+    rvec          *xref;
+    /** Reference position ids (NULL if not available). */
+    int           *refid;
+    /** PBC data. */
+    t_pbc         *pbc;
+
+    /** Number of excluded reference positions for current test particle. */
+    int            nexcl;
+    /** Exclusions for current test particle. */
+    int           *excl;
+
+    /** Whether to try grid searching. */
+    gmx_bool           bTryGrid;
+    /** Whether grid searching is actually used for the current positions. */
+    gmx_bool           bGrid;
+    /** Array allocated for storing in-unit-cell reference positions. */
+    rvec          *xref_alloc;
+    /** FALSE if the box is rectangular. */
+    gmx_bool           bTric;
+    /** Box vectors of a single grid cell. */
+    matrix         cellbox;
+    /** The reciprocal cell vectors as columns; the inverse of \p cellbox. */
+    matrix         recipcell;
+    /** Number of cells along each dimension. */
+    ivec           ncelldim;
+    /** Total number of cells. */
+    int            ncells;
+    /** Number of reference positions in each cell. */
+    int           *ncatoms;
+    /** List of reference positions in each cell. */
+    atom_id      **catom;
+    /** Allocation counts for each \p catom[i]. */
+    int           *catom_nalloc;
+    /** Allocation count for the per-cell arrays. */
+    int            cells_nalloc;
+    /** Number of neighboring cells to consider. */
+    int            ngridnb;
+    /** Offsets of the neighboring cells to consider. */
+    ivec          *gnboffs;
+    /** Allocation count for \p gnboffs. */
+    int            gnboffs_nalloc;
+
+    /** Stores test position during a pair loop. */
+    rvec           xtest;
+    /** Stores the previous returned position during a pair loop. */
+    int            previ;
+    /** Stores the current exclusion index during loops. */
+    int            exclind;
+    /** Stores the test particle cell index during loops. */
+    ivec           testcell;
+    /** Stores the current cell neighbor index during pair loops. */
+    int            prevnbi;
+    /** Stores the index within the current cell during pair loops. */
+    int            prevcai;
+};
+
+/*!
+ * \param[out] data   Neighborhood search data structure pointer to initialize.
+ * \param[in]  cutoff Cutoff distance for the search
+ *   (<=0 stands for no cutoff).
+ * \param[in]  maxn   Maximum number of reference particles.
+ * \returns    0 on success.
+ */
+int
+gmx_ana_nbsearch_create(gmx_ana_nbsearch_t **data, real cutoff, int maxn)
+{
+    gmx_ana_nbsearch_t *d;
+    
+    snew(d, 1);
+    d->bTryGrid = TRUE;
+    if (cutoff <= 0)
+    {
+        cutoff = HUGE_VAL;
+        d->bTryGrid = FALSE;
+    }
+    d->cutoff = cutoff;
+    d->cutoff2 = sqr(cutoff);
+    d->maxnref = maxn;
+
+    d->xref = NULL;
+    d->nexcl = 0;
+    d->exclind = 0;
+
+    d->xref_alloc = NULL;
+    d->ncells = 0;
+    d->ncatoms = NULL;
+    d->catom = NULL;
+    d->catom_nalloc = 0;
+    d->cells_nalloc = 0;
+
+    d->ngridnb = 0;
+    d->gnboffs = NULL;
+    d->gnboffs_nalloc = 0;
+
+    *data = d;
+    return 0;
+}
+
+/*!
+ * \param     d Data structure to free.
+ *
+ * After the call, the pointer \p d is no longer valid.
+ */
+void
+gmx_ana_nbsearch_free(gmx_ana_nbsearch_t *d)
+{
+    sfree(d->xref_alloc);
+    sfree(d->ncatoms);
+    if (d->catom)
+    {
+        int ci;
+
+        for (ci = 0; ci < d->ncells; ++ci)
+        {
+            sfree(d->catom[ci]);
+        }
+        sfree(d->catom);
+    }
+    sfree(d->catom_nalloc);
+    sfree(d->gnboffs);
+    sfree(d);
+}
+
+/*! \brief
+ * Calculates offsets to neighboring grid cells that should be considered.
+ *
+ * \param[in,out] d    Grid information.
+ * \param[in]     pbc  Information about the box.
+ */
+static void
+grid_init_cell_nblist(gmx_ana_nbsearch_t *d, t_pbc *pbc)
+{
+    int   maxx, maxy, maxz;
+    int   x, y, z, i;
+    real  rvnorm;
+
+    /* Find the extent of the sphere in triclinic coordinates */
+    maxz = (int)(d->cutoff * d->recipcell[ZZ][ZZ]) + 1;
+    rvnorm = sqrt(sqr(d->recipcell[YY][YY]) + sqr(d->recipcell[ZZ][YY]));
+    maxy = (int)(d->cutoff * rvnorm) + 1;
+    rvnorm = sqrt(sqr(d->recipcell[XX][XX]) + sqr(d->recipcell[YY][XX])
+                  + sqr(d->recipcell[ZZ][XX]));
+    maxx = (int)(d->cutoff * rvnorm) + 1;
+
+    /* Calculate the number of cells and reallocate if necessary */
+    d->ngridnb = (2 * maxx + 1) * (2 * maxy + 1) * (2 * maxz + 1);
+    if (d->gnboffs_nalloc < d->ngridnb)
+    {
+        d->gnboffs_nalloc = d->ngridnb;
+        srenew(d->gnboffs, d->gnboffs_nalloc);
+    }
+
+    /* Store the whole cube */
+    /* TODO: Prune off corners that are not needed */
+    i = 0;
+    for (x = -maxx; x <= maxx; ++x)
+    {
+        for (y = -maxy; y <= maxy; ++y)
+        {
+            for (z = -maxz; z <= maxz; ++z)
+            {
+                d->gnboffs[i][XX] = x;
+                d->gnboffs[i][YY] = y;
+                d->gnboffs[i][ZZ] = z;
+                ++i;
+            }
+        }
+    }
+}
+
+/*! \brief
+ * Determines a suitable grid size.
+ *
+ * \param[in,out] d    Grid information.
+ * \param[in]     pbc  Information about the box.
+ * \returns  FALSE if grid search is not suitable.
+ */
+static gmx_bool
+grid_setup_cells(gmx_ana_nbsearch_t *d, t_pbc *pbc)
+{
+    real targetsize;
+    int  dd;
+
+#ifdef HAVE_CBRT
+    targetsize = cbrt(pbc->box[XX][XX] * pbc->box[YY][YY] * pbc->box[ZZ][ZZ]
+                      * 10 / d->nref);
+#else
+    targetsize = pow(pbc->box[XX][XX] * pbc->box[YY][YY] * pbc->box[ZZ][ZZ]
+                      * 10 / d->nref, 1./3.);
+#endif
+
+    d->ncells = 1;
+    for (dd = 0; dd < DIM; ++dd)
+    {
+        d->ncelldim[dd] = (int)(pbc->box[dd][dd] / targetsize);
+        d->ncells *= d->ncelldim[dd];
+        if (d->ncelldim[dd] < 3)
+        {
+            return FALSE;
+        }
+    }
+    /* Reallocate if necessary */
+    if (d->cells_nalloc < d->ncells)
+    {
+        int  i;
+
+        srenew(d->ncatoms, d->ncells);
+        srenew(d->catom, d->ncells);
+        srenew(d->catom_nalloc, d->ncells);
+        for (i = d->cells_nalloc; i < d->ncells; ++i)
+        {
+            d->catom[i] = NULL;
+            d->catom_nalloc[i] = 0;
+        }
+        d->cells_nalloc = d->ncells;
+    }
+    return TRUE;
+}
+
+/*! \brief
+ * Sets ua a search grid for a given box.
+ *
+ * \param[in,out] d    Grid information.
+ * \param[in]     pbc  Information about the box.
+ * \returns  FALSE if grid search is not suitable.
+ */
+static gmx_bool
+grid_set_box(gmx_ana_nbsearch_t *d, t_pbc *pbc)
+{
+    int dd;
+
+    /* TODO: This check could be improved. */
+    if (0.5*pbc->max_cutoff2 < d->cutoff2)
+    {
+        return FALSE;
+    }
+
+    if (!grid_setup_cells(d, pbc))
+    {
+        return FALSE;
+    }
+
+    d->bTric = TRICLINIC(pbc->box);
+    if (d->bTric)
+    {
+        for (dd = 0; dd < DIM; ++dd)
+        {
+            svmul(1.0 / d->ncelldim[dd], pbc->box[dd], d->cellbox[dd]);
+        }
+        m_inv_ur0(d->cellbox, d->recipcell);
+    }
+    else
+    {
+        for (dd = 0; dd < DIM; ++dd)
+        {
+            d->cellbox[dd][dd] = pbc->box[dd][dd] / d->ncelldim[dd];
+            d->recipcell[dd][dd] = 1 / d->cellbox[dd][dd];
+        }
+    }
+    grid_init_cell_nblist(d, pbc);
+    return TRUE;
+}
+
+/*! \brief
+ * Maps a point into a grid cell.
+ *
+ * \param[in]  d    Grid information.
+ * \param[in]  x    Point to map.
+ * \param[out] cell Indices of the grid cell in which \p x lies.
+ *
+ * \p x should be in the triclinic unit cell.
+ */
+static void
+grid_map_onto(gmx_ana_nbsearch_t *d, const rvec x, ivec cell)
+{
+    int dd;
+
+    if (d->bTric)
+    {
+        rvec tx;
+
+        tmvmul_ur0(d->recipcell, x, tx);
+        for (dd = 0; dd < DIM; ++dd)
+        {
+            cell[dd] = (int)tx[dd];
+        }
+    }
+    else
+    {
+        for (dd = 0; dd < DIM; ++dd)
+        {
+            cell[dd] = (int)(x[dd] * d->recipcell[dd][dd]);
+        }
+    }
+}
+
+/*! \brief
+ * Calculates linear index of a grid cell.
+ *
+ * \param[in]  d    Grid information.
+ * \param[in]  cell Cell indices.
+ * \returns    Linear index of \p cell.
+ */
+static int
+grid_index(gmx_ana_nbsearch_t *d, const ivec cell)
+{
+    return cell[XX] + cell[YY] * d->ncelldim[XX]
+        + cell[ZZ] * d->ncelldim[XX] * d->ncelldim[YY];
+}
+
+/*! \brief
+ * Clears all grid cells.
+ *
+ * \param[in,out] d    Grid information.
+ */
+static void
+grid_clear_cells(gmx_ana_nbsearch_t *d)
+{
+    int  ci;
+
+    for (ci = 0; ci < d->ncells; ++ci)
+    {
+        d->ncatoms[ci] = 0;
+    }
+}
+
+/*! \brief
+ * Adds an index into a grid cell.
+ *
+ * \param[in,out] d    Grid information.
+ * \param[in]     cell Cell into which \p i should be added.
+ * \param[in]     i    Index to add.
+ */
+static void
+grid_add_to_cell(gmx_ana_nbsearch_t *d, const ivec cell, int i)
+{
+    int ci = grid_index(d, cell);
+
+    if (d->ncatoms[ci] == d->catom_nalloc[ci])
+    {
+        d->catom_nalloc[ci] += 10;
+        srenew(d->catom[ci], d->catom_nalloc[ci]);
+    }
+    d->catom[ci][d->ncatoms[ci]++] = i;
+}
+
+/*!
+ * \param[in,out] d   Neighborhood search data structure.
+ * \param[in]     pbc PBC information for the frame.
+ * \param[in]     n   Number of reference positions for the frame.
+ * \param[in]     x   \p n reference positions for the frame.
+ * \returns       0 on success.
+ *
+ * Initializes the data structure \p d such that it can be used to search
+ * for the neighbors of \p x.
+ */
+int
+gmx_ana_nbsearch_init(gmx_ana_nbsearch_t *d, t_pbc *pbc, int n, rvec x[])
+{
+    d->pbc  = pbc;
+    d->nref = n;
+    if (!pbc)
+    {
+        d->bGrid = FALSE;
+    }
+    else if (d->bTryGrid)
+    {
+        d->bGrid = grid_set_box(d, pbc);
+    }
+    if (d->bGrid)
+    {
+        int  i;
+
+        if (!d->xref_alloc)
+        {
+            snew(d->xref_alloc, d->maxnref);
+        }
+        d->xref = d->xref_alloc;
+        grid_clear_cells(d);
+
+        for (i = 0; i < n; ++i)
+        {
+            copy_rvec(x[i], d->xref[i]);
+        }
+        put_atoms_in_triclinic_unitcell(ecenterTRIC, pbc->box, n, d->xref);
+        for (i = 0; i < n; ++i)
+        {
+            ivec refcell;
+
+            grid_map_onto(d, d->xref[i], refcell);
+            grid_add_to_cell(d, refcell, i);
+        }
+    }
+    else
+    {
+        d->xref = x;
+    }
+    d->refid = NULL;
+    return 0;
+}
+
+/*!
+ * \param[in,out] d   Neighborhood search data structure.
+ * \param[in]     pbc PBC information for the frame.
+ * \param[in]     p   Reference positions for the frame.
+ * \returns       0 on success.
+ *
+ * A convenience wrapper for gmx_ana_nbsearch_init().
+ */
+int
+gmx_ana_nbsearch_pos_init(gmx_ana_nbsearch_t *d, t_pbc *pbc, gmx_ana_pos_t *p)
+{
+    int rc;
+
+    rc = gmx_ana_nbsearch_init(d, pbc, p->nr, p->x);
+    d->refid = (p->nr < d->maxnref ? p->m.refid : NULL);
+    return rc;
+}
+
+/*!
+ * \param[in,out] d     Neighborhood search data structure.
+ * \param[in]     nexcl Number of reference positions to exclude from next
+ *      search.
+ * \param[in]     excl  Indices of reference positions to exclude.
+ * \returns       0 on success.
+ *
+ * The set exclusions remain in effect until the next call of this function.
+ */
+int
+gmx_ana_nbsearch_set_excl(gmx_ana_nbsearch_t *d, int nexcl, int excl[])
+{
+
+    d->nexcl = nexcl;
+    d->excl = excl;
+    return 0;
+}
+
+/*! \brief
+ * Helper function to check whether a reference point should be excluded.
+ */
+static gmx_bool
+is_excluded(gmx_ana_nbsearch_t *d, int j)
+{
+    if (d->exclind < d->nexcl)
+    {
+        if (d->refid)
+        {
+            while (d->exclind < d->nexcl && d->refid[j] > d->excl[d->exclind])
+            {
+                ++d->exclind;
+            }
+            if (d->exclind < d->nexcl && d->refid[j] == d->excl[d->exclind])
+            {
+                ++d->exclind;
+                return TRUE;
+            }
+        }
+        else
+        {
+            while (d->bGrid && d->exclind < d->nexcl && d->excl[d->exclind] < j)
+            {
+                ++d->exclind;
+            }
+            if (d->excl[d->exclind] == j)
+            {
+                ++d->exclind;
+                return TRUE;
+            }
+        }
+    }
+    return FALSE;
+}
+
+/*! \brief
+ * Initializes a grid search to find reference positions neighboring \p x.
+ */
+static void
+grid_search_start(gmx_ana_nbsearch_t *d, rvec x)
+{
+    copy_rvec(x, d->xtest);
+    if (d->bGrid)
+    {
+        put_atoms_in_triclinic_unitcell(ecenterTRIC, d->pbc->box, 1, &d->xtest);
+        grid_map_onto(d, d->xtest, d->testcell);
+        d->prevnbi = 0;
+        d->prevcai = -1;
+    }
+    else
+    {
+        d->previ = -1;
+    }
+    d->exclind = 0;
+}
+
+/*! \brief
+ * Does a grid search.
+ */
+static gmx_bool
+grid_search(gmx_ana_nbsearch_t *d,
+            gmx_bool (*action)(gmx_ana_nbsearch_t *d, int i, real r2))
+{
+    int  i;
+    rvec dx;
+    real r2;
+
+    if (d->bGrid)
+    {
+        int  nbi, ci, cai;
+
+        nbi = d->prevnbi;
+        cai = d->prevcai + 1;
+
+        for ( ; nbi < d->ngridnb; ++nbi)
+        {
+            ivec cell;
+
+            ivec_add(d->testcell, d->gnboffs[nbi], cell);
+            /* TODO: Support for 2D and screw PBC */
+            cell[XX] = (cell[XX] + d->ncelldim[XX]) % d->ncelldim[XX];
+            cell[YY] = (cell[YY] + d->ncelldim[YY]) % d->ncelldim[YY];
+            cell[ZZ] = (cell[ZZ] + d->ncelldim[ZZ]) % d->ncelldim[ZZ];
+            ci = grid_index(d, cell);
+            /* TODO: Calculate the required PBC shift outside the inner loop */
+            for ( ; cai < d->ncatoms[ci]; ++cai)
+            {
+                i = d->catom[ci][cai];
+                if (is_excluded(d, i))
+                {
+                    continue;
+                }
+                pbc_dx_aiuc(d->pbc, d->xtest, d->xref[i], dx);
+                r2 = norm2(dx);
+                if (r2 <= d->cutoff2)
+                {
+                    if (action(d, i, r2))
+                    {
+                        d->prevnbi = nbi;
+                        d->prevcai = cai;
+                        d->previ   = i;
+                        return TRUE;
+                    }
+                }
+            }
+            d->exclind = 0;
+            cai = 0;
+        }
+    }
+    else
+    {
+        i = d->previ + 1;
+        for ( ; i < d->nref; ++i)
+        {
+            if (is_excluded(d, i))
+            {
+                continue;
+            }
+            if (d->pbc)
+            {
+                pbc_dx(d->pbc, d->xtest, d->xref[i], dx);
+            }
+            else
+            {
+                rvec_sub(d->xtest, d->xref[i], dx);
+            }
+            r2 = norm2(dx);
+            if (r2 <= d->cutoff2)
+            {
+                if (action(d, i, r2))
+                {
+                    d->previ = i;
+                    return TRUE;
+                }
+            }
+        }
+    }
+    return FALSE;
+}
+
+/*! \brief
+ * Helper function to use with grid_search() to find the next neighbor.
+ *
+ * Simply breaks the loop on the first found neighbor.
+ */
+static gmx_bool
+within_action(gmx_ana_nbsearch_t *d, int i, real r2)
+{
+    return TRUE;
+}
+
+/*! \brief
+ * Helper function to use with grid_search() to find the minimum distance.
+ */
+static gmx_bool
+mindist_action(gmx_ana_nbsearch_t *d, int i, real r2)
+{
+    d->cutoff2 = r2;
+    return FALSE;
+}
+
+/*!
+ * \param[in] d   Neighborhood search data structure.
+ * \param[in] x   Test position.
+ * \returns   TRUE if \p x is within the cutoff of any reference position,
+ *   FALSE otherwise.
+ */
+gmx_bool
+gmx_ana_nbsearch_is_within(gmx_ana_nbsearch_t *d, rvec x)
+{
+    grid_search_start(d, x);
+    return grid_search(d, &within_action);
+}
+
+/*!
+ * \param[in] d   Neighborhood search data structure.
+ * \param[in] p   Test positions.
+ * \param[in] i   Use the i'th position in \p p for testing.
+ * \returns   TRUE if the test position is within the cutoff of any reference
+ *   position, FALSE otherwise.
+ */
+gmx_bool
+gmx_ana_nbsearch_pos_is_within(gmx_ana_nbsearch_t *d, gmx_ana_pos_t *p, int i)
+{
+    return gmx_ana_nbsearch_is_within(d, p->x[i]);
+}
+
+/*!
+ * \param[in] d   Neighborhood search data structure.
+ * \param[in] x   Test position.
+ * \returns   The distance to the nearest reference position, or the cutoff
+ *   value if there are no reference positions within the cutoff.
+ */
+real
+gmx_ana_nbsearch_mindist(gmx_ana_nbsearch_t *d, rvec x)
+{
+    real mind;
+
+    grid_search_start(d, x);
+    grid_search(d, &mindist_action);
+    mind = sqrt(d->cutoff2);
+    d->cutoff2 = sqr(d->cutoff);
+    return mind;
+}
+
+/*!
+ * \param[in] d   Neighborhood search data structure.
+ * \param[in] p   Test positions.
+ * \param[in] i   Use the i'th position in \p p for testing.
+ * \returns   The distance to the nearest reference position, or the cutoff
+ *   value if there are no reference positions within the cutoff.
+ */
+real
+gmx_ana_nbsearch_pos_mindist(gmx_ana_nbsearch_t *d, gmx_ana_pos_t *p, int i)
+{
+    return gmx_ana_nbsearch_mindist(d, p->x[i]);
+}
+
+/*!
+ * \param[in]  d   Neighborhood search data structure.
+ * \param[in]  x   Test positions.
+ * \param[out] jp  Index of the reference position in the first pair.
+ * \returns    TRUE if there are positions within the cutoff.
+ */
+gmx_bool
+gmx_ana_nbsearch_first_within(gmx_ana_nbsearch_t *d, rvec x, int *jp)
+{
+    grid_search_start(d, x);
+    return gmx_ana_nbsearch_next_within(d, jp);
+}
+
+/*!
+ * \param[in]  d   Neighborhood search data structure.
+ * \param[in]  p   Test positions.
+ * \param[in]  i   Use the i'th position in \p p.
+ * \param[out] jp  Index of the reference position in the first pair.
+ * \returns    TRUE if there are positions within the cutoff.
+ */
+gmx_bool
+gmx_ana_nbsearch_pos_first_within(gmx_ana_nbsearch_t *d, gmx_ana_pos_t *p,
+                                  int i, int *jp)
+{
+    return gmx_ana_nbsearch_first_within(d, p->x[i], jp);
+}
+
+/*!
+ * \param[in]  d   Neighborhood search data structure.
+ * \param[out] jp  Index of the test position in the next pair.
+ * \returns    TRUE if there are positions within the cutoff.
+ */
+gmx_bool
+gmx_ana_nbsearch_next_within(gmx_ana_nbsearch_t *d, int *jp)
+{
+    if (grid_search(d, &within_action))
+    {
+        *jp = d->previ;
+        return TRUE;
+    }
+    *jp = -1;
+    return FALSE;
+}
diff --git a/src/gromacs/selection/nbsearch.h b/src/gromacs/selection/nbsearch.h
new file mode 100644 (file)
index 0000000..b8500b6
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \file
+ * \brief API for neighborhood searching.
+ *
+ * The API is documented in more detail on a separate page:
+ * \ref nbsearch
+ *
+ * The functions within this file can be used independently of the other parts
+ * of the library.
+ * The library also uses the functions internally.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_selection
+ */
+#ifndef GMX_SELECTION_NBSEARCH_H
+#define GMX_SELECTION_NBSEARCH_H
+
+#include "../legacyheaders/typedefs.h"
+
+#include "indexutil.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct gmx_ana_pos_t;
+
+/** Data structure for neighborhood searches. */
+typedef struct gmx_ana_nbsearch_t gmx_ana_nbsearch_t;
+
+/** Create a new neighborhood search data structure. */
+int
+gmx_ana_nbsearch_create(gmx_ana_nbsearch_t **d, real cutoff, int maxn);
+/** Free memory allocated for neighborhood search. */
+void
+gmx_ana_nbsearch_free(gmx_ana_nbsearch_t *d);
+
+/** Initializes neighborhood search for a new frame. */
+int
+gmx_ana_nbsearch_init(gmx_ana_nbsearch_t *d, t_pbc *pbc, int n, rvec x[]);
+/** Initializes neighborhood search for a frame using \c gmx_ana_pos_t.  */
+int
+gmx_ana_nbsearch_pos_init(gmx_ana_nbsearch_t *d, t_pbc *pbc,
+                          struct gmx_ana_pos_t *p);
+/** Sets the exclusions for the next neighborhood search. */
+int
+gmx_ana_nbsearch_set_excl(gmx_ana_nbsearch_t *d, int nexcl, int excl[]);
+/** Check whether a point is within a neighborhood. */
+gmx_bool
+gmx_ana_nbsearch_is_within(gmx_ana_nbsearch_t *d, rvec x);
+/** Check whether a position is within a neighborhood. */
+gmx_bool
+gmx_ana_nbsearch_pos_is_within(gmx_ana_nbsearch_t *d,
+                               struct gmx_ana_pos_t *p, int i);
+/** Calculates the minimun distance from the reference points. */
+real
+gmx_ana_nbsearch_mindist(gmx_ana_nbsearch_t *d, rvec x);
+/** Calculates the minimun distance from the reference points. */
+real
+gmx_ana_nbsearch_pos_mindist(gmx_ana_nbsearch_t *d,
+                             struct gmx_ana_pos_t *p, int i);
+/** Finds the first reference position within the cutoff. */
+gmx_bool
+gmx_ana_nbsearch_first_within(gmx_ana_nbsearch_t *d, rvec x, int *jp);
+/** Finds the first reference position within the cutoff. */
+gmx_bool
+gmx_ana_nbsearch_pos_first_within(gmx_ana_nbsearch_t *d,
+                                  struct gmx_ana_pos_t *p, int i, int *jp);
+/** Finds the next reference position within the cutoff. */
+gmx_bool
+gmx_ana_nbsearch_next_within(gmx_ana_nbsearch_t *d, int *jp);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/gromacs/selection/params.cpp b/src/gromacs/selection/params.cpp
new file mode 100644 (file)
index 0000000..fabbc0b
--- /dev/null
@@ -0,0 +1,1285 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * Implements functions in selparam.h.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_selection
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <smalloc.h>
+#include <string2.h>
+#include <vec.h>
+
+#include "gromacs/errorreporting/errorcontext.h"
+#include "gromacs/fatalerror/fatalerror.h"
+#include "gromacs/selection/position.h"
+#include "gromacs/selection/selmethod.h"
+#include "gromacs/selection/selparam.h"
+
+#include "parsetree.h"
+#include "position.h"
+#include "scanner.h"
+#include "selelem.h"
+
+template <typename T>
+static T min(T a, T b)
+{
+    return (a < b) ? a : b;
+}
+
+template <typename T>
+static T max(T a, T b)
+{
+    return (a > b) ? a : b;
+}
+
+/*!
+ * \param[in] name   Name of the parameter to search.
+ * \param[in] nparam Number of parameters in the \p param array.
+ * \param[in] param  Parameter array to search.
+ * \returns   Pointer to the parameter in the \p param
+ *   or NULL if no parameter with name \p name was found.
+ *
+ * The comparison is case-sensitive.
+ */
+gmx_ana_selparam_t *
+gmx_ana_selparam_find(const char *name, int nparam, gmx_ana_selparam_t *param)
+{
+    int                i;
+
+    if (nparam == 0)
+    {
+        return NULL;
+    }
+    /* Find the first non-null parameter */
+    i = 0;
+    while (i < nparam && param[i].name == NULL)
+    {
+        ++i;
+    }
+    /* Process the special case of a NULL parameter */
+    if (name == NULL)
+    {
+        return (i == 0) ? NULL : &param[i-1];
+    }
+    for ( ; i < nparam; ++i)
+    {
+        if (!strcmp(param[i].name, name))
+        {
+            return &param[i];
+        }
+        /* Check for 'no' prefix on gmx_boolean parameters */
+        if (param[i].val.type == NO_VALUE
+            && strlen(name) > 2 && name[0] == 'n' && name[1] == 'o'
+            && !strcmp(param[i].name, name+2))
+        {
+            return &param[i];
+        }
+    }
+    return NULL;
+}
+
+/*! \brief
+ * Does a type conversion on a \c t_selexpr_value.
+ *
+ * \param[in,out] value    Value to convert.
+ * \param[in]     type     Type to convert to.
+ * \param[in]     scanner  Scanner data structure.
+ * \returns       0 on success, a non-zero value on error.
+ */
+static int
+convert_value(t_selexpr_value *value, e_selvalue_t type, void *scanner)
+{
+    if (value->type == type || type == NO_VALUE)
+    {
+        return 0;
+    }
+    if (value->bExpr)
+    {
+        /* Conversion from atom selection to position using default
+         * reference positions. */
+        if (value->type == GROUP_VALUE && type == POS_VALUE)
+        {
+            value->u.expr =
+                _gmx_sel_init_position(value->u.expr, NULL, scanner);
+            if (value->u.expr == NULL)
+            {
+                return -1;
+            }
+            value->type = type;
+            return 0;
+        }
+        return -1;
+    }
+    else
+    {
+        /* Integers to floating point are easy */
+        if (value->type == INT_VALUE && type == REAL_VALUE)
+        {
+            value->u.r.r1 = (real)value->u.i.i1;
+            value->u.r.r2 = (real)value->u.i.i2;
+            value->type = type;
+            return 0;
+        }
+        /* Reals that are integer-valued can also be converted */
+        if (value->type == REAL_VALUE && type == INT_VALUE
+            && gmx_within_tol(value->u.r.r1, (int)value->u.r.r1, GMX_REAL_EPS)
+            && gmx_within_tol(value->u.r.r2, (int)value->u.r.r2, GMX_REAL_EPS))
+        {
+            value->u.i.i1 = (int)value->u.r.r1;
+            value->u.i.i2 = (int)value->u.r.r2;
+            value->type = type;
+            return 0;
+        }
+    }
+    return -1;
+}
+
+/*! \brief
+ * Does a type conversion on a list of values.
+ *
+ * \param[in,out] values   Values to convert.
+ * \param[in]     type     Type to convert to.
+ * \param[in]     scanner  Scanner data structure.
+ * \returns       0 on success, a non-zero value on error.
+ */
+static int
+convert_values(t_selexpr_value *values, e_selvalue_t type, void *scanner)
+{
+    t_selexpr_value *value;
+    int              rc, rc1;
+
+    rc = 0;
+    value = values;
+    while (value)
+    {
+        rc1 = convert_value(value, type, scanner);
+        if (rc1 != 0 && rc == 0)
+        {
+            rc = rc1;
+        }
+        value = value->next;
+    }
+    /* FIXME: More informative error messages */
+    return rc;
+}
+
+/*! \brief
+ * Adds a child element for a parameter, keeping the parameter order.
+ *
+ * \param[in,out] root  Root element to which the child is added.
+ * \param[in]     child Child to add.
+ * \param[in]     param Parameter for which this child is a value.
+ *
+ * Puts \p child in the child list of \p root such that the list remains
+ * in the same order as the corresponding parameters.
+ */
+static void
+place_child(t_selelem *root, t_selelem *child, gmx_ana_selparam_t *param)
+{
+    gmx_ana_selparam_t *ps;
+    int                 n;
+
+    ps = root->u.expr.method->param;
+    n  = param - ps;
+    /* Put the child element in the correct place */
+    if (!root->child || n < root->child->u.param - ps)
+    {
+        child->next = root->child;
+        root->child = child;
+    }
+    else
+    {
+        t_selelem *prev;
+
+        prev = root->child;
+        while (prev->next && prev->next->u.param - ps >= n)
+        {
+            prev = prev->next;
+        }
+        child->next = prev->next;
+        prev->next  = child;
+    }
+}
+
+/*! \brief
+ * Comparison function for sorting integer ranges.
+ * 
+ * \param[in] a Pointer to the first range.
+ * \param[in] b Pointer to the second range.
+ * \returns   -1, 0, or 1 depending on the relative order of \p a and \p b.
+ *
+ * The ranges are primarily sorted based on their starting point, and
+ * secondarily based on length (longer ranges come first).
+ */
+static int
+cmp_int_range(const void *a, const void *b)
+{
+    if (((int *)a)[0] < ((int *)b)[0])
+    {
+        return -1;
+    }
+    if (((int *)a)[0] > ((int *)b)[0])
+    {
+        return 1;
+    }
+    if (((int *)a)[1] > ((int *)b)[1])
+    {
+        return -1;
+    }
+    return 0;
+}
+
+/*! \brief
+ * Comparison function for sorting real ranges.
+ *
+ * \param[in] a Pointer to the first range.
+ * \param[in] b Pointer to the second range.
+ * \returns   -1, 0, or 1 depending on the relative order of \p a and \p b.
+ *
+ * The ranges are primarily sorted based on their starting point, and
+ * secondarily based on length (longer ranges come first).
+ */
+static int
+cmp_real_range(const void *a, const void *b)
+{
+    if (((real *)a)[0] < ((real *)b)[0])
+    {
+        return -1;
+    }
+    if (((real *)a)[0] > ((real *)b)[0])
+    {
+        return 1;
+    }
+    if (((real *)a)[1] > ((real *)b)[1])
+    {
+        return -1;
+    }
+    return 0;
+}
+
+/*! \brief
+ * Parses the values for a parameter that takes integer or real ranges.
+ * 
+ * \param[in] nval   Number of values in \p values.
+ * \param[in] values Pointer to the list of values.
+ * \param     param  Parameter to parse.
+ * \param[in] scanner Scanner data structure.
+ * \returns   TRUE if the values were parsed successfully, FALSE otherwise.
+ */
+static gmx_bool
+parse_values_range(int nval, t_selexpr_value *values, gmx_ana_selparam_t *param,
+                   void *scanner)
+{
+    t_selexpr_value    *value;
+    int                *idata;
+    real               *rdata;
+    int                 i, j, n;
+
+    param->flags &= ~SPAR_DYNAMIC;
+    if (param->val.type != INT_VALUE && param->val.type != REAL_VALUE)
+    {
+        GMX_ERROR_NORET(gmx::eeInternalError, "Invalid range parameter type");
+        return FALSE;
+    }
+    idata = NULL;
+    rdata = NULL;
+    if (param->val.type == INT_VALUE)
+    {
+        snew(idata, nval*2);
+    }
+    else
+    {
+        snew(rdata, nval*2);
+    }
+    value = values;
+    i = 0;
+    while (value)
+    {
+        if (value->bExpr)
+        {
+            _gmx_selparser_error(scanner, "expressions not supported within range parameters");
+            return FALSE;
+        }
+        if (value->type != param->val.type)
+        {
+            GMX_ERROR_NORET(gmx::eeInternalError, "Invalid range value type");
+            return FALSE;
+        }
+        if (param->val.type == INT_VALUE)
+        {
+            /* Make sure the input range is in increasing order */
+            if (value->u.i.i1 > value->u.i.i2)
+            {
+                int tmp       = value->u.i.i1;
+                value->u.i.i1 = value->u.i.i2;
+                value->u.i.i2 = tmp;
+            }
+            /* Check if the new range overlaps or extends the previous one */
+            if (i > 0 && value->u.i.i1 <= idata[i-1]+1 && value->u.i.i2 >= idata[i-2]-1)
+            {
+                idata[i-2] = min(idata[i-2], value->u.i.i1);
+                idata[i-1] = max(idata[i-1], value->u.i.i2);
+            }
+            else
+            {
+                idata[i++] = value->u.i.i1;
+                idata[i++] = value->u.i.i2;
+            }
+        }
+        else
+        {
+            /* Make sure the input range is in increasing order */
+            if (value->u.r.r1 > value->u.r.r2)
+            {
+                real tmp      = value->u.r.r1;
+                value->u.r.r1 = value->u.r.r2;
+                value->u.r.r2 = tmp;
+            }
+            /* Check if the new range overlaps or extends the previous one */
+            if (i > 0 && value->u.r.r1 <= rdata[i-1] && value->u.r.r2 >= rdata[i-2])
+            {
+                rdata[i-2] = min(rdata[i-2], value->u.r.r1);
+                rdata[i-1] = max(rdata[i-1], value->u.r.r2);
+            }
+            else
+            {
+                rdata[i++] = value->u.r.r1;
+                rdata[i++] = value->u.r.r2;
+            }
+        }
+        value = value->next;
+    }
+    n = i/2;
+    /* Sort the ranges and merge consequent ones */
+    if (param->val.type == INT_VALUE)
+    {
+        qsort(idata, n, 2*sizeof(int), &cmp_int_range);
+        for (i = j = 2; i < 2*n; i += 2)
+        {
+            if (idata[j-1]+1 >= idata[i])
+            {
+                if (idata[i+1] > idata[j-1])
+                {
+                    idata[j-1] = idata[i+1];
+                }
+            }
+            else
+            {
+                idata[j]   = idata[i];
+                idata[j+1] = idata[i+1];
+                j += 2;
+            }
+        }
+    }
+    else
+    {
+        qsort(rdata, n, 2*sizeof(real), &cmp_real_range);
+        for (i = j = 2; i < 2*n; i += 2)
+        {
+            if (rdata[j-1]+1 >= rdata[i])
+            {
+                if (rdata[i+1] > rdata[j-1])
+                {
+                    rdata[j-1] = rdata[i+1];
+                }
+            }
+            else
+            {
+                rdata[j]   = rdata[i];
+                rdata[j+1] = rdata[i+1];
+                j += 2;
+            }
+        }
+    }
+    n = j/2;
+    /* Store the values */
+    if (param->flags & SPAR_VARNUM)
+    {
+        param->val.nr  = n;
+        if (param->val.type == INT_VALUE)
+        {
+            srenew(idata, j);
+            _gmx_selvalue_setstore_alloc(&param->val, idata, j);
+        }
+        else
+        {
+            srenew(rdata, j);
+            _gmx_selvalue_setstore_alloc(&param->val, rdata, j);
+        }
+    }
+    else
+    {
+        if (n != param->val.nr)
+        {
+            _gmx_selparser_error(scanner, "the value should consist of exactly one range");
+            sfree(idata);
+            sfree(rdata);
+            return FALSE;
+        }
+        if (param->val.type == INT_VALUE)
+        {
+            memcpy(param->val.u.i, idata, 2*n*sizeof(int));
+            sfree(idata);
+        }
+        else
+        {
+            memcpy(param->val.u.r, rdata, 2*n*sizeof(real));
+            sfree(rdata);
+        }
+    }
+    if (param->nvalptr)
+    {
+        *param->nvalptr = param->val.nr;
+    }
+    param->nvalptr = NULL;
+
+    return TRUE;
+}
+
+/*! \brief
+ * Parses the values for a parameter that takes a variable number of values.
+ * 
+ * \param[in] nval   Number of values in \p values.
+ * \param[in] values Pointer to the list of values.
+ * \param     param  Parameter to parse.
+ * \param     root   Selection element to which child expressions are added.
+ * \param[in] scanner Scanner data structure.
+ * \returns   TRUE if the values were parsed successfully, FALSE otherwise.
+ *
+ * For integer ranges, the sequence of numbers from the first to second value
+ * is stored, each as a separate value.
+ */
+static gmx_bool
+parse_values_varnum(int nval, t_selexpr_value *values,
+                    gmx_ana_selparam_t *param, t_selelem *root, void *scanner)
+{
+    t_selexpr_value    *value;
+    int                 i, j;
+
+    param->flags &= ~SPAR_DYNAMIC;
+    /* Update nval if there are integer ranges. */
+    if (param->val.type == INT_VALUE)
+    {
+        value = values;
+        while (value)
+        {
+            if (value->type == INT_VALUE && !value->bExpr)
+            {
+                nval += abs(value->u.i.i2 - value->u.i.i1);
+            }
+            value = value->next;
+        }
+    }
+
+    /* Check that the value type is actually implemented */
+    if (param->val.type != INT_VALUE && param->val.type != REAL_VALUE
+        && param->val.type != STR_VALUE && param->val.type != POS_VALUE)
+    {
+        GMX_ERROR_NORET(gmx::eeInternalError,
+                        "Variable-count value type not implemented");
+        return FALSE;
+    }
+
+    /* Reserve appropriate amount of memory */
+    if (param->val.type == POS_VALUE)
+    {
+        gmx_ana_pos_reserve(param->val.u.p, nval, 0);
+        gmx_ana_pos_set_nr(param->val.u.p, nval);
+        gmx_ana_indexmap_init(&param->val.u.p->m, NULL, NULL, INDEX_UNKNOWN);
+    }
+    else
+    {
+        _gmx_selvalue_reserve(&param->val, nval);
+    }
+
+    value = values;
+    i     = 0;
+    while (value)
+    {
+        if (value->bExpr)
+        {
+            _gmx_selparser_error(scanner, "expressions not supported within value lists");
+            return FALSE;
+        }
+        if (value->type != param->val.type)
+        {
+            GMX_ERROR_NORET(gmx::eeInternalError, "Invalid value type");
+            return FALSE;
+        }
+        switch (param->val.type)
+        {
+            case INT_VALUE:
+                if (value->u.i.i1 <= value->u.i.i2)
+                {
+                    for (j = value->u.i.i1; j <= value->u.i.i2; ++j)
+                    {
+                        param->val.u.i[i++] = j;
+                    }
+                }
+                else
+                {
+                    for (j = value->u.i.i1; j >= value->u.i.i2; --j)
+                    {
+                        param->val.u.i[i++] = j;
+                    }
+                }
+                break;
+            case REAL_VALUE:
+                if (value->u.r.r1 != value->u.r.r2)
+                {
+                    _gmx_selparser_error(scanner, "real ranges not supported");
+                    return FALSE;
+                }
+                param->val.u.r[i++] = value->u.r.r1;
+                break;
+            case STR_VALUE:  param->val.u.s[i++] = strdup(value->u.s); break;
+            case POS_VALUE:  copy_rvec(value->u.x, param->val.u.p->x[i++]); break;
+            default: /* Should not be reached */
+                GMX_ERROR_NORET(gmx::eeInternalError, "Invalid value type");
+                return FALSE;
+        }
+        value = value->next;
+    }
+    param->val.nr = i;
+    if (param->nvalptr)
+    {
+        *param->nvalptr = param->val.nr;
+    }
+    param->nvalptr = NULL;
+    /* Create a dummy child element to store the string values.
+     * This element is responsible for freeing the values, but carries no
+     * other function. */
+    if (param->val.type == STR_VALUE)
+    {
+        t_selelem *child;
+
+        child = _gmx_selelem_create(SEL_CONST);
+        _gmx_selelem_set_vtype(child, STR_VALUE);
+        child->name = param->name;
+        child->flags &= ~SEL_ALLOCVAL;
+        child->flags |= SEL_FLAGSSET | SEL_VARNUMVAL | SEL_ALLOCDATA;
+        child->v.nr = param->val.nr;
+        _gmx_selvalue_setstore(&child->v, param->val.u.s);
+        /* Because the child is not group-valued, the u union is not used
+         * for anything, so we can abuse it by storing the parameter value
+         * as place_child() expects, but this is really ugly... */
+        child->u.param = param;
+        place_child(root, child, param);
+    }
+
+    return TRUE;
+}
+
+/*! \brief
+ * Adds a new subexpression reference to a selection element.
+ *
+ * \param[in,out] root  Root element to which the subexpression is added.
+ * \param[in]     param Parameter for which this expression is a value.
+ * \param[in]     expr  Expression to add.
+ * \param[in]     scanner Scanner data structure.
+ * \returns       The created child element.
+ *
+ * Creates a new \ref SEL_SUBEXPRREF element and adds it into the child
+ * list of \p root.
+ * If \p expr is already a \ref SEL_SUBEXPRREF, it is used as it is.
+ * \ref SEL_ALLOCVAL is cleared for the returned element.
+ */
+static t_selelem *
+add_child(t_selelem *root, gmx_ana_selparam_t *param, t_selelem *expr,
+          void *scanner)
+{
+    t_selelem          *child;
+    int                 rc;
+
+    if (root->type != SEL_EXPRESSION && root->type != SEL_MODIFIER)
+    {
+        GMX_ERROR_NORET(gmx::eeInternalError,
+                        "Unsupported root element for selection parameter parser");
+        return NULL;
+    }
+    /* Create a subexpression reference element if necessary */
+    if (expr->type == SEL_SUBEXPRREF)
+    {
+        child = expr;
+    }
+    else
+    {
+        child = _gmx_selelem_create(SEL_SUBEXPRREF);
+        if (!child)
+        {
+            return NULL;
+        }
+        _gmx_selelem_set_vtype(child, expr->v.type);
+        child->child  = expr;
+    }
+    /* Setup the child element */
+    child->flags &= ~SEL_ALLOCVAL;
+    child->u.param = param;
+    if (child->v.type != param->val.type)
+    {
+        _gmx_selparser_error(scanner, "invalid expression value");
+        goto on_error;
+    }
+    rc = _gmx_selelem_update_flags(child, scanner);
+    if (rc != 0)
+    {
+        goto on_error;
+    }
+    if ((child->flags & SEL_DYNAMIC) && !(param->flags & SPAR_DYNAMIC))
+    {
+        _gmx_selparser_error(scanner, "dynamic values not supported");
+        goto on_error;
+    }
+    if (!(child->flags & SEL_DYNAMIC))
+    {
+        param->flags &= ~SPAR_DYNAMIC;
+    }
+    /* Put the child element in the correct place */
+    place_child(root, child, param);
+    return child;
+
+on_error:
+    if (child != expr)
+    {
+        _gmx_selelem_free(child);
+    }
+    return NULL;
+}
+
+/*! \brief
+ * Parses an expression value for a parameter that takes a variable number of values.
+ * 
+ * \param[in] nval   Number of values in \p values.
+ * \param[in] values Pointer to the list of values.
+ * \param     param  Parameter to parse.
+ * \param     root   Selection element to which child expressions are added.
+ * \param[in] scanner Scanner data structure.
+ * \returns   TRUE if the values were parsed successfully, FALSE otherwise.
+ */
+static gmx_bool
+parse_values_varnum_expr(int nval, t_selexpr_value *values,
+                         gmx_ana_selparam_t *param, t_selelem *root,
+                         void *scanner)
+{
+    t_selexpr_value    *value;
+    t_selelem          *child;
+    t_selelem          *expr;
+
+    if (nval != 1 || !values->bExpr)
+    {
+        GMX_ERROR_NORET(gmx::eeInternalError, "Invalid expression value");
+        return FALSE;
+    }
+
+    value = values;
+    child = add_child(root, param, value->u.expr, scanner);
+    value->u.expr = NULL;
+    if (!child)
+    {
+        return FALSE;
+    }
+
+    /* Process single-valued expressions */
+    /* TODO: We should also handle SEL_SINGLEVAL expressions here */
+    if (child->v.type == POS_VALUE || child->v.type == GROUP_VALUE)
+    {
+        /* Set the value storage */
+        _gmx_selvalue_setstore(&child->v, param->val.u.ptr);
+        param->val.nr = 1;
+        if (param->nvalptr)
+        {
+            *param->nvalptr = param->val.nr;
+        }
+        param->nvalptr = NULL;
+        return TRUE;
+    }
+
+    if (!(child->flags & SEL_VARNUMVAL))
+    {
+        _gmx_selparser_error(scanner, "invalid expression value");
+        return FALSE;
+    }
+
+    child->flags   |= SEL_ALLOCVAL;
+    param->val.nr   = -1;
+    *param->nvalptr = param->val.nr;
+    /* Rest of the initialization is done during compilation in
+     * init_method(). */
+
+    return TRUE;
+}
+
+/*! \brief
+ * Initializes the storage of an expression value.
+ *
+ * \param[in,out] sel   Selection element that evaluates the value.
+ * \param[in]     param Parameter to receive the value.
+ * \param[in]     i     The value of \p sel evaluates the value \p i for
+ *   \p param.
+ * \param[in]     scanner Scanner data structure.
+ *
+ * Initializes the data pointer of \p sel such that the result is stored
+ * as the value \p i of \p param.
+ * This function is used internally by parse_values_std().
+ */
+static gmx_bool
+set_expr_value_store(t_selelem *sel, gmx_ana_selparam_t *param, int i,
+                     void *scanner)
+{
+    if (sel->v.type != GROUP_VALUE && !(sel->flags & SEL_SINGLEVAL))
+    {
+        _gmx_selparser_error(scanner, "invalid expression value");
+        return FALSE;
+    }
+    switch (sel->v.type)
+    {
+        case INT_VALUE:   sel->v.u.i = &param->val.u.i[i]; break;
+        case REAL_VALUE:  sel->v.u.r = &param->val.u.r[i]; break;
+        case STR_VALUE:   sel->v.u.s = &param->val.u.s[i]; break;
+        case POS_VALUE:   sel->v.u.p = &param->val.u.p[i]; break;
+        case GROUP_VALUE: sel->v.u.g = &param->val.u.g[i]; break;
+        default: /* Error */
+            GMX_ERROR_NORET(gmx::eeInternalError, "Invalid value type");
+            return FALSE;
+    }
+    sel->v.nr = 1;
+    sel->v.nalloc = -1;
+    return TRUE;
+}
+
+/*! \brief
+ * Parses the values for a parameter that takes a constant number of values.
+ * 
+ * \param[in] nval   Number of values in \p values.
+ * \param[in] values Pointer to the list of values.
+ * \param     param  Parameter to parse.
+ * \param     root   Selection element to which child expressions are added.
+ * \param[in] scanner Scanner data structure.
+ * \returns   TRUE if the values were parsed successfully, FALSE otherwise.
+ *
+ * For integer ranges, the sequence of numbers from the first to second value
+ * is stored, each as a separate value.
+ */
+static gmx_bool
+parse_values_std(int nval, t_selexpr_value *values, gmx_ana_selparam_t *param,
+                 t_selelem *root, void *scanner)
+{
+    t_selexpr_value   *value;
+    t_selelem         *child;
+    int                i, j;
+    gmx_bool               bDynamic;
+
+    /* Handle atom-valued parameters */
+    if (param->flags & SPAR_ATOMVAL)
+    {
+        if (nval > 1)
+        {
+            _gmx_selparser_error(scanner, "more than one value not supported");
+            return FALSE;
+        }
+        value = values;
+        if (value->bExpr)
+        {
+            child = add_child(root, param, value->u.expr, scanner);
+            value->u.expr = NULL;
+            if (!child)
+            {
+                return FALSE;
+            }
+            child->flags |= SEL_ALLOCVAL;
+            if (child->v.type != GROUP_VALUE && (child->flags & SEL_ATOMVAL))
+            {
+                /* Rest of the initialization is done during compilation in
+                 * init_method(). */
+                /* TODO: Positions are not correctly handled */
+                param->val.nr = -1;
+                if (param->nvalptr)
+                {
+                    *param->nvalptr = -1;
+                }
+                return TRUE;
+            }
+            param->flags  &= ~SPAR_ATOMVAL;
+            param->val.nr  = 1;
+            if (param->nvalptr)
+            {
+                *param->nvalptr = 1;
+            }
+            param->nvalptr = NULL;
+            if (param->val.type == INT_VALUE || param->val.type == REAL_VALUE
+                || param->val.type == STR_VALUE)
+            {
+                _gmx_selvalue_reserve(&param->val, 1);
+            }
+            return set_expr_value_store(child, param, 0, scanner);
+        }
+        /* If we reach here, proceed with normal parameter handling */
+        param->val.nr = 1;
+        if (param->val.type == INT_VALUE || param->val.type == REAL_VALUE
+            || param->val.type == STR_VALUE)
+        {
+            _gmx_selvalue_reserve(&param->val, 1);
+        }
+        param->flags &= ~SPAR_ATOMVAL;
+        param->flags &= ~SPAR_DYNAMIC;
+    }
+
+    value = values;
+    i = 0;
+    bDynamic = FALSE;
+    while (value && i < param->val.nr)
+    {
+        if (value->type != param->val.type)
+        {
+            _gmx_selparser_warning(scanner, "incorrect value skipped");
+            value = value->next;
+            continue;
+        }
+        if (value->bExpr)
+        {
+            child = add_child(root, param, value->u.expr, scanner);
+            /* Clear the expression from the value once it is stored */
+            value->u.expr = NULL;
+            /* Check that the expression is valid */
+            if (!child)
+            {
+                return FALSE;
+            }
+            if (!set_expr_value_store(child, param, i, scanner))
+            {
+                return FALSE;
+            }
+            if (child->flags & SEL_DYNAMIC)
+            {
+                bDynamic = TRUE;
+            }
+        }
+        else
+        {
+            /* Value is not an expression */
+            switch (value->type)
+            {
+                case INT_VALUE:
+                    if (value->u.i.i1 <= value->u.i.i2)
+                    {
+                        for (j = value->u.i.i1; j <= value->u.i.i2 && i < param->val.nr; ++j)
+                        {
+                            param->val.u.i[i++] = j;
+                        }
+                        if (j != value->u.i.i2 + 1)
+                        {
+                            _gmx_selparser_warning(scanner, "extra values skipped");
+                        }
+                    }
+                    else
+                    {
+                        for (j = value->u.i.i1; j >= value->u.i.i2 && i < param->val.nr; --j)
+                        {
+                            param->val.u.i[i++] = j;
+                        }
+                        if (j != value->u.i.i2 - 1)
+                        {
+                            _gmx_selparser_warning(scanner, "extra values skipped");
+                        }
+                    }
+                    --i;
+                    break;
+                case REAL_VALUE:
+                    if (value->u.r.r1 != value->u.r.r2)
+                    {
+                        _gmx_selparser_error(scanner, "real ranges not supported");
+                        return FALSE;
+                    }
+                    param->val.u.r[i] = value->u.r.r1;
+                    break;
+                case STR_VALUE:
+                    param->val.u.s[i] = strdup(value->u.s);
+                    break;
+                case POS_VALUE:
+                    gmx_ana_pos_init_const(&param->val.u.p[i], value->u.x);
+                    break;
+                case NO_VALUE:
+                case GROUP_VALUE:
+                    GMX_ERROR_NORET(gmx::eeInternalError,
+                                    "Invalid non-expression value");
+                    return FALSE;
+            }
+        }
+        ++i;
+        value = value->next;
+    }
+    if (value != NULL)
+    {
+        _gmx_selparser_error(scanner, "extra values'");
+        return FALSE;
+    }
+    if (i < param->val.nr)
+    {
+        _gmx_selparser_error(scanner, "not enough values");
+        return FALSE;
+    }
+    if (!bDynamic)
+    {
+        param->flags &= ~SPAR_DYNAMIC;
+    }
+    if (param->nvalptr)
+    {
+        *param->nvalptr = param->val.nr;
+    }
+    param->nvalptr = NULL;
+
+    return TRUE;
+}
+
+/*! \brief
+ * Parses the values for a boolean parameter.
+ *
+ * \param[in] name   Name by which the parameter was given.
+ * \param[in] nval   Number of values in \p values.
+ * \param[in] values Pointer to the list of values.
+ * \param     param  Parameter to parse.
+ * \param[in] scanner Scanner data structure.
+ * \returns   TRUE if the values were parsed successfully, FALSE otherwise.
+ */
+static gmx_bool
+parse_values_bool(const char *name, int nval, t_selexpr_value *values,
+                  gmx_ana_selparam_t *param, void *scanner)
+{
+    gmx_bool bSetNo;
+    int  len;
+
+    if (param->val.type != NO_VALUE)
+    {
+        GMX_ERROR_NORET(gmx::eeInternalError, "Invalid boolean parameter");
+        return FALSE;
+    }
+    if (nval > 1 || (values && values->type != INT_VALUE))
+    {
+        _gmx_selparser_error(scanner, "parameter takes only a yes/no/on/off/0/1 value");
+        return FALSE;
+    }
+
+    bSetNo = FALSE;
+    /* Check if the parameter name is given with a 'no' prefix */
+    len = strlen(name);
+    if (len > 2 && name[0] == 'n' && name[1] == 'o'
+        && strncmp(name+2, param->name, len-2) == 0)
+    {
+        bSetNo = TRUE;
+    }
+    if (bSetNo && nval > 0)
+    {
+        _gmx_selparser_error(scanner, "parameter 'no%s' should not have a value",
+                             param->name);
+        return FALSE;
+    }
+    if (values && values->u.i.i1 == 0)
+    {
+        bSetNo = TRUE;
+    }
+
+    *param->val.u.b = bSetNo ? FALSE : TRUE;
+    return TRUE;
+}
+
+/*! \brief
+ * Parses the values for an enumeration parameter.
+ *
+ * \param[in] nval   Number of values in \p values.
+ * \param[in] values Pointer to the list of values.
+ * \param     param  Parameter to parse.
+ * \param[in] scanner Scanner data structure.
+ * \returns   TRUE if the values were parsed successfully, FALSE otherwise.
+ */
+static gmx_bool
+parse_values_enum(int nval, t_selexpr_value *values, gmx_ana_selparam_t *param,
+                  void *scanner)
+{
+    int  i, len, match;
+
+    if (nval != 1)
+    {
+        _gmx_selparser_error(scanner, "a single value is required");
+        return FALSE;
+    }
+    if (values->type != STR_VALUE || param->val.type != STR_VALUE)
+    {
+        GMX_ERROR_NORET(gmx::eeInternalError, "Invalid enum parameter");
+        return FALSE;
+    }
+    if (values->bExpr)
+    {
+        _gmx_selparser_error(scanner, "expression value for enumerated parameter not supported");
+        return FALSE;
+    }
+
+    len = strlen(values->u.s);
+    i = 1;
+    match = 0;
+    while (param->val.u.s[i] != NULL)
+    {
+        if (strncmp(values->u.s, param->val.u.s[i], len) == 0)
+        {
+            /* Check if there is a duplicate match */
+            if (match > 0)
+            {
+                _gmx_selparser_error(scanner, "ambiguous value");
+                return FALSE;
+            }
+            match = i;
+        }
+        ++i;
+    }
+    if (match == 0)
+    {
+        _gmx_selparser_error(scanner, "invalid value");
+        return FALSE;
+    }
+    param->val.u.s[0] = param->val.u.s[match];
+    return TRUE;
+}
+
+/*! \brief
+ * Replaces constant expressions with their values.
+ *
+ * \param[in,out] values First element in the value list to process.
+ */
+static void
+convert_const_values(t_selexpr_value *values)
+{
+    t_selexpr_value *val;
+
+    val = values;
+    while (val)
+    {
+        if (val->bExpr && val->u.expr->v.type != GROUP_VALUE &&
+            val->u.expr->type == SEL_CONST)
+        {
+            t_selelem *expr = val->u.expr;
+            val->bExpr = FALSE;
+            switch (expr->v.type)
+            {
+                case INT_VALUE:
+                    val->u.i.i1 = val->u.i.i2 = expr->v.u.i[0];
+                    break;
+                case REAL_VALUE:
+                    val->u.r.r1 = val->u.r.r2 = expr->v.u.r[0];
+                    break;
+                case STR_VALUE:
+                    val->u.s = expr->v.u.s[0];
+                    break;
+                case POS_VALUE:
+                    copy_rvec(expr->v.u.p->x[0], val->u.x);
+                    break;
+                default:
+                    GMX_ERROR_NORET(gmx::eeInternalError,
+                                    "Unsupported value type");
+                    break;
+            }
+            _gmx_selelem_free(expr);
+        }
+        val = val->next;
+    }
+}
+
+/*!
+ * \param     pparams List of parameters from the selection parser.
+ * \param[in] nparam  Number of parameters in \p params.
+ * \param     params  Array of parameters to parse.
+ * \param     root    Selection element to which child expressions are added.
+ * \param[in] scanner Scanner data structure.
+ * \returns   TRUE if the parameters were parsed successfully, FALSE otherwise.
+ *
+ * Initializes the \p params array based on the parameters in \p pparams.
+ * See the documentation of \c gmx_ana_selparam_t for different options
+ * available for parsing.
+ *
+ * The list \p pparams and any associated values are freed after the parameters
+ * have been processed, no matter is there was an error or not.
+ */
+gmx_bool
+_gmx_sel_parse_params(t_selexpr_param *pparams, int nparam, gmx_ana_selparam_t *params,
+                      t_selelem *root, void *scanner)
+{
+    gmx::AbstractErrorReporter *errors = _gmx_sel_lexer_error_reporter(scanner);
+    t_selexpr_param    *pparam;
+    gmx_ana_selparam_t *oparam;
+    gmx_bool                bOk, rc;
+    int                 i;
+
+    /* Check that the value pointers of SPAR_VARNUM parameters are NULL and
+     * that they are not NULL for other parameters */
+    bOk = TRUE;
+    for (i = 0; i < nparam; ++i)
+    {
+        char buf[128];
+        sprintf(buf, "In parameter '%s'", params[i].name);
+        gmx::ErrorContext context(errors, buf);
+        if (params[i].val.type != POS_VALUE && (params[i].flags & (SPAR_VARNUM | SPAR_ATOMVAL)))
+        {
+            if (params[i].val.u.ptr != NULL)
+            {
+                _gmx_selparser_warning(scanner, "value pointer is not NULL "
+                                       "although it should be for SPAR_VARNUM "
+                                       "and SPAR_ATOMVAL parameters");
+            }
+            if ((params[i].flags & SPAR_VARNUM)
+                && (params[i].flags & SPAR_DYNAMIC) && !params[i].nvalptr)
+            {
+                _gmx_selparser_error(scanner, "nvalptr is NULL but both "
+                                     "SPAR_VARNUM and SPAR_DYNAMIC are specified");
+                bOk = FALSE;
+            }
+        }
+        else
+        {
+            if (params[i].val.u.ptr == NULL)
+            {
+                _gmx_selparser_error(scanner, "value pointer is NULL");
+                bOk = FALSE;
+            }
+        }
+    }
+    if (!bOk)
+    {
+        _gmx_selexpr_free_params(pparams);
+        return FALSE;
+    }
+    /* Parse the parameters */
+    pparam = pparams;
+    i      = 0;
+    while (pparam)
+    {
+        char buf[128];
+        /* Find the parameter and make some checks */
+        if (pparam->name != NULL)
+        {
+            sprintf(buf, "In parameter '%s'", pparam->name);
+            i = -1;
+            oparam = gmx_ana_selparam_find(pparam->name, nparam, params);
+        }
+        else if (i >= 0)
+        {
+            sprintf(buf, "In value %d", i + 1);
+            oparam = &params[i];
+            if (oparam->name != NULL)
+            {
+                oparam = NULL;
+                _gmx_selparser_error(scanner, "too many NULL parameters provided");
+                bOk = FALSE;
+                pparam = pparam->next;
+                continue;
+            }
+            ++i;
+        }
+        else
+        {
+            _gmx_selparser_error(scanner, "all NULL parameters should appear in the beginning of the list");
+            bOk = FALSE;
+            pparam = pparam->next;
+            continue;
+        }
+        gmx::ErrorContext context(errors, buf);
+        if (!oparam)
+        {
+            _gmx_selparser_error(scanner, "unknown parameter skipped");
+            bOk = FALSE;
+            goto next_param;
+        }
+        if (oparam->flags & SPAR_SET)
+        {
+            _gmx_selparser_error(scanner, "parameter set multiple times, extra values skipped");
+            bOk = FALSE;
+            goto next_param;
+        }
+        oparam->flags |= SPAR_SET;
+        /* Process the values for the parameter */
+        convert_const_values(pparam->value);
+        if (convert_values(pparam->value, oparam->val.type, scanner) != 0)
+        {
+            _gmx_selparser_error(scanner, "invalid value");
+            bOk = FALSE;
+            goto next_param;
+        }
+        if (oparam->val.type == NO_VALUE)
+        {
+            rc = parse_values_bool(pparam->name, pparam->nval, pparam->value, oparam, scanner);
+        }
+        else if (oparam->flags & SPAR_RANGES)
+        {
+            rc = parse_values_range(pparam->nval, pparam->value, oparam, scanner);
+        }
+        else if (oparam->flags & SPAR_VARNUM)
+        {
+            if (pparam->nval == 1 && pparam->value->bExpr)
+            {
+                rc = parse_values_varnum_expr(pparam->nval, pparam->value, oparam, root, scanner);
+            }
+            else
+            {
+                rc = parse_values_varnum(pparam->nval, pparam->value, oparam, root, scanner);
+            }
+        }
+        else if (oparam->flags & SPAR_ENUMVAL)
+        {
+            rc = parse_values_enum(pparam->nval, pparam->value, oparam, scanner);
+        }
+        else
+        {
+            rc = parse_values_std(pparam->nval, pparam->value, oparam, root, scanner);
+        }
+        if (!rc)
+        {
+            bOk = FALSE;
+        }
+        /* Advance to the next parameter */
+next_param:
+        pparam = pparam->next;
+    }
+    /* Check that all required parameters are present */
+    for (i = 0; i < nparam; ++i)
+    {
+        if (!(params[i].flags & SPAR_OPTIONAL) && !(params[i].flags & SPAR_SET))
+        {
+            _gmx_selparser_error(scanner, "required parameter '%s' not specified", params[i].name);
+            bOk = FALSE;
+        }
+    }
+
+    _gmx_selexpr_free_params(pparams);
+    return bOk;
+}
diff --git a/src/gromacs/selection/parser.cpp b/src/gromacs/selection/parser.cpp
new file mode 100644 (file)
index 0000000..cdc51e6
--- /dev/null
@@ -0,0 +1,2584 @@
+/* A Bison parser, made by GNU Bison 2.3.  */
+
+/* Skeleton implementation for Bison's Yacc-like parsers in C
+
+   Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+   Free Software Foundation, Inc.
+
+   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, or (at your option)
+   any later version.
+
+   This program 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 General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
+
+/* As a special exception, you may create a larger work that contains
+   part or all of the Bison parser skeleton and distribute that work
+   under terms of your choice, so long as that work isn't itself a
+   parser generator using the skeleton or a modified version thereof
+   as a parser skeleton.  Alternatively, if you modify or redistribute
+   the parser skeleton itself, you may (at your option) remove this
+   special exception, which will cause the skeleton and the resulting
+   Bison output files to be licensed under the GNU General Public
+   License without this special exception.
+
+   This special exception was added by the Free Software Foundation in
+   version 2.2 of Bison.  */
+
+/* C LALR(1) parser skeleton written by Richard Stallman, by
+   simplifying the original so-called "semantic" parser.  */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+   infringing on user name space.  This should be done even for local
+   variables, as they might otherwise be expanded by user macros.
+   There are some unavoidable exceptions within include files to
+   define necessary library symbols; they are noted "INFRINGES ON
+   USER NAME SPACE" below.  */
+
+/* Identify Bison output.  */
+#define YYBISON 1
+
+/* Bison version.  */
+#define YYBISON_VERSION "2.3"
+
+/* Skeleton name.  */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers.  */
+#define YYPURE 1
+
+/* Using locations.  */
+#define YYLSP_NEEDED 0
+
+/* Substitute the variable and function names.  */
+#define yyparse _gmx_sel_yybparse
+#define yylex   _gmx_sel_yyblex
+#define yyerror _gmx_sel_yyberror
+#define yylval  _gmx_sel_yyblval
+#define yychar  _gmx_sel_yybchar
+#define yydebug _gmx_sel_yybdebug
+#define yynerrs _gmx_sel_yybnerrs
+
+
+/* Tokens.  */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+   /* Put the tokens into the symbol table, so that GDB and other debuggers
+      know about them.  */
+   enum yytokentype {
+     INVALID = 258,
+     HELP = 259,
+     HELP_TOPIC = 260,
+     TOK_INT = 261,
+     TOK_REAL = 262,
+     STR = 263,
+     IDENTIFIER = 264,
+     CMD_SEP = 265,
+     GROUP = 266,
+     TO = 267,
+     VARIABLE_NUMERIC = 268,
+     VARIABLE_GROUP = 269,
+     VARIABLE_POS = 270,
+     KEYWORD_NUMERIC = 271,
+     KEYWORD_STR = 272,
+     KEYWORD_POS = 273,
+     KEYWORD_GROUP = 274,
+     METHOD_NUMERIC = 275,
+     METHOD_GROUP = 276,
+     METHOD_POS = 277,
+     MODIFIER = 278,
+     EMPTY_POSMOD = 279,
+     PARAM = 280,
+     END_OF_METHOD = 281,
+     OF = 282,
+     CMP_OP = 283,
+     PARAM_REDUCT = 284,
+     XOR = 285,
+     OR = 286,
+     AND = 287,
+     NOT = 288,
+     UNARY_NEG = 289,
+     NUM_REDUCT = 290
+   };
+#endif
+/* Tokens.  */
+#define INVALID 258
+#define HELP 259
+#define HELP_TOPIC 260
+#define TOK_INT 261
+#define TOK_REAL 262
+#define STR 263
+#define IDENTIFIER 264
+#define CMD_SEP 265
+#define GROUP 266
+#define TO 267
+#define VARIABLE_NUMERIC 268
+#define VARIABLE_GROUP 269
+#define VARIABLE_POS 270
+#define KEYWORD_NUMERIC 271
+#define KEYWORD_STR 272
+#define KEYWORD_POS 273
+#define KEYWORD_GROUP 274
+#define METHOD_NUMERIC 275
+#define METHOD_GROUP 276
+#define METHOD_POS 277
+#define MODIFIER 278
+#define EMPTY_POSMOD 279
+#define PARAM 280
+#define END_OF_METHOD 281
+#define OF 282
+#define CMP_OP 283
+#define PARAM_REDUCT 284
+#define XOR 285
+#define OR 286
+#define AND 287
+#define NOT 288
+#define UNARY_NEG 289
+#define NUM_REDUCT 290
+
+
+
+
+/* Copy the first part of user declarations.  */
+#line 37 "parser.y"
+
+/*! \internal \file parser.cpp
+ * \brief Generated (from parser.y by Bison) parser for the selection language.
+ *
+ * \ingroup module_selection
+ */
+/*! \internal \file parser.h
+ * \brief Generated (from parser.y by Bison) parser include file.
+ *
+ * \ingroup module_selection
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+
+#include <string2.h>
+
+#include "parsetree.h"
+#include "selelem.h"
+
+#include "scanner.h"
+
+static t_selexpr_value *
+process_value_list(t_selexpr_value *values, int *nr);
+static t_selexpr_param *
+process_param_list(t_selexpr_param *params);
+
+static void
+yyerror(yyscan_t, char const *s);
+
+
+/* Enabling traces.  */
+#ifndef YYDEBUG
+# define YYDEBUG 1
+#endif
+
+/* Enabling verbose error messages.  */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
+
+/* Enabling the token table.  */
+#ifndef YYTOKEN_TABLE
+# define YYTOKEN_TABLE 0
+#endif
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+#line 69 "parser.y"
+{
+    int                         i;
+    real                        r;
+    char                       *str;
+    struct gmx_ana_selmethod_t *meth;
+
+    struct t_selelem           *sel;
+
+    struct t_selexpr_value     *val;
+    struct t_selexpr_param     *param;
+}
+/* Line 187 of yacc.c.  */
+#line 218 "parser.cpp"
+       YYSTYPE;
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+
+
+
+/* Copy the second part of user declarations.  */
+
+
+/* Line 216 of yacc.c.  */
+#line 231 "parser.cpp"
+
+#ifdef short
+# undef short
+#endif
+
+#ifdef YYTYPE_UINT8
+typedef YYTYPE_UINT8 yytype_uint8;
+#else
+typedef unsigned char yytype_uint8;
+#endif
+
+#ifdef YYTYPE_INT8
+typedef YYTYPE_INT8 yytype_int8;
+#elif (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+typedef signed char yytype_int8;
+#else
+typedef short int yytype_int8;
+#endif
+
+#ifdef YYTYPE_UINT16
+typedef YYTYPE_UINT16 yytype_uint16;
+#else
+typedef unsigned short int yytype_uint16;
+#endif
+
+#ifdef YYTYPE_INT16
+typedef YYTYPE_INT16 yytype_int16;
+#else
+typedef short int yytype_int16;
+#endif
+
+#ifndef YYSIZE_T
+# ifdef __SIZE_TYPE__
+#  define YYSIZE_T __SIZE_TYPE__
+# elif defined size_t
+#  define YYSIZE_T size_t
+# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+#  include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+#  define YYSIZE_T size_t
+# else
+#  define YYSIZE_T unsigned int
+# endif
+#endif
+
+#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
+
+#ifndef YY_
+# if YYENABLE_NLS
+#  if ENABLE_NLS
+#   include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+#   define YY_(msgid) dgettext ("bison-runtime", msgid)
+#  endif
+# endif
+# ifndef YY_
+#  define YY_(msgid) msgid
+# endif
+#endif
+
+/* Suppress unused-variable warnings by "using" E.  */
+#if ! defined lint || defined __GNUC__
+# define YYUSE(e) ((void) (e))
+#else
+# define YYUSE(e) /* empty */
+#endif
+
+/* Identity function, used to suppress warnings about constant conditions.  */
+#ifndef lint
+# define YYID(n) (n)
+#else
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static int
+YYID (int i)
+#else
+static int
+YYID (i)
+    int i;
+#endif
+{
+  return i;
+}
+#endif
+
+#if ! defined yyoverflow || YYERROR_VERBOSE
+
+/* The parser invokes alloca or malloc; define the necessary symbols.  */
+
+# ifdef YYSTACK_USE_ALLOCA
+#  if YYSTACK_USE_ALLOCA
+#   ifdef __GNUC__
+#    define YYSTACK_ALLOC __builtin_alloca
+#   elif defined __BUILTIN_VA_ARG_INCR
+#    include <alloca.h> /* INFRINGES ON USER NAME SPACE */
+#   elif defined _AIX
+#    define YYSTACK_ALLOC __alloca
+#   elif defined _MSC_VER
+#    include <malloc.h> /* INFRINGES ON USER NAME SPACE */
+#    define alloca _alloca
+#   else
+#    define YYSTACK_ALLOC alloca
+#    if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+#     include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+#     ifndef _STDLIB_H
+#      define _STDLIB_H 1
+#     endif
+#    endif
+#   endif
+#  endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+   /* Pacify GCC's `empty if-body' warning.  */
+#  define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
+#  ifndef YYSTACK_ALLOC_MAXIMUM
+    /* The OS might guarantee only one guard page at the bottom of the stack,
+       and a page size can be as small as 4096 bytes.  So we cannot safely
+       invoke alloca (N) if N exceeds 4096.  Use a slightly smaller number
+       to allow for a few compiler-allocated temporary stack slots.  */
+#   define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
+#  endif
+# else
+#  define YYSTACK_ALLOC YYMALLOC
+#  define YYSTACK_FREE YYFREE
+#  ifndef YYSTACK_ALLOC_MAXIMUM
+#   define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
+#  endif
+#  if (defined __cplusplus && ! defined _STDLIB_H \
+       && ! ((defined YYMALLOC || defined malloc) \
+            && (defined YYFREE || defined free)))
+#   include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+#   ifndef _STDLIB_H
+#    define _STDLIB_H 1
+#   endif
+#  endif
+#  ifndef YYMALLOC
+#   define YYMALLOC malloc
+#   if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+#   endif
+#  endif
+#  ifndef YYFREE
+#   define YYFREE free
+#   if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+#   endif
+#  endif
+# endif
+#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
+
+
+#if (! defined yyoverflow \
+     && (! defined __cplusplus \
+        || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member.  */
+union yyalloc
+{
+  yytype_int16 yyss;
+  YYSTYPE yyvs;
+  };
+
+/* The size of the maximum gap between one aligned stack and the next.  */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+   N elements.  */
+# define YYSTACK_BYTES(N) \
+     ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
+      + YYSTACK_GAP_MAXIMUM)
+
+/* Copy COUNT objects from FROM to TO.  The source and destination do
+   not overlap.  */
+# ifndef YYCOPY
+#  if defined __GNUC__ && 1 < __GNUC__
+#   define YYCOPY(To, From, Count) \
+      __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
+#  else
+#   define YYCOPY(To, From, Count)             \
+      do                                       \
+       {                                       \
+         YYSIZE_T yyi;                         \
+         for (yyi = 0; yyi < (Count); yyi++)   \
+           (To)[yyi] = (From)[yyi];            \
+       }                                       \
+      while (YYID (0))
+#  endif
+# endif
+
+/* Relocate STACK from its old location to the new one.  The
+   local variables YYSIZE and YYSTACKSIZE give the old and new number of
+   elements in the stack, and YYPTR gives the new location of the
+   stack.  Advance YYPTR to a properly aligned location for the next
+   stack.  */
+# define YYSTACK_RELOCATE(Stack)                                       \
+    do                                                                 \
+      {                                                                        \
+       YYSIZE_T yynewbytes;                                            \
+       YYCOPY (&yyptr->Stack, Stack, yysize);                          \
+       Stack = &yyptr->Stack;                                          \
+       yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+       yyptr += yynewbytes / sizeof (*yyptr);                          \
+      }                                                                        \
+    while (YYID (0))
+
+#endif
+
+/* YYFINAL -- State number of the termination state.  */
+#define YYFINAL  2
+/* YYLAST -- Last index in YYTABLE.  */
+#define YYLAST   417
+
+/* YYNTOKENS -- Number of terminals.  */
+#define YYNTOKENS  49
+/* YYNNTS -- Number of nonterminals.  */
+#define YYNNTS  26
+/* YYNRULES -- Number of rules.  */
+#define YYNRULES  91
+/* YYNRULES -- Number of states.  */
+#define YYNSTATES  150
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX.  */
+#define YYUNDEFTOK  2
+#define YYMAXUTOK   290
+
+#define YYTRANSLATE(YYX)                                               \
+  ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX.  */
+static const yytype_uint8 yytranslate[] =
+{
+       0,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+      42,    43,    36,    34,    45,    35,     2,    37,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,    41,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,    44,     2,    46,    39,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,    47,     2,    48,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     1,     2,     3,     4,
+       5,     6,     7,     8,     9,    10,    11,    12,    13,    14,
+      15,    16,    17,    18,    19,    20,    21,    22,    23,    24,
+      25,    26,    27,    28,    29,    30,    31,    32,    33,    38,
+      40
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+   YYRHS.  */
+static const yytype_uint16 yyprhs[] =
+{
+       0,     0,     3,     4,     7,    10,    13,    14,    16,    18,
+      20,    22,    25,    29,    33,    37,    39,    41,    44,    47,
+      49,    51,    55,    59,    61,    64,    66,    69,    71,    73,
+      75,    77,    80,    84,    88,    92,    96,    99,   102,   104,
+     106,   109,   113,   117,   121,   123,   125,   128,   132,   136,
+     140,   144,   148,   151,   155,   159,   161,   164,   172,   176,
+     179,   183,   185,   187,   189,   191,   194,   195,   198,   201,
+     202,   204,   208,   210,   213,   217,   219,   223,   225,   228,
+     232,   234,   236,   238,   240,   242,   244,   246,   248,   250,
+     254,   258
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS.  */
+static const yytype_int8 yyrhs[] =
+{
+      50,     0,    -1,    -1,    50,    51,    -1,    52,    10,    -1,
+       1,    10,    -1,    -1,    53,    -1,     6,    -1,    59,    -1,
+      55,    -1,    59,    55,    -1,     9,    41,    60,    -1,     9,
+      41,    62,    -1,     9,    41,    64,    -1,     4,    -1,    54,
+      -1,     4,     5,    -1,    54,     5,    -1,    64,    -1,    60,
+      -1,    42,    55,    43,    -1,    55,    23,    65,    -1,     6,
+      -1,    35,     6,    -1,     7,    -1,    35,     7,    -1,    56,
+      -1,    57,    -1,     8,    -1,     9,    -1,    33,    60,    -1,
+      60,    32,    60,    -1,    60,    31,    60,    -1,    42,    60,
+      43,    -1,    62,    28,    62,    -1,    11,    59,    -1,    11,
+       6,    -1,    24,    -1,    18,    -1,    61,    19,    -1,    61,
+      17,    70,    -1,    61,    16,    70,    -1,    61,    21,    65,
+      -1,     6,    -1,     7,    -1,    61,    16,    -1,    61,    20,
+      65,    -1,    62,    34,    62,    -1,    62,    35,    62,    -1,
+      62,    36,    62,    -1,    62,    37,    62,    -1,    35,    62,
+      -1,    62,    39,    62,    -1,    42,    62,    43,    -1,    59,
+      -1,    61,    17,    -1,    44,    58,    45,    58,    45,    58,
+      46,    -1,    42,    64,    43,    -1,    22,    65,    -1,    18,
+      27,    60,    -1,    14,    -1,    13,    -1,    15,    -1,    66,
+      -1,    66,    26,    -1,    -1,    66,    67,    -1,    25,    68,
+      -1,    -1,    69,    -1,    47,    69,    48,    -1,    72,    -1,
+      69,    72,    -1,    69,    45,    72,    -1,    71,    -1,    47,
+      71,    48,    -1,    73,    -1,    71,    73,    -1,    71,    45,
+      73,    -1,    60,    -1,    64,    -1,    62,    -1,    63,    -1,
+      74,    -1,    56,    -1,    57,    -1,    59,    -1,    74,    -1,
+      56,    12,    56,    -1,    56,    12,    57,    -1,    57,    12,
+      58,    -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
+static const yytype_uint16 yyrline[] =
+{
+       0,   189,   189,   190,   199,   200,   220,   224,   225,   234,
+     244,   246,   248,   250,   252,   258,   259,   262,   263,   267,
+     268,   273,   274,   286,   287,   291,   292,   295,   296,   299,
+     300,   308,   314,   320,   332,   336,   344,   350,   358,   359,
+     363,   368,   373,   381,   393,   400,   410,   415,   423,   425,
+     427,   429,   431,   433,   435,   442,   449,   461,   466,   470,
+     478,   489,   493,   497,   506,   508,   513,   514,   519,   526,
+     527,   528,   532,   533,   535,   540,   541,   545,   546,   548,
+     552,   554,   556,   558,   560,   564,   569,   574,   579,   583,
+     588,   593
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+   First, the terminals, then, starting at YYNTOKENS, nonterminals.  */
+static const char *const yytname[] =
+{
+  "$end", "error", "$undefined", "INVALID", "HELP", "HELP_TOPIC",
+  "TOK_INT", "TOK_REAL", "STR", "IDENTIFIER", "CMD_SEP", "GROUP", "TO",
+  "VARIABLE_NUMERIC", "VARIABLE_GROUP", "VARIABLE_POS", "KEYWORD_NUMERIC",
+  "KEYWORD_STR", "KEYWORD_POS", "KEYWORD_GROUP", "METHOD_NUMERIC",
+  "METHOD_GROUP", "METHOD_POS", "MODIFIER", "EMPTY_POSMOD", "PARAM",
+  "END_OF_METHOD", "OF", "CMP_OP", "PARAM_REDUCT", "XOR", "OR", "AND",
+  "NOT", "'+'", "'-'", "'*'", "'/'", "UNARY_NEG", "'^'", "NUM_REDUCT",
+  "'='", "'('", "')'", "'['", "','", "']'", "'{'", "'}'", "$accept",
+  "commands", "command", "cmd_plain", "help_request", "help_topic",
+  "selection", "integer_number", "real_number", "number", "string",
+  "sel_expr", "pos_mod", "num_expr", "str_expr", "pos_expr",
+  "method_params", "method_param_list", "method_param", "value_list",
+  "value_list_contents", "basic_value_list", "basic_value_list_contents",
+  "value_item", "basic_value_item", "value_item_range", 0
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+   token YYLEX-NUM.  */
+static const yytype_uint16 yytoknum[] =
+{
+       0,   256,   257,   258,   259,   260,   261,   262,   263,   264,
+     265,   266,   267,   268,   269,   270,   271,   272,   273,   274,
+     275,   276,   277,   278,   279,   280,   281,   282,   283,   284,
+     285,   286,   287,   288,    43,    45,    42,    47,   289,    94,
+     290,    61,    40,    41,    91,    44,    93,   123,   125
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
+static const yytype_uint8 yyr1[] =
+{
+       0,    49,    50,    50,    51,    51,    52,    52,    52,    52,
+      52,    52,    52,    52,    52,    53,    53,    54,    54,    55,
+      55,    55,    55,    56,    56,    57,    57,    58,    58,    59,
+      59,    60,    60,    60,    60,    60,    60,    60,    61,    61,
+      60,    60,    60,    60,    62,    62,    62,    62,    62,    62,
+      62,    62,    62,    62,    62,    63,    63,    64,    64,    64,
+      64,    60,    62,    64,    65,    65,    66,    66,    67,    68,
+      68,    68,    69,    69,    69,    70,    70,    71,    71,    71,
+      72,    72,    72,    72,    72,    73,    73,    73,    73,    74,
+      74,    74
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN.  */
+static const yytype_uint8 yyr2[] =
+{
+       0,     2,     0,     2,     2,     2,     0,     1,     1,     1,
+       1,     2,     3,     3,     3,     1,     1,     2,     2,     1,
+       1,     3,     3,     1,     2,     1,     2,     1,     1,     1,
+       1,     2,     3,     3,     3,     3,     2,     2,     1,     1,
+       2,     3,     3,     3,     1,     1,     2,     3,     3,     3,
+       3,     3,     2,     3,     3,     1,     2,     7,     3,     2,
+       3,     1,     1,     1,     1,     2,     0,     2,     2,     0,
+       1,     3,     1,     2,     3,     1,     3,     1,     2,     3,
+       1,     1,     1,     1,     1,     1,     1,     1,     1,     3,
+       3,     3
+};
+
+/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
+   STATE-NUM when YYTABLE doesn't specify something else to do.  Zero
+   means the default is an error.  */
+static const yytype_uint8 yydefact[] =
+{
+       2,     0,     1,     0,    15,    44,    45,    29,    30,     0,
+      62,    61,    63,    39,    66,    38,     0,     0,     0,     0,
+       3,     0,     7,    16,    10,     9,    20,     0,     0,    19,
+       5,    17,     0,    37,    30,    36,     0,    59,    64,    44,
+      39,     0,    31,     0,     0,    52,     0,    20,     0,    19,
+      23,    25,     0,    27,    28,     0,     4,    18,    66,    11,
+       0,     0,    46,     0,    40,    66,    66,     0,     0,     0,
+       0,     0,     0,     0,    12,    13,    14,    60,    69,    65,
+      67,     0,     0,    46,    21,    34,    54,    58,    24,    26,
+       0,    22,    33,    32,     0,    85,    86,    87,    42,    75,
+      77,    88,    41,    47,    43,    35,    48,    49,    50,    51,
+      53,     0,    44,    45,     0,     0,     0,     0,    55,    80,
+       0,    82,    83,    81,    68,    70,    72,    84,     0,     0,
+       0,     0,     0,    78,    44,    45,     0,    56,     0,    73,
+       0,    76,    89,    90,    91,    79,    71,    74,     0,    57
+};
+
+/* YYDEFGOTO[NTERM-NUM].  */
+static const yytype_int8 yydefgoto[] =
+{
+      -1,     1,    20,    21,    22,    23,    24,    95,    96,    55,
+      97,   119,    27,    28,   122,   123,    37,    38,    80,   124,
+     125,   102,    99,   126,   100,   101
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+   STATE-NUM.  */
+#define YYPACT_NINF -93
+static const yytype_int16 yypact[] =
+{
+     -93,   155,   -93,    10,    19,    26,   -93,   -93,    -3,    73,
+     -93,   -93,   -93,    22,   -93,   -93,   356,   372,   317,    11,
+     -93,    79,   -93,    86,    70,   317,    29,   384,   180,   -93,
+     -93,   -93,   342,   -93,   -93,   -93,   356,   -93,     6,   -93,
+     -93,   356,   -93,   372,   -10,    57,   -20,   -17,   256,    54,
+     -93,   -93,    88,   -93,   -93,    55,   -93,   -93,   -93,    70,
+     356,   356,   197,   174,   -93,   -93,   -93,   372,   372,   372,
+     372,   372,   372,   342,    29,   180,   -93,    29,   221,   -93,
+     -93,   -17,   223,   -93,   -93,   -93,   -93,   -93,   -93,   -93,
+      11,   -93,    69,   -93,    78,    90,    94,   -93,   -93,   244,
+     -93,   -93,   -93,   -93,   -93,   267,    36,    36,    57,    57,
+      57,    54,    95,    96,   375,   303,    90,    94,   -93,    29,
+     392,   267,   -93,   -93,   -93,   263,   -93,   -93,    71,    35,
+      11,    11,    78,   -93,   105,   106,   178,   174,   303,   -93,
+      11,   -93,   -93,   -93,   -93,   -93,   -93,   -93,    80,   -93
+};
+
+/* YYPGOTO[NTERM-NUM].  */
+static const yytype_int8 yypgoto[] =
+{
+     -93,   -93,   -93,   -93,   -93,   -93,   -13,     0,    14,   -81,
+      -1,    87,    -4,   -16,   -93,     3,   -36,   -93,   -93,   -93,
+      12,    81,    39,   -91,   -92,   -67
+};
+
+/* YYTABLE[YYPACT[STATE-NUM]].  What to do in state STATE-NUM.  If
+   positive, shift that token.  If negative, reduce the rule which
+   number is the opposite.  If zero, do what YYDEFACT says.
+   If YYTABLE_NINF, syntax error.  */
+#define YYTABLE_NINF -27
+static const yytype_int16 yytable[] =
+{
+      25,    45,    48,    58,    29,    46,    83,   133,    35,   128,
+      65,   127,    59,    44,    60,    61,    75,    50,    51,    53,
+      30,    49,    91,    84,    31,    48,    85,    82,    29,   103,
+     104,    78,    79,    54,   139,    76,    -8,   133,    32,    44,
+     145,    50,    51,     7,    34,   139,    52,   147,   127,    36,
+     144,   105,   106,   107,   108,   109,   110,    48,   127,   148,
+      60,    61,   121,    44,    44,    44,    44,    44,    44,   127,
+      52,   127,    70,    71,   120,    72,   111,   118,   116,    33,
+     132,     7,    34,   141,    50,    51,     7,    34,    26,    56,
+      53,    57,   117,    58,    88,    89,    72,    87,    45,   121,
+      90,    61,   130,    42,    54,    47,   131,   -23,   -25,   121,
+      44,   120,    26,    52,   118,   116,   140,   -24,   -26,    74,
+     121,   120,   121,    77,   118,   116,   149,   136,    81,   117,
+     142,    53,   120,   129,   120,   118,   116,   118,   116,   117,
+      53,     0,     0,    98,   143,    54,     0,    92,    93,     0,
+     117,     0,   117,     0,    54,     2,     3,     0,     0,     4,
+      81,     5,     6,     7,     8,    -6,     9,     0,    10,    11,
+      12,     0,     0,    13,     0,     0,     0,    14,     0,    15,
+      50,    51,     7,    34,   112,   113,     7,    34,    16,     9,
+      17,    10,    11,    12,     0,     0,    13,    18,     0,    19,
+      14,     0,    15,    50,    51,     7,    34,     0,    67,    52,
+       0,    16,     0,   114,    68,    69,    70,    71,     0,    72,
+      73,    94,    19,   138,     0,     0,   146,   112,   113,     7,
+      34,     0,     9,     0,    10,    11,    12,     0,     0,    13,
+       0,     0,     0,    14,    94,    15,     0,     0,     0,     0,
+      50,    51,     7,    34,    16,     0,   114,    68,    69,    70,
+      71,     0,    72,    73,     0,    19,    86,     0,   115,   112,
+     113,     7,    34,     0,     9,     0,    10,    11,    12,    52,
+       0,    13,     0,     0,    67,    14,     0,    15,     0,   132,
+      68,    69,    70,    71,     0,    72,    16,     0,   114,    86,
+       0,    68,    69,    70,    71,    73,    72,    19,   138,   112,
+     113,     7,    34,     0,     9,     0,    10,    11,    12,     0,
+       0,    13,     0,    39,     6,    14,     0,    15,     9,     0,
+      10,    11,    12,     0,     0,    13,    16,     0,   114,    14,
+       0,    15,     0,     0,     0,    73,     0,    19,    39,     6,
+      16,     0,    17,     9,     0,    10,    11,    12,     0,    18,
+      13,    19,    39,     6,    14,     0,    15,     9,     0,    10,
+      11,     0,     0,     0,    40,    16,     0,    17,    39,     6,
+      15,   134,   135,     0,    73,    10,    19,     0,    10,    16,
+      40,    17,     0,    40,     0,     0,    15,     0,    41,    15,
+      62,    63,     0,    64,    65,    66,     0,    17,    62,   137,
+      17,    64,    65,    66,    43,     0,     0,    43
+};
+
+static const yytype_int16 yycheck[] =
+{
+       1,    17,    18,    23,     1,    18,    16,    99,     9,    90,
+      20,    78,    25,    17,    31,    32,    32,     6,     7,    19,
+      10,    18,    58,    43,     5,    41,    43,    43,    25,    65,
+      66,    25,    26,    19,   125,    32,    10,   129,    41,    43,
+     132,     6,     7,     8,     9,   136,    35,   138,   115,    27,
+     131,    67,    68,    69,    70,    71,    72,    73,   125,   140,
+      31,    32,    78,    67,    68,    69,    70,    71,    72,   136,
+      35,   138,    36,    37,    78,    39,    73,    78,    78,     6,
+      45,     8,     9,    48,     6,     7,     8,     9,     1,    10,
+      90,     5,    78,    23,     6,     7,    39,    43,   114,   115,
+      45,    32,    12,    16,    90,    18,    12,    12,    12,   125,
+     114,   115,    25,    35,   115,   115,    45,    12,    12,    32,
+     136,   125,   138,    36,   125,   125,    46,   115,    41,   115,
+     130,   131,   136,    94,   138,   136,   136,   138,   138,   125,
+     140,    -1,    -1,    62,   130,   131,    -1,    60,    61,    -1,
+     136,    -1,   138,    -1,   140,     0,     1,    -1,    -1,     4,
+      73,     6,     7,     8,     9,    10,    11,    -1,    13,    14,
+      15,    -1,    -1,    18,    -1,    -1,    -1,    22,    -1,    24,
+       6,     7,     8,     9,     6,     7,     8,     9,    33,    11,
+      35,    13,    14,    15,    -1,    -1,    18,    42,    -1,    44,
+      22,    -1,    24,     6,     7,     8,     9,    -1,    28,    35,
+      -1,    33,    -1,    35,    34,    35,    36,    37,    -1,    39,
+      42,    47,    44,    45,    -1,    -1,    48,     6,     7,     8,
+       9,    -1,    11,    -1,    13,    14,    15,    -1,    -1,    18,
+      -1,    -1,    -1,    22,    47,    24,    -1,    -1,    -1,    -1,
+       6,     7,     8,     9,    33,    -1,    35,    34,    35,    36,
+      37,    -1,    39,    42,    -1,    44,    43,    -1,    47,     6,
+       7,     8,     9,    -1,    11,    -1,    13,    14,    15,    35,
+      -1,    18,    -1,    -1,    28,    22,    -1,    24,    -1,    45,
+      34,    35,    36,    37,    -1,    39,    33,    -1,    35,    43,
+      -1,    34,    35,    36,    37,    42,    39,    44,    45,     6,
+       7,     8,     9,    -1,    11,    -1,    13,    14,    15,    -1,
+      -1,    18,    -1,     6,     7,    22,    -1,    24,    11,    -1,
+      13,    14,    15,    -1,    -1,    18,    33,    -1,    35,    22,
+      -1,    24,    -1,    -1,    -1,    42,    -1,    44,     6,     7,
+      33,    -1,    35,    11,    -1,    13,    14,    15,    -1,    42,
+      18,    44,     6,     7,    22,    -1,    24,    11,    -1,    13,
+      14,    -1,    -1,    -1,    18,    33,    -1,    35,     6,     7,
+      24,     6,     7,    -1,    42,    13,    44,    -1,    13,    33,
+      18,    35,    -1,    18,    -1,    -1,    24,    -1,    42,    24,
+      16,    17,    -1,    19,    20,    21,    -1,    35,    16,    17,
+      35,    19,    20,    21,    42,    -1,    -1,    42
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+   symbol of state STATE-NUM.  */
+static const yytype_uint8 yystos[] =
+{
+       0,    50,     0,     1,     4,     6,     7,     8,     9,    11,
+      13,    14,    15,    18,    22,    24,    33,    35,    42,    44,
+      51,    52,    53,    54,    55,    59,    60,    61,    62,    64,
+      10,     5,    41,     6,     9,    59,    27,    65,    66,     6,
+      18,    42,    60,    42,    61,    62,    55,    60,    62,    64,
+       6,     7,    35,    56,    57,    58,    10,     5,    23,    55,
+      31,    32,    16,    17,    19,    20,    21,    28,    34,    35,
+      36,    37,    39,    42,    60,    62,    64,    60,    25,    26,
+      67,    60,    62,    16,    43,    43,    43,    43,     6,     7,
+      45,    65,    60,    60,    47,    56,    57,    59,    70,    71,
+      73,    74,    70,    65,    65,    62,    62,    62,    62,    62,
+      62,    64,     6,     7,    35,    47,    56,    57,    59,    60,
+      61,    62,    63,    64,    68,    69,    72,    74,    58,    71,
+      12,    12,    45,    73,     6,     7,    69,    17,    45,    72,
+      45,    48,    56,    57,    58,    73,    48,    72,    58,    46
+};
+
+#define yyerrok                (yyerrstatus = 0)
+#define yyclearin      (yychar = YYEMPTY)
+#define YYEMPTY                (-2)
+#define YYEOF          0
+
+#define YYACCEPT       goto yyacceptlab
+#define YYABORT                goto yyabortlab
+#define YYERROR                goto yyerrorlab
+
+
+/* Like YYERROR except do call yyerror.  This remains here temporarily
+   to ease the transition to the new meaning of YYERROR, for GCC.
+   Once GCC version 2 has supplanted version 1, this can go.  */
+
+#define YYFAIL         goto yyerrlab
+
+#define YYRECOVERING()  (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value)                                 \
+do                                                             \
+  if (yychar == YYEMPTY && yylen == 1)                         \
+    {                                                          \
+      yychar = (Token);                                                \
+      yylval = (Value);                                                \
+      yytoken = YYTRANSLATE (yychar);                          \
+      YYPOPSTACK (1);                                          \
+      goto yybackup;                                           \
+    }                                                          \
+  else                                                         \
+    {                                                          \
+      yyerror (scanner, YY_("syntax error: cannot back up")); \
+      YYERROR;                                                 \
+    }                                                          \
+while (YYID (0))
+
+
+#define YYTERROR       1
+#define YYERRCODE      256
+
+
+/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
+   If N is 0, then set CURRENT to the empty location which ends
+   the previous symbol: RHS[0] (always defined).  */
+
+#define YYRHSLOC(Rhs, K) ((Rhs)[K])
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N)                               \
+    do                                                                 \
+      if (YYID (N))                                                    \
+       {                                                               \
+         (Current).first_line   = YYRHSLOC (Rhs, 1).first_line;        \
+         (Current).first_column = YYRHSLOC (Rhs, 1).first_column;      \
+         (Current).last_line    = YYRHSLOC (Rhs, N).last_line;         \
+         (Current).last_column  = YYRHSLOC (Rhs, N).last_column;       \
+       }                                                               \
+      else                                                             \
+       {                                                               \
+         (Current).first_line   = (Current).last_line   =              \
+           YYRHSLOC (Rhs, 0).last_line;                                \
+         (Current).first_column = (Current).last_column =              \
+           YYRHSLOC (Rhs, 0).last_column;                              \
+       }                                                               \
+    while (YYID (0))
+#endif
+
+
+/* YY_LOCATION_PRINT -- Print the location on the stream.
+   This macro was not mandated originally: define only if we know
+   we won't break user code: when these are the locations we know.  */
+
+#ifndef YY_LOCATION_PRINT
+# if YYLTYPE_IS_TRIVIAL
+#  define YY_LOCATION_PRINT(File, Loc)                 \
+     fprintf (File, "%d.%d-%d.%d",                     \
+             (Loc).first_line, (Loc).first_column,     \
+             (Loc).last_line,  (Loc).last_column)
+# else
+#  define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+# endif
+#endif
+
+
+/* YYLEX -- calling `yylex' with the right arguments.  */
+
+#ifdef YYLEX_PARAM
+# define YYLEX yylex (&yylval, YYLEX_PARAM)
+#else
+# define YYLEX yylex (&yylval, scanner)
+#endif
+
+/* Enable debugging if requested.  */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+#  include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+#  define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args)                       \
+do {                                           \
+  if (yydebug)                                 \
+    YYFPRINTF Args;                            \
+} while (YYID (0))
+
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)                   \
+do {                                                                     \
+  if (yydebug)                                                           \
+    {                                                                    \
+      YYFPRINTF (stderr, "%s ", Title);                                          \
+      yy_symbol_print (stderr,                                           \
+                 Type, Value, scanner); \
+      YYFPRINTF (stderr, "\n");                                                  \
+    }                                                                    \
+} while (YYID (0))
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT.  |
+`--------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, yyscan_t                 scanner)
+#else
+static void
+yy_symbol_value_print (yyoutput, yytype, yyvaluep, scanner)
+    FILE *yyoutput;
+    int yytype;
+    YYSTYPE const * const yyvaluep;
+    yyscan_t                 scanner;
+#endif
+{
+  if (!yyvaluep)
+    return;
+  YYUSE (scanner);
+# ifdef YYPRINT
+  if (yytype < YYNTOKENS)
+    YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# else
+  YYUSE (yyoutput);
+# endif
+  switch (yytype)
+    {
+      default:
+       break;
+    }
+}
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT.  |
+`--------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, yyscan_t                 scanner)
+#else
+static void
+yy_symbol_print (yyoutput, yytype, yyvaluep, scanner)
+    FILE *yyoutput;
+    int yytype;
+    YYSTYPE const * const yyvaluep;
+    yyscan_t                 scanner;
+#endif
+{
+  if (yytype < YYNTOKENS)
+    YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+  else
+    YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+  yy_symbol_value_print (yyoutput, yytype, yyvaluep, scanner);
+  YYFPRINTF (yyoutput, ")");
+}
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included).                                                   |
+`------------------------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_stack_print (yytype_int16 *bottom, yytype_int16 *top)
+#else
+static void
+yy_stack_print (bottom, top)
+    yytype_int16 *bottom;
+    yytype_int16 *top;
+#endif
+{
+  YYFPRINTF (stderr, "Stack now");
+  for (; bottom <= top; ++bottom)
+    YYFPRINTF (stderr, " %d", *bottom);
+  YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top)                           \
+do {                                                           \
+  if (yydebug)                                                 \
+    yy_stack_print ((Bottom), (Top));                          \
+} while (YYID (0))
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced.  |
+`------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_reduce_print (YYSTYPE *yyvsp, int yyrule, yyscan_t                 scanner)
+#else
+static void
+yy_reduce_print (yyvsp, yyrule, scanner)
+    YYSTYPE *yyvsp;
+    int yyrule;
+    yyscan_t                 scanner;
+#endif
+{
+  int yynrhs = yyr2[yyrule];
+  int yyi;
+  unsigned long int yylno = yyrline[yyrule];
+  YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
+            yyrule - 1, yylno);
+  /* The symbols being reduced.  */
+  for (yyi = 0; yyi < yynrhs; yyi++)
+    {
+      fprintf (stderr, "   $%d = ", yyi + 1);
+      yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
+                      &(yyvsp[(yyi + 1) - (yynrhs)])
+                                      , scanner);
+      fprintf (stderr, "\n");
+    }
+}
+
+# define YY_REDUCE_PRINT(Rule)         \
+do {                                   \
+  if (yydebug)                         \
+    yy_reduce_print (yyvsp, Rule, scanner); \
+} while (YYID (0))
+
+/* Nonzero means print parse trace.  It is left uninitialized so that
+   multiple parsers can coexist.  */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks.  */
+#ifndef        YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+   if the built-in stack extension method is used).
+
+   Do not make this value too large; the results are undefined if
+   YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
+   evaluated with infinite-precision integer arithmetic.  */
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+\f
+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+#  if defined __GLIBC__ && defined _STRING_H
+#   define yystrlen strlen
+#  else
+/* Return the length of YYSTR.  */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static YYSIZE_T
+yystrlen (const char *yystr)
+#else
+static YYSIZE_T
+yystrlen (yystr)
+    const char *yystr;
+#endif
+{
+  YYSIZE_T yylen;
+  for (yylen = 0; yystr[yylen]; yylen++)
+    continue;
+  return yylen;
+}
+#  endif
+# endif
+
+# ifndef yystpcpy
+#  if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
+#   define yystpcpy stpcpy
+#  else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+   YYDEST.  */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static char *
+yystpcpy (char *yydest, const char *yysrc)
+#else
+static char *
+yystpcpy (yydest, yysrc)
+    char *yydest;
+    const char *yysrc;
+#endif
+{
+  char *yyd = yydest;
+  const char *yys = yysrc;
+
+  while ((*yyd++ = *yys++) != '\0')
+    continue;
+
+  return yyd - 1;
+}
+#  endif
+# endif
+
+# ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+   quotes and backslashes, so that it's suitable for yyerror.  The
+   heuristic is that double-quoting is unnecessary unless the string
+   contains an apostrophe, a comma, or backslash (other than
+   backslash-backslash).  YYSTR is taken from yytname.  If YYRES is
+   null, do not copy; instead, return the length of what the result
+   would have been.  */
+static YYSIZE_T
+yytnamerr (char *yyres, const char *yystr)
+{
+  if (*yystr == '"')
+    {
+      YYSIZE_T yyn = 0;
+      char const *yyp = yystr;
+
+      for (;;)
+       switch (*++yyp)
+         {
+         case '\'':
+         case ',':
+           goto do_not_strip_quotes;
+
+         case '\\':
+           if (*++yyp != '\\')
+             goto do_not_strip_quotes;
+           /* Fall through.  */
+         default:
+           if (yyres)
+             yyres[yyn] = *yyp;
+           yyn++;
+           break;
+
+         case '"':
+           if (yyres)
+             yyres[yyn] = '\0';
+           return yyn;
+         }
+    do_not_strip_quotes: ;
+    }
+
+  if (! yyres)
+    return yystrlen (yystr);
+
+  return yystpcpy (yyres, yystr) - yyres;
+}
+# endif
+
+/* Copy into YYRESULT an error message about the unexpected token
+   YYCHAR while in state YYSTATE.  Return the number of bytes copied,
+   including the terminating null byte.  If YYRESULT is null, do not
+   copy anything; just return the number of bytes that would be
+   copied.  As a special case, return 0 if an ordinary "syntax error"
+   message will do.  Return YYSIZE_MAXIMUM if overflow occurs during
+   size calculation.  */
+static YYSIZE_T
+yysyntax_error (char *yyresult, int yystate, int yychar)
+{
+  int yyn = yypact[yystate];
+
+  if (! (YYPACT_NINF < yyn && yyn <= YYLAST))
+    return 0;
+  else
+    {
+      int yytype = YYTRANSLATE (yychar);
+      YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]);
+      YYSIZE_T yysize = yysize0;
+      YYSIZE_T yysize1;
+      int yysize_overflow = 0;
+      enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
+      char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+      int yyx;
+
+# if 0
+      /* This is so xgettext sees the translatable formats that are
+        constructed on the fly.  */
+      YY_("syntax error, unexpected %s");
+      YY_("syntax error, unexpected %s, expecting %s");
+      YY_("syntax error, unexpected %s, expecting %s or %s");
+      YY_("syntax error, unexpected %s, expecting %s or %s or %s");
+      YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s");
+# endif
+      char *yyfmt;
+      char const *yyf;
+      static char const yyunexpected[] = "syntax error, unexpected %s";
+      static char const yyexpecting[] = ", expecting %s";
+      static char const yyor[] = " or %s";
+      char yyformat[sizeof yyunexpected
+                   + sizeof yyexpecting - 1
+                   + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2)
+                      * (sizeof yyor - 1))];
+      char const *yyprefix = yyexpecting;
+
+      /* Start YYX at -YYN if negative to avoid negative indexes in
+        YYCHECK.  */
+      int yyxbegin = yyn < 0 ? -yyn : 0;
+
+      /* Stay within bounds of both yycheck and yytname.  */
+      int yychecklim = YYLAST - yyn + 1;
+      int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+      int yycount = 1;
+
+      yyarg[0] = yytname[yytype];
+      yyfmt = yystpcpy (yyformat, yyunexpected);
+
+      for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+       if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+         {
+           if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+             {
+               yycount = 1;
+               yysize = yysize0;
+               yyformat[sizeof yyunexpected - 1] = '\0';
+               break;
+             }
+           yyarg[yycount++] = yytname[yyx];
+           yysize1 = yysize + yytnamerr (0, yytname[yyx]);
+           yysize_overflow |= (yysize1 < yysize);
+           yysize = yysize1;
+           yyfmt = yystpcpy (yyfmt, yyprefix);
+           yyprefix = yyor;
+         }
+
+      yyf = YY_(yyformat);
+      yysize1 = yysize + yystrlen (yyf);
+      yysize_overflow |= (yysize1 < yysize);
+      yysize = yysize1;
+
+      if (yysize_overflow)
+       return YYSIZE_MAXIMUM;
+
+      if (yyresult)
+       {
+         /* Avoid sprintf, as that infringes on the user's name space.
+            Don't have undefined behavior even if the translation
+            produced a string with the wrong number of "%s"s.  */
+         char *yyp = yyresult;
+         int yyi = 0;
+         while ((*yyp = *yyf) != '\0')
+           {
+             if (*yyp == '%' && yyf[1] == 's' && yyi < yycount)
+               {
+                 yyp += yytnamerr (yyp, yyarg[yyi++]);
+                 yyf += 2;
+               }
+             else
+               {
+                 yyp++;
+                 yyf++;
+               }
+           }
+       }
+      return yysize;
+    }
+}
+#endif /* YYERROR_VERBOSE */
+\f
+
+/*-----------------------------------------------.
+| Release the memory associated to this symbol.  |
+`-----------------------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, yyscan_t                 scanner)
+#else
+static void
+yydestruct (yymsg, yytype, yyvaluep, scanner)
+    const char *yymsg;
+    int yytype;
+    YYSTYPE *yyvaluep;
+    yyscan_t                 scanner;
+#endif
+{
+  YYUSE (yyvaluep);
+  YYUSE (scanner);
+
+  if (!yymsg)
+    yymsg = "Deleting";
+  YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+
+  switch (yytype)
+    {
+      case 5: /* "HELP_TOPIC" */
+#line 168 "parser.y"
+       { free((yyvaluep->str));                     };
+#line 1321 "parser.cpp"
+       break;
+      case 8: /* "STR" */
+#line 168 "parser.y"
+       { free((yyvaluep->str));                     };
+#line 1326 "parser.cpp"
+       break;
+      case 9: /* "IDENTIFIER" */
+#line 168 "parser.y"
+       { free((yyvaluep->str));                     };
+#line 1331 "parser.cpp"
+       break;
+      case 25: /* "PARAM" */
+#line 169 "parser.y"
+       { if((yyvaluep->str)) free((yyvaluep->str));              };
+#line 1336 "parser.cpp"
+       break;
+      case 28: /* "CMP_OP" */
+#line 168 "parser.y"
+       { free((yyvaluep->str));                     };
+#line 1341 "parser.cpp"
+       break;
+      case 51: /* "command" */
+#line 170 "parser.y"
+       { if((yyvaluep->sel)) _gmx_selelem_free((yyvaluep->sel)); };
+#line 1346 "parser.cpp"
+       break;
+      case 52: /* "cmd_plain" */
+#line 170 "parser.y"
+       { if((yyvaluep->sel)) _gmx_selelem_free((yyvaluep->sel)); };
+#line 1351 "parser.cpp"
+       break;
+      case 55: /* "selection" */
+#line 171 "parser.y"
+       { _gmx_selelem_free_chain((yyvaluep->sel));  };
+#line 1356 "parser.cpp"
+       break;
+      case 59: /* "string" */
+#line 168 "parser.y"
+       { free((yyvaluep->str));                     };
+#line 1361 "parser.cpp"
+       break;
+      case 60: /* "sel_expr" */
+#line 172 "parser.y"
+       { _gmx_selelem_free((yyvaluep->sel));        };
+#line 1366 "parser.cpp"
+       break;
+      case 62: /* "num_expr" */
+#line 172 "parser.y"
+       { _gmx_selelem_free((yyvaluep->sel));        };
+#line 1371 "parser.cpp"
+       break;
+      case 63: /* "str_expr" */
+#line 172 "parser.y"
+       { _gmx_selelem_free((yyvaluep->sel));        };
+#line 1376 "parser.cpp"
+       break;
+      case 64: /* "pos_expr" */
+#line 172 "parser.y"
+       { _gmx_selelem_free((yyvaluep->sel));        };
+#line 1381 "parser.cpp"
+       break;
+      case 65: /* "method_params" */
+#line 173 "parser.y"
+       { _gmx_selexpr_free_params((yyvaluep->param)); };
+#line 1386 "parser.cpp"
+       break;
+      case 66: /* "method_param_list" */
+#line 173 "parser.y"
+       { _gmx_selexpr_free_params((yyvaluep->param)); };
+#line 1391 "parser.cpp"
+       break;
+      case 67: /* "method_param" */
+#line 173 "parser.y"
+       { _gmx_selexpr_free_params((yyvaluep->param)); };
+#line 1396 "parser.cpp"
+       break;
+      case 68: /* "value_list" */
+#line 174 "parser.y"
+       { _gmx_selexpr_free_values((yyvaluep->val)); };
+#line 1401 "parser.cpp"
+       break;
+      case 69: /* "value_list_contents" */
+#line 174 "parser.y"
+       { _gmx_selexpr_free_values((yyvaluep->val)); };
+#line 1406 "parser.cpp"
+       break;
+      case 70: /* "basic_value_list" */
+#line 175 "parser.y"
+       { _gmx_selexpr_free_values((yyvaluep->val)); };
+#line 1411 "parser.cpp"
+       break;
+      case 71: /* "basic_value_list_contents" */
+#line 175 "parser.y"
+       { _gmx_selexpr_free_values((yyvaluep->val)); };
+#line 1416 "parser.cpp"
+       break;
+      case 72: /* "value_item" */
+#line 174 "parser.y"
+       { _gmx_selexpr_free_values((yyvaluep->val)); };
+#line 1421 "parser.cpp"
+       break;
+      case 73: /* "basic_value_item" */
+#line 175 "parser.y"
+       { _gmx_selexpr_free_values((yyvaluep->val)); };
+#line 1426 "parser.cpp"
+       break;
+      case 74: /* "value_item_range" */
+#line 174 "parser.y"
+       { _gmx_selexpr_free_values((yyvaluep->val)); };
+#line 1431 "parser.cpp"
+       break;
+
+      default:
+       break;
+    }
+}
+\f
+
+/* Prevent warnings from -Wmissing-prototypes.  */
+
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void *YYPARSE_PARAM);
+#else
+int yyparse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
+int yyparse (yyscan_t                 scanner);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+
+
+
+
+
+/*----------.
+| yyparse.  |
+`----------*/
+
+#ifdef YYPARSE_PARAM
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void *YYPARSE_PARAM)
+#else
+int
+yyparse (YYPARSE_PARAM)
+    void *YYPARSE_PARAM;
+#endif
+#else /* ! YYPARSE_PARAM */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (yyscan_t                 scanner)
+#else
+int
+yyparse (scanner)
+    yyscan_t                 scanner;
+#endif
+#endif
+{
+  /* The look-ahead symbol.  */
+int yychar;
+
+/* The semantic value of the look-ahead symbol.  */
+YYSTYPE yylval;
+
+/* Number of syntax errors so far.  */
+int yynerrs;
+
+  int yystate;
+  int yyn;
+  int yyresult;
+  /* Number of tokens to shift before error messages enabled.  */
+  int yyerrstatus;
+  /* Look-ahead token as an internal (translated) token number.  */
+  int yytoken = 0;
+#if YYERROR_VERBOSE
+  /* Buffer for error messages, and its allocated size.  */
+  char yymsgbuf[128];
+  char *yymsg = yymsgbuf;
+  YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
+#endif
+
+  /* Three stacks and their tools:
+     `yyss': related to states,
+     `yyvs': related to semantic values,
+     `yyls': related to locations.
+
+     Refer to the stacks thru separate pointers, to allow yyoverflow
+     to reallocate them elsewhere.  */
+
+  /* The state stack.  */
+  yytype_int16 yyssa[YYINITDEPTH];
+  yytype_int16 *yyss = yyssa;
+  yytype_int16 *yyssp;
+
+  /* The semantic value stack.  */
+  YYSTYPE yyvsa[YYINITDEPTH];
+  YYSTYPE *yyvs = yyvsa;
+  YYSTYPE *yyvsp;
+
+
+
+#define YYPOPSTACK(N)   (yyvsp -= (N), yyssp -= (N))
+
+  YYSIZE_T yystacksize = YYINITDEPTH;
+
+  /* The variables used to return semantic value and location from the
+     action routines.  */
+  YYSTYPE yyval;
+
+
+  /* The number of symbols on the RHS of the reduced rule.
+     Keep to zero when no symbol should be popped.  */
+  int yylen = 0;
+
+  YYDPRINTF ((stderr, "Starting parse\n"));
+
+  yystate = 0;
+  yyerrstatus = 0;
+  yynerrs = 0;
+  yychar = YYEMPTY;            /* Cause a token to be read.  */
+
+  /* Initialize stack pointers.
+     Waste one element of value and location stack
+     so that they stay on the same level as the state stack.
+     The wasted elements are never initialized.  */
+
+  yyssp = yyss;
+  yyvsp = yyvs;
+
+  goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate.  |
+`------------------------------------------------------------*/
+ yynewstate:
+  /* In all cases, when you get here, the value and location stacks
+     have just been pushed.  So pushing a state here evens the stacks.  */
+  yyssp++;
+
+ yysetstate:
+  *yyssp = yystate;
+
+  if (yyss + yystacksize - 1 <= yyssp)
+    {
+      /* Get the current used size of the three stacks, in elements.  */
+      YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+      {
+       /* Give user a chance to reallocate the stack.  Use copies of
+          these so that the &'s don't force the real ones into
+          memory.  */
+       YYSTYPE *yyvs1 = yyvs;
+       yytype_int16 *yyss1 = yyss;
+
+
+       /* Each stack pointer address is followed by the size of the
+          data in use in that stack, in bytes.  This used to be a
+          conditional around just the two extra args, but that might
+          be undefined if yyoverflow is a macro.  */
+       yyoverflow (YY_("memory exhausted"),
+                   &yyss1, yysize * sizeof (*yyssp),
+                   &yyvs1, yysize * sizeof (*yyvsp),
+
+                   &yystacksize);
+
+       yyss = yyss1;
+       yyvs = yyvs1;
+      }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+      goto yyexhaustedlab;
+# else
+      /* Extend the stack our own way.  */
+      if (YYMAXDEPTH <= yystacksize)
+       goto yyexhaustedlab;
+      yystacksize *= 2;
+      if (YYMAXDEPTH < yystacksize)
+       yystacksize = YYMAXDEPTH;
+
+      {
+       yytype_int16 *yyss1 = yyss;
+       union yyalloc *yyptr =
+         (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+       if (! yyptr)
+         goto yyexhaustedlab;
+       YYSTACK_RELOCATE (yyss);
+       YYSTACK_RELOCATE (yyvs);
+
+#  undef YYSTACK_RELOCATE
+       if (yyss1 != yyssa)
+         YYSTACK_FREE (yyss1);
+      }
+# endif
+#endif /* no yyoverflow */
+
+      yyssp = yyss + yysize - 1;
+      yyvsp = yyvs + yysize - 1;
+
+
+      YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+                 (unsigned long int) yystacksize));
+
+      if (yyss + yystacksize - 1 <= yyssp)
+       YYABORT;
+    }
+
+  YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+  goto yybackup;
+
+/*-----------.
+| yybackup.  |
+`-----------*/
+yybackup:
+
+  /* Do appropriate processing given the current state.  Read a
+     look-ahead token if we need one and don't already have one.  */
+
+  /* First try to decide what to do without reference to look-ahead token.  */
+  yyn = yypact[yystate];
+  if (yyn == YYPACT_NINF)
+    goto yydefault;
+
+  /* Not known => get a look-ahead token if don't already have one.  */
+
+  /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol.  */
+  if (yychar == YYEMPTY)
+    {
+      YYDPRINTF ((stderr, "Reading a token: "));
+      yychar = YYLEX;
+    }
+
+  if (yychar <= YYEOF)
+    {
+      yychar = yytoken = YYEOF;
+      YYDPRINTF ((stderr, "Now at end of input.\n"));
+    }
+  else
+    {
+      yytoken = YYTRANSLATE (yychar);
+      YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
+    }
+
+  /* If the proper action on seeing token YYTOKEN is to reduce or to
+     detect an error, take that action.  */
+  yyn += yytoken;
+  if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+    goto yydefault;
+  yyn = yytable[yyn];
+  if (yyn <= 0)
+    {
+      if (yyn == 0 || yyn == YYTABLE_NINF)
+       goto yyerrlab;
+      yyn = -yyn;
+      goto yyreduce;
+    }
+
+  if (yyn == YYFINAL)
+    YYACCEPT;
+
+  /* Count tokens shifted since error; after three, turn off error
+     status.  */
+  if (yyerrstatus)
+    yyerrstatus--;
+
+  /* Shift the look-ahead token.  */
+  YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+
+  /* Discard the shifted token unless it is eof.  */
+  if (yychar != YYEOF)
+    yychar = YYEMPTY;
+
+  yystate = yyn;
+  *++yyvsp = yylval;
+
+  goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state.  |
+`-----------------------------------------------------------*/
+yydefault:
+  yyn = yydefact[yystate];
+  if (yyn == 0)
+    goto yyerrlab;
+  goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction.  |
+`-----------------------------*/
+yyreduce:
+  /* yyn is the number of a rule to reduce with.  */
+  yylen = yyr2[yyn];
+
+  /* If YYLEN is nonzero, implement the default value of the action:
+     `$$ = $1'.
+
+     Otherwise, the following line sets YYVAL to garbage.
+     This behavior is undocumented and Bison
+     users should not rely upon it.  Assigning to YYVAL
+     unconditionally makes the parser a bit smaller, and it avoids a
+     GCC warning that YYVAL may be used uninitialized.  */
+  yyval = yyvsp[1-yylen];
+
+
+  YY_REDUCE_PRINT (yyn);
+  switch (yyn)
+    {
+        case 2:
+#line 189 "parser.y"
+    { (yyval.sel) = NULL ;}
+    break;
+
+  case 3:
+#line 191 "parser.y"
+    {
+                 (yyval.sel) = _gmx_sel_append_selection((yyvsp[(2) - (2)].sel), (yyvsp[(1) - (2)].sel), scanner);
+                 if (_gmx_sel_parser_should_finish(scanner))
+                     YYACCEPT;
+             ;}
+    break;
+
+  case 4:
+#line 199 "parser.y"
+    { (yyval.sel) = (yyvsp[(1) - (2)].sel); ;}
+    break;
+
+  case 5:
+#line 201 "parser.y"
+    {
+                 (yyval.sel) = NULL;
+                 _gmx_selparser_error(scanner, "invalid selection '%s'",
+                                      _gmx_sel_lexer_pselstr(scanner));
+                 _gmx_sel_lexer_clear_method_stack(scanner);
+                 if (_gmx_sel_is_lexer_interactive(scanner))
+                 {
+                     _gmx_sel_lexer_clear_pselstr(scanner);
+                     yyerrok;
+                 }
+                 else
+                 {
+                     YYABORT;
+                 }
+             ;}
+    break;
+
+  case 6:
+#line 220 "parser.y"
+    {
+                 (yyval.sel) = NULL;
+                 _gmx_sel_handle_empty_cmd(scanner);
+             ;}
+    break;
+
+  case 7:
+#line 224 "parser.y"
+    { (yyval.sel) = NULL; ;}
+    break;
+
+  case 8:
+#line 226 "parser.y"
+    {
+                 t_selelem *s, *p;
+                 s = _gmx_sel_init_group_by_id((yyvsp[(1) - (1)].i), scanner);
+                 if (s == NULL) YYERROR;
+                 p = _gmx_sel_init_position(s, NULL, scanner);
+                 if (p == NULL) YYERROR;
+                 (yyval.sel) = _gmx_sel_init_selection(strdup(s->name), p, scanner);
+             ;}
+    break;
+
+  case 9:
+#line 235 "parser.y"
+    {
+                 t_selelem *s, *p;
+                 s = _gmx_sel_init_group_by_name((yyvsp[(1) - (1)].str), scanner);
+                 free((yyvsp[(1) - (1)].str));
+                 if (s == NULL) YYERROR;
+                 p = _gmx_sel_init_position(s, NULL, scanner);
+                 if (p == NULL) YYERROR;
+                 (yyval.sel) = _gmx_sel_init_selection(strdup(s->name), p, scanner);
+             ;}
+    break;
+
+  case 10:
+#line 245 "parser.y"
+    { (yyval.sel) = _gmx_sel_init_selection(NULL, (yyvsp[(1) - (1)].sel), scanner); ;}
+    break;
+
+  case 11:
+#line 247 "parser.y"
+    { (yyval.sel) = _gmx_sel_init_selection((yyvsp[(1) - (2)].str), (yyvsp[(2) - (2)].sel), scanner);   ;}
+    break;
+
+  case 12:
+#line 249 "parser.y"
+    { (yyval.sel) = _gmx_sel_assign_variable((yyvsp[(1) - (3)].str), (yyvsp[(3) - (3)].sel), scanner);  ;}
+    break;
+
+  case 13:
+#line 251 "parser.y"
+    { (yyval.sel) = _gmx_sel_assign_variable((yyvsp[(1) - (3)].str), (yyvsp[(3) - (3)].sel), scanner);  ;}
+    break;
+
+  case 14:
+#line 253 "parser.y"
+    { (yyval.sel) = _gmx_sel_assign_variable((yyvsp[(1) - (3)].str), (yyvsp[(3) - (3)].sel), scanner);  ;}
+    break;
+
+  case 15:
+#line 258 "parser.y"
+    { _gmx_sel_handle_help_cmd(NULL, scanner); ;}
+    break;
+
+  case 17:
+#line 262 "parser.y"
+    { _gmx_sel_handle_help_cmd((yyvsp[(2) - (2)].str), scanner); ;}
+    break;
+
+  case 18:
+#line 263 "parser.y"
+    { _gmx_sel_handle_help_cmd((yyvsp[(2) - (2)].str), scanner); ;}
+    break;
+
+  case 19:
+#line 267 "parser.y"
+    { (yyval.sel) = (yyvsp[(1) - (1)].sel); ;}
+    break;
+
+  case 20:
+#line 269 "parser.y"
+    {
+                 (yyval.sel) = _gmx_sel_init_position((yyvsp[(1) - (1)].sel), NULL, scanner);
+                 if ((yyval.sel) == NULL) YYERROR;
+             ;}
+    break;
+
+  case 21:
+#line 273 "parser.y"
+    { (yyval.sel) = (yyvsp[(2) - (3)].sel); ;}
+    break;
+
+  case 22:
+#line 275 "parser.y"
+    {
+                 (yyval.sel) = _gmx_sel_init_modifier((yyvsp[(2) - (3)].meth), (yyvsp[(3) - (3)].param), (yyvsp[(1) - (3)].sel), scanner);
+                 if ((yyval.sel) == NULL) YYERROR;
+             ;}
+    break;
+
+  case 23:
+#line 286 "parser.y"
+    { (yyval.r) = (yyvsp[(1) - (1)].i); ;}
+    break;
+
+  case 24:
+#line 287 "parser.y"
+    { (yyval.r) = -(yyvsp[(2) - (2)].i); ;}
+    break;
+
+  case 25:
+#line 291 "parser.y"
+    { (yyval.r) = (yyvsp[(1) - (1)].r); ;}
+    break;
+
+  case 26:
+#line 292 "parser.y"
+    { (yyval.r) = -(yyvsp[(2) - (2)].r); ;}
+    break;
+
+  case 27:
+#line 295 "parser.y"
+    { (yyval.r) = (yyvsp[(1) - (1)].r); ;}
+    break;
+
+  case 28:
+#line 296 "parser.y"
+    { (yyval.r) = (yyvsp[(1) - (1)].r); ;}
+    break;
+
+  case 29:
+#line 299 "parser.y"
+    { (yyval.str) = (yyvsp[(1) - (1)].str); ;}
+    break;
+
+  case 30:
+#line 300 "parser.y"
+    { (yyval.str) = (yyvsp[(1) - (1)].str); ;}
+    break;
+
+  case 31:
+#line 309 "parser.y"
+    {
+                 (yyval.sel) = _gmx_selelem_create(SEL_BOOLEAN);
+                 (yyval.sel)->u.boolt = BOOL_NOT;
+                 (yyval.sel)->child = (yyvsp[(2) - (2)].sel);
+             ;}
+    break;
+
+  case 32:
+#line 315 "parser.y"
+    {
+                 (yyval.sel) = _gmx_selelem_create(SEL_BOOLEAN);
+                 (yyval.sel)->u.boolt = BOOL_AND;
+                 (yyval.sel)->child = (yyvsp[(1) - (3)].sel); (yyval.sel)->child->next = (yyvsp[(3) - (3)].sel);
+             ;}
+    break;
+
+  case 33:
+#line 321 "parser.y"
+    {
+                 (yyval.sel) = _gmx_selelem_create(SEL_BOOLEAN);
+                 (yyval.sel)->u.boolt = BOOL_OR;
+                 (yyval.sel)->child = (yyvsp[(1) - (3)].sel); (yyval.sel)->child->next = (yyvsp[(3) - (3)].sel);
+             ;}
+    break;
+
+  case 34:
+#line 332 "parser.y"
+    { (yyval.sel) = (yyvsp[(2) - (3)].sel); ;}
+    break;
+
+  case 35:
+#line 337 "parser.y"
+    {
+                 (yyval.sel) = _gmx_sel_init_comparison((yyvsp[(1) - (3)].sel), (yyvsp[(3) - (3)].sel), (yyvsp[(2) - (3)].str), scanner);
+                 if ((yyval.sel) == NULL) YYERROR;
+             ;}
+    break;
+
+  case 36:
+#line 345 "parser.y"
+    {
+                 (yyval.sel) = _gmx_sel_init_group_by_name((yyvsp[(2) - (2)].str), scanner);
+                 free((yyvsp[(2) - (2)].str));
+                 if ((yyval.sel) == NULL) YYERROR;
+             ;}
+    break;
+
+  case 37:
+#line 351 "parser.y"
+    {
+                 (yyval.sel) = _gmx_sel_init_group_by_id((yyvsp[(2) - (2)].i), scanner);
+                 if ((yyval.sel) == NULL) YYERROR;
+             ;}
+    break;
+
+  case 38:
+#line 358 "parser.y"
+    { (yyval.str) = NULL; ;}
+    break;
+
+  case 39:
+#line 359 "parser.y"
+    { (yyval.str) = (yyvsp[(1) - (1)].str);   ;}
+    break;
+
+  case 40:
+#line 364 "parser.y"
+    {
+                 (yyval.sel) = _gmx_sel_init_keyword((yyvsp[(2) - (2)].meth), NULL, (yyvsp[(1) - (2)].str), scanner);
+                 if ((yyval.sel) == NULL) YYERROR;
+             ;}
+    break;
+
+  case 41:
+#line 369 "parser.y"
+    {
+                 (yyval.sel) = _gmx_sel_init_keyword((yyvsp[(2) - (3)].meth), process_value_list((yyvsp[(3) - (3)].val), NULL), (yyvsp[(1) - (3)].str), scanner);
+                 if ((yyval.sel) == NULL) YYERROR;
+             ;}
+    break;
+
+  case 42:
+#line 374 "parser.y"
+    {
+                 (yyval.sel) = _gmx_sel_init_keyword((yyvsp[(2) - (3)].meth), process_value_list((yyvsp[(3) - (3)].val), NULL), (yyvsp[(1) - (3)].str), scanner);
+                 if ((yyval.sel) == NULL) YYERROR;
+             ;}
+    break;
+
+  case 43:
+#line 382 "parser.y"
+    {
+                 (yyval.sel) = _gmx_sel_init_method((yyvsp[(2) - (3)].meth), (yyvsp[(3) - (3)].param), (yyvsp[(1) - (3)].str), scanner);
+                 if ((yyval.sel) == NULL) YYERROR;
+             ;}
+    break;
+
+  case 44:
+#line 394 "parser.y"
+    {
+                 (yyval.sel) = _gmx_selelem_create(SEL_CONST);
+                 _gmx_selelem_set_vtype((yyval.sel), INT_VALUE);
+                 _gmx_selvalue_reserve(&(yyval.sel)->v, 1);
+                 (yyval.sel)->v.u.i[0] = (yyvsp[(1) - (1)].i);
+             ;}
+    break;
+
+  case 45:
+#line 401 "parser.y"
+    {
+                 (yyval.sel) = _gmx_selelem_create(SEL_CONST);
+                 _gmx_selelem_set_vtype((yyval.sel), REAL_VALUE);
+                 _gmx_selvalue_reserve(&(yyval.sel)->v, 1);
+                 (yyval.sel)->v.u.r[0] = (yyvsp[(1) - (1)].r);
+             ;}
+    break;
+
+  case 46:
+#line 411 "parser.y"
+    {
+                 (yyval.sel) = _gmx_sel_init_keyword((yyvsp[(2) - (2)].meth), NULL, (yyvsp[(1) - (2)].str), scanner);
+                 if ((yyval.sel) == NULL) YYERROR;
+             ;}
+    break;
+
+  case 47:
+#line 416 "parser.y"
+    {
+                 (yyval.sel) = _gmx_sel_init_method((yyvsp[(2) - (3)].meth), (yyvsp[(3) - (3)].param), (yyvsp[(1) - (3)].str), scanner);
+                 if ((yyval.sel) == NULL) YYERROR;
+             ;}
+    break;
+
+  case 48:
+#line 424 "parser.y"
+    { (yyval.sel) = _gmx_sel_init_arithmetic((yyvsp[(1) - (3)].sel), (yyvsp[(3) - (3)].sel), '+', scanner); ;}
+    break;
+
+  case 49:
+#line 426 "parser.y"
+    { (yyval.sel) = _gmx_sel_init_arithmetic((yyvsp[(1) - (3)].sel), (yyvsp[(3) - (3)].sel), '-', scanner); ;}
+    break;
+
+  case 50:
+#line 428 "parser.y"
+    { (yyval.sel) = _gmx_sel_init_arithmetic((yyvsp[(1) - (3)].sel), (yyvsp[(3) - (3)].sel), '*', scanner); ;}
+    break;
+
+  case 51:
+#line 430 "parser.y"
+    { (yyval.sel) = _gmx_sel_init_arithmetic((yyvsp[(1) - (3)].sel), (yyvsp[(3) - (3)].sel), '/', scanner); ;}
+    break;
+
+  case 52:
+#line 432 "parser.y"
+    { (yyval.sel) = _gmx_sel_init_arithmetic((yyvsp[(2) - (2)].sel), NULL, '-', scanner); ;}
+    break;
+
+  case 53:
+#line 434 "parser.y"
+    { (yyval.sel) = _gmx_sel_init_arithmetic((yyvsp[(1) - (3)].sel), (yyvsp[(3) - (3)].sel), '^', scanner); ;}
+    break;
+
+  case 54:
+#line 435 "parser.y"
+    { (yyval.sel) = (yyvsp[(2) - (3)].sel); ;}
+    break;
+
+  case 55:
+#line 443 "parser.y"
+    {
+                 (yyval.sel) = _gmx_selelem_create(SEL_CONST);
+                 _gmx_selelem_set_vtype((yyval.sel), STR_VALUE);
+                 _gmx_selvalue_reserve(&(yyval.sel)->v, 1);
+                 (yyval.sel)->v.u.s[0] = (yyvsp[(1) - (1)].str);
+             ;}
+    break;
+
+  case 56:
+#line 450 "parser.y"
+    {
+                 (yyval.sel) = _gmx_sel_init_keyword((yyvsp[(2) - (2)].meth), NULL, (yyvsp[(1) - (2)].str), scanner);
+                 if ((yyval.sel) == NULL) YYERROR;
+             ;}
+    break;
+
+  case 57:
+#line 462 "parser.y"
+    { (yyval.sel) = _gmx_sel_init_const_position((yyvsp[(2) - (7)].r), (yyvsp[(4) - (7)].r), (yyvsp[(6) - (7)].r)); ;}
+    break;
+
+  case 58:
+#line 466 "parser.y"
+    { (yyval.sel) = (yyvsp[(2) - (3)].sel); ;}
+    break;
+
+  case 59:
+#line 471 "parser.y"
+    {
+                 (yyval.sel) = _gmx_sel_init_method((yyvsp[(1) - (2)].meth), (yyvsp[(2) - (2)].param), NULL, scanner);
+                 if ((yyval.sel) == NULL) YYERROR;
+             ;}
+    break;
+
+  case 60:
+#line 479 "parser.y"
+    {
+                 (yyval.sel) = _gmx_sel_init_position((yyvsp[(3) - (3)].sel), (yyvsp[(1) - (3)].str), scanner);
+                 if ((yyval.sel) == NULL) YYERROR;
+             ;}
+    break;
+
+  case 61:
+#line 490 "parser.y"
+    { (yyval.sel) = _gmx_sel_init_variable_ref((yyvsp[(1) - (1)].sel)); ;}
+    break;
+
+  case 62:
+#line 494 "parser.y"
+    { (yyval.sel) = _gmx_sel_init_variable_ref((yyvsp[(1) - (1)].sel)); ;}
+    break;
+
+  case 63:
+#line 498 "parser.y"
+    { (yyval.sel) = _gmx_sel_init_variable_ref((yyvsp[(1) - (1)].sel)); ;}
+    break;
+
+  case 64:
+#line 507 "parser.y"
+    { (yyval.param) = process_param_list((yyvsp[(1) - (1)].param)); ;}
+    break;
+
+  case 65:
+#line 509 "parser.y"
+    { (yyval.param) = process_param_list((yyvsp[(1) - (2)].param)); ;}
+    break;
+
+  case 66:
+#line 513 "parser.y"
+    { (yyval.param) = NULL;              ;}
+    break;
+
+  case 67:
+#line 515 "parser.y"
+    { (yyvsp[(2) - (2)].param)->next = (yyvsp[(1) - (2)].param); (yyval.param) = (yyvsp[(2) - (2)].param); ;}
+    break;
+
+  case 68:
+#line 520 "parser.y"
+    {
+                 (yyval.param) = _gmx_selexpr_create_param((yyvsp[(1) - (2)].str));
+                 (yyval.param)->value = process_value_list((yyvsp[(2) - (2)].val), &(yyval.param)->nval);
+             ;}
+    break;
+
+  case 69:
+#line 526 "parser.y"
+    { (yyval.val) = NULL; ;}
+    break;
+
+  case 70:
+#line 527 "parser.y"
+    { (yyval.val) = (yyvsp[(1) - (1)].val);   ;}
+    break;
+
+  case 71:
+#line 528 "parser.y"
+    { (yyval.val) = (yyvsp[(2) - (3)].val);   ;}
+    break;
+
+  case 72:
+#line 532 "parser.y"
+    { (yyval.val) = (yyvsp[(1) - (1)].val); ;}
+    break;
+
+  case 73:
+#line 534 "parser.y"
+    { (yyvsp[(2) - (2)].val)->next = (yyvsp[(1) - (2)].val); (yyval.val) = (yyvsp[(2) - (2)].val); ;}
+    break;
+
+  case 74:
+#line 536 "parser.y"
+    { (yyvsp[(3) - (3)].val)->next = (yyvsp[(1) - (3)].val); (yyval.val) = (yyvsp[(3) - (3)].val); ;}
+    break;
+
+  case 75:
+#line 540 "parser.y"
+    { (yyval.val) = (yyvsp[(1) - (1)].val); ;}
+    break;
+
+  case 76:
+#line 541 "parser.y"
+    { (yyval.val) = (yyvsp[(2) - (3)].val); ;}
+    break;
+
+  case 77:
+#line 545 "parser.y"
+    { (yyval.val) = (yyvsp[(1) - (1)].val); ;}
+    break;
+
+  case 78:
+#line 547 "parser.y"
+    { (yyvsp[(2) - (2)].val)->next = (yyvsp[(1) - (2)].val); (yyval.val) = (yyvsp[(2) - (2)].val); ;}
+    break;
+
+  case 79:
+#line 549 "parser.y"
+    { (yyvsp[(3) - (3)].val)->next = (yyvsp[(1) - (3)].val); (yyval.val) = (yyvsp[(3) - (3)].val); ;}
+    break;
+
+  case 80:
+#line 553 "parser.y"
+    { (yyval.val) = _gmx_selexpr_create_value_expr((yyvsp[(1) - (1)].sel)); ;}
+    break;
+
+  case 81:
+#line 555 "parser.y"
+    { (yyval.val) = _gmx_selexpr_create_value_expr((yyvsp[(1) - (1)].sel)); ;}
+    break;
+
+  case 82:
+#line 557 "parser.y"
+    { (yyval.val) = _gmx_selexpr_create_value_expr((yyvsp[(1) - (1)].sel)); ;}
+    break;
+
+  case 83:
+#line 559 "parser.y"
+    { (yyval.val) = _gmx_selexpr_create_value_expr((yyvsp[(1) - (1)].sel)); ;}
+    break;
+
+  case 84:
+#line 560 "parser.y"
+    { (yyval.val) = (yyvsp[(1) - (1)].val); ;}
+    break;
+
+  case 85:
+#line 565 "parser.y"
+    {
+                 (yyval.val) = _gmx_selexpr_create_value(INT_VALUE);
+                 (yyval.val)->u.i.i1 = (yyval.val)->u.i.i2 = (yyvsp[(1) - (1)].r);
+             ;}
+    break;
+
+  case 86:
+#line 570 "parser.y"
+    {
+                 (yyval.val) = _gmx_selexpr_create_value(REAL_VALUE);
+                 (yyval.val)->u.r.r1 = (yyval.val)->u.r.r2 = (yyvsp[(1) - (1)].r);
+             ;}
+    break;
+
+  case 87:
+#line 575 "parser.y"
+    {
+                 (yyval.val) = _gmx_selexpr_create_value(STR_VALUE);
+                 (yyval.val)->u.s = (yyvsp[(1) - (1)].str);
+             ;}
+    break;
+
+  case 88:
+#line 579 "parser.y"
+    { (yyval.val) = (yyvsp[(1) - (1)].val); ;}
+    break;
+
+  case 89:
+#line 584 "parser.y"
+    {
+                 (yyval.val) = _gmx_selexpr_create_value(INT_VALUE);
+                 (yyval.val)->u.i.i1 = (yyvsp[(1) - (3)].r); (yyval.val)->u.i.i2 = (yyvsp[(3) - (3)].r);
+             ;}
+    break;
+
+  case 90:
+#line 589 "parser.y"
+    {
+                 (yyval.val) = _gmx_selexpr_create_value(REAL_VALUE);
+                 (yyval.val)->u.r.r1 = (yyvsp[(1) - (3)].r); (yyval.val)->u.r.r2 = (yyvsp[(3) - (3)].r);
+             ;}
+    break;
+
+  case 91:
+#line 594 "parser.y"
+    {
+                 (yyval.val) = _gmx_selexpr_create_value(REAL_VALUE);
+                 (yyval.val)->u.r.r1 = (yyvsp[(1) - (3)].r); (yyval.val)->u.r.r2 = (yyvsp[(3) - (3)].r);
+             ;}
+    break;
+
+
+/* Line 1267 of yacc.c.  */
+#line 2313 "parser.cpp"
+      default: break;
+    }
+  YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
+
+  YYPOPSTACK (yylen);
+  yylen = 0;
+  YY_STACK_PRINT (yyss, yyssp);
+
+  *++yyvsp = yyval;
+
+
+  /* Now `shift' the result of the reduction.  Determine what state
+     that goes to, based on the state we popped back to and the rule
+     number reduced by.  */
+
+  yyn = yyr1[yyn];
+
+  yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+  if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+    yystate = yytable[yystate];
+  else
+    yystate = yydefgoto[yyn - YYNTOKENS];
+
+  goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+  /* If not already recovering from an error, report this error.  */
+  if (!yyerrstatus)
+    {
+      ++yynerrs;
+#if ! YYERROR_VERBOSE
+      yyerror (scanner, YY_("syntax error"));
+#else
+      {
+       YYSIZE_T yysize = yysyntax_error (0, yystate, yychar);
+       if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM)
+         {
+           YYSIZE_T yyalloc = 2 * yysize;
+           if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM))
+             yyalloc = YYSTACK_ALLOC_MAXIMUM;
+           if (yymsg != yymsgbuf)
+             YYSTACK_FREE (yymsg);
+           yymsg = (char *) YYSTACK_ALLOC (yyalloc);
+           if (yymsg)
+             yymsg_alloc = yyalloc;
+           else
+             {
+               yymsg = yymsgbuf;
+               yymsg_alloc = sizeof yymsgbuf;
+             }
+         }
+
+       if (0 < yysize && yysize <= yymsg_alloc)
+         {
+           (void) yysyntax_error (yymsg, yystate, yychar);
+           yyerror (scanner, yymsg);
+         }
+       else
+         {
+           yyerror (scanner, YY_("syntax error"));
+           if (yysize != 0)
+             goto yyexhaustedlab;
+         }
+      }
+#endif
+    }
+
+
+
+  if (yyerrstatus == 3)
+    {
+      /* If just tried and failed to reuse look-ahead token after an
+        error, discard it.  */
+
+      if (yychar <= YYEOF)
+       {
+         /* Return failure if at end of input.  */
+         if (yychar == YYEOF)
+           YYABORT;
+       }
+      else
+       {
+         yydestruct ("Error: discarding",
+                     yytoken, &yylval, scanner);
+         yychar = YYEMPTY;
+       }
+    }
+
+  /* Else will try to reuse look-ahead token after shifting the error
+     token.  */
+  goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR.  |
+`---------------------------------------------------*/
+yyerrorlab:
+
+  /* Pacify compilers like GCC when the user code never invokes
+     YYERROR and the label yyerrorlab therefore never appears in user
+     code.  */
+  if (/*CONSTCOND*/ 0)
+     goto yyerrorlab;
+
+  /* Do not reclaim the symbols of the rule which action triggered
+     this YYERROR.  */
+  YYPOPSTACK (yylen);
+  yylen = 0;
+  YY_STACK_PRINT (yyss, yyssp);
+  yystate = *yyssp;
+  goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR.  |
+`-------------------------------------------------------------*/
+yyerrlab1:
+  yyerrstatus = 3;     /* Each real token shifted decrements this.  */
+
+  for (;;)
+    {
+      yyn = yypact[yystate];
+      if (yyn != YYPACT_NINF)
+       {
+         yyn += YYTERROR;
+         if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+           {
+             yyn = yytable[yyn];
+             if (0 < yyn)
+               break;
+           }
+       }
+
+      /* Pop the current state because it cannot handle the error token.  */
+      if (yyssp == yyss)
+       YYABORT;
+
+
+      yydestruct ("Error: popping",
+                 yystos[yystate], yyvsp, scanner);
+      YYPOPSTACK (1);
+      yystate = *yyssp;
+      YY_STACK_PRINT (yyss, yyssp);
+    }
+
+  if (yyn == YYFINAL)
+    YYACCEPT;
+
+  *++yyvsp = yylval;
+
+
+  /* Shift the error token.  */
+  YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
+
+  yystate = yyn;
+  goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here.  |
+`-------------------------------------*/
+yyacceptlab:
+  yyresult = 0;
+  goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here.  |
+`-----------------------------------*/
+yyabortlab:
+  yyresult = 1;
+  goto yyreturn;
+
+#ifndef yyoverflow
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here.  |
+`-------------------------------------------------*/
+yyexhaustedlab:
+  yyerror (scanner, YY_("memory exhausted"));
+  yyresult = 2;
+  /* Fall through.  */
+#endif
+
+yyreturn:
+  if (yychar != YYEOF && yychar != YYEMPTY)
+     yydestruct ("Cleanup: discarding lookahead",
+                yytoken, &yylval, scanner);
+  /* Do not reclaim the symbols of the rule which action triggered
+     this YYABORT or YYACCEPT.  */
+  YYPOPSTACK (yylen);
+  YY_STACK_PRINT (yyss, yyssp);
+  while (yyssp != yyss)
+    {
+      yydestruct ("Cleanup: popping",
+                 yystos[*yyssp], yyvsp, scanner);
+      YYPOPSTACK (1);
+    }
+#ifndef yyoverflow
+  if (yyss != yyssa)
+    YYSTACK_FREE (yyss);
+#endif
+#if YYERROR_VERBOSE
+  if (yymsg != yymsgbuf)
+    YYSTACK_FREE (yymsg);
+#endif
+  /* Make sure YYID is used.  */
+  return YYID (yyresult);
+}
+
+
+#line 600 "parser.y"
+
+
+static t_selexpr_value *
+process_value_list(t_selexpr_value *values, int *nr)
+{
+    t_selexpr_value *val, *pval, *nval;
+
+    /* Count values (if needed) and reverse list */
+    if (nr)
+    {
+        *nr  = 0;
+    }
+    pval = NULL;
+    val  = values;
+    while (val)
+    {
+        if (nr)
+        {
+            ++*nr;
+        }
+        nval = val->next;
+        val->next = pval;
+        pval = val;
+        val = nval;
+    }
+    values = pval;
+
+    return values;
+}
+
+static t_selexpr_param *
+process_param_list(t_selexpr_param *params)
+{
+    t_selexpr_param *par, *ppar, *npar;
+
+    /* Reverse list */
+    ppar = NULL;
+    par  = params;
+    while (par)
+    {
+        npar = par->next;
+        par->next = ppar;
+        ppar = par;
+        par = npar;
+    }
+    params = ppar;
+
+    return params;
+}
+
+static void
+yyerror(yyscan_t scanner, char const *s)
+{
+    _gmx_selparser_error(scanner, "%s", s);
+}
+
+
+
diff --git a/src/gromacs/selection/parser.h b/src/gromacs/selection/parser.h
new file mode 100644 (file)
index 0000000..753ddbf
--- /dev/null
@@ -0,0 +1,138 @@
+/* A Bison parser, made by GNU Bison 2.3.  */
+
+/* Skeleton interface for Bison's Yacc-like parsers in C
+
+   Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+   Free Software Foundation, Inc.
+
+   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, or (at your option)
+   any later version.
+
+   This program 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 General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
+
+/* As a special exception, you may create a larger work that contains
+   part or all of the Bison parser skeleton and distribute that work
+   under terms of your choice, so long as that work isn't itself a
+   parser generator using the skeleton or a modified version thereof
+   as a parser skeleton.  Alternatively, if you modify or redistribute
+   the parser skeleton itself, you may (at your option) remove this
+   special exception, which will cause the skeleton and the resulting
+   Bison output files to be licensed under the GNU General Public
+   License without this special exception.
+
+   This special exception was added by the Free Software Foundation in
+   version 2.2 of Bison.  */
+
+/* Tokens.  */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+   /* Put the tokens into the symbol table, so that GDB and other debuggers
+      know about them.  */
+   enum yytokentype {
+     INVALID = 258,
+     HELP = 259,
+     HELP_TOPIC = 260,
+     TOK_INT = 261,
+     TOK_REAL = 262,
+     STR = 263,
+     IDENTIFIER = 264,
+     CMD_SEP = 265,
+     GROUP = 266,
+     TO = 267,
+     VARIABLE_NUMERIC = 268,
+     VARIABLE_GROUP = 269,
+     VARIABLE_POS = 270,
+     KEYWORD_NUMERIC = 271,
+     KEYWORD_STR = 272,
+     KEYWORD_POS = 273,
+     KEYWORD_GROUP = 274,
+     METHOD_NUMERIC = 275,
+     METHOD_GROUP = 276,
+     METHOD_POS = 277,
+     MODIFIER = 278,
+     EMPTY_POSMOD = 279,
+     PARAM = 280,
+     END_OF_METHOD = 281,
+     OF = 282,
+     CMP_OP = 283,
+     PARAM_REDUCT = 284,
+     XOR = 285,
+     OR = 286,
+     AND = 287,
+     NOT = 288,
+     UNARY_NEG = 289,
+     NUM_REDUCT = 290
+   };
+#endif
+/* Tokens.  */
+#define INVALID 258
+#define HELP 259
+#define HELP_TOPIC 260
+#define TOK_INT 261
+#define TOK_REAL 262
+#define STR 263
+#define IDENTIFIER 264
+#define CMD_SEP 265
+#define GROUP 266
+#define TO 267
+#define VARIABLE_NUMERIC 268
+#define VARIABLE_GROUP 269
+#define VARIABLE_POS 270
+#define KEYWORD_NUMERIC 271
+#define KEYWORD_STR 272
+#define KEYWORD_POS 273
+#define KEYWORD_GROUP 274
+#define METHOD_NUMERIC 275
+#define METHOD_GROUP 276
+#define METHOD_POS 277
+#define MODIFIER 278
+#define EMPTY_POSMOD 279
+#define PARAM 280
+#define END_OF_METHOD 281
+#define OF 282
+#define CMP_OP 283
+#define PARAM_REDUCT 284
+#define XOR 285
+#define OR 286
+#define AND 287
+#define NOT 288
+#define UNARY_NEG 289
+#define NUM_REDUCT 290
+
+
+
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+#line 69 "parser.y"
+{
+    int                         i;
+    real                        r;
+    char                       *str;
+    struct gmx_ana_selmethod_t *meth;
+
+    struct t_selelem           *sel;
+
+    struct t_selexpr_value     *val;
+    struct t_selexpr_param     *param;
+}
+/* Line 1489 of yacc.c.  */
+#line 131 "parser.h"
+       YYSTYPE;
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+
+
+
diff --git a/src/gromacs/selection/parser.y b/src/gromacs/selection/parser.y
new file mode 100644 (file)
index 0000000..aab69f5
--- /dev/null
@@ -0,0 +1,656 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief Grammar description and parser for the selection language.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_selection
+ */
+%{
+/*! \internal \file parser.cpp
+ * \brief Generated (from parser.y by Bison) parser for the selection language.
+ *
+ * \ingroup module_selection
+ */
+/*! \internal \file parser.h
+ * \brief Generated (from parser.y by Bison) parser include file.
+ *
+ * \ingroup module_selection
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+
+#include <string2.h>
+
+#include "parsetree.h"
+#include "selelem.h"
+
+#include "scanner.h"
+
+static t_selexpr_value *
+process_value_list(t_selexpr_value *values, int *nr);
+static t_selexpr_param *
+process_param_list(t_selexpr_param *params);
+
+static void
+yyerror(yyscan_t, char const *s);
+%}
+
+%union{
+    int                         i;
+    real                        r;
+    char                       *str;
+    struct gmx_ana_selmethod_t *meth;
+
+    struct t_selelem           *sel;
+
+    struct t_selexpr_value     *val;
+    struct t_selexpr_param     *param;
+};
+/* NOTE: The Intel compiler seems to report warnings for the above line about
+ * "definition at end of file not followed by a semicolon or a declarator".
+ * This is due to the compiler misinterpreting #line directives in the
+ * generated files parser.c/.h, and changing them would be more trouble than
+ * it's worth. */
+
+/* Invalid token to report lexer errors */
+%token INVALID
+
+/* Tokens for help requests */
+%token         HELP
+%token <str>   HELP_TOPIC
+
+/* Simple input tokens */
+%token <i>     TOK_INT
+%token <r>     TOK_REAL
+%token <str>   STR
+%token <str>   IDENTIFIER
+%token         CMD_SEP
+
+/* Simple keyword tokens */
+%token         GROUP
+%token         TO
+
+/* Variable tokens */
+%token <sel>   VARIABLE_NUMERIC
+%token <sel>   VARIABLE_GROUP
+%token <sel>   VARIABLE_POS
+
+/* Selection method tokens */
+%token <meth>  KEYWORD_NUMERIC
+%token <meth>  KEYWORD_STR
+%token <str>   KEYWORD_POS
+%token <meth>  KEYWORD_GROUP
+%token <meth>  METHOD_NUMERIC
+%token <meth>  METHOD_GROUP
+%token <meth>  METHOD_POS
+%token <meth>  MODIFIER
+/* Empty token that should precede any non-position KEYWORD/METHOD token that
+ * is not preceded by KEYWORD_POS. This is used to work around reduce/reduce
+ * conflicts that appear when a lookahead token would require a reduction of
+ * a rule with empty RHS before shifting, and there is an alternative reduction
+ * available. Replacing the empty RHS with a dummy token makes these conflicts
+ * only shift/reduce conflicts. Another alternative would be to remove the
+ * pos_mod non-terminal completely and split each rule that uses it into two,
+ * but this would require duplicating six rules in the grammar. */
+%token         EMPTY_POSMOD
+
+%token <str>   PARAM
+%token         END_OF_METHOD
+
+%token          OF
+/* Comparison operators have lower precedence than parameter reduction
+ * to make it possible to parse, e.g., "mindist from resnr 1 < 2" without
+ * parenthesis. */
+%nonassoc <str> CMP_OP
+/* A dummy token that determines the precedence of parameter reduction */
+%nonassoc       PARAM_REDUCT
+/* Boolean operator tokens */
+%left           OR XOR
+%left           AND
+%left           NOT
+/* Arithmetic operator tokens */
+%left           '+' '-'
+%left           '*' '/'
+%right          UNARY_NEG   /* Dummy token for unary negation precedence */
+%right          '^'
+%nonassoc       NUM_REDUCT  /* Dummy token for numerical keyword reduction precedence */
+
+/* Simple non-terminals */
+%type <r>     integer_number
+%type <r>     real_number number
+%type <str>   string
+%type <str>   pos_mod
+
+/* Expression non-terminals */
+%type <sel>   commands command cmd_plain
+%type <sel>   selection
+%type <sel>   sel_expr
+%type <sel>   num_expr
+%type <sel>   str_expr
+%type <sel>   pos_expr
+
+/* Parameter/value non-terminals */
+%type <param> method_params method_param_list method_param
+%type <val>   value_list value_list_contents value_item value_item_range
+%type <val>   basic_value_list basic_value_list_contents basic_value_item
+
+%destructor { free($$);                     } HELP_TOPIC STR IDENTIFIER CMP_OP string
+%destructor { if($$) free($$);              } PARAM
+%destructor { if($$) _gmx_selelem_free($$); } command cmd_plain
+%destructor { _gmx_selelem_free_chain($$);  } selection
+%destructor { _gmx_selelem_free($$);        } sel_expr num_expr str_expr pos_expr
+%destructor { _gmx_selexpr_free_params($$); } method_params method_param_list method_param
+%destructor { _gmx_selexpr_free_values($$); } value_list value_list_contents value_item value_item_range
+%destructor { _gmx_selexpr_free_values($$); } basic_value_list basic_value_list_contents basic_value_item
+
+%expect 50
+%debug
+%pure-parser
+
+/* If you change these, you also need to update the prototype in parsetree.c. */
+%name-prefix="_gmx_sel_yyb"
+%parse-param { yyscan_t                 scanner }
+%lex-param   { yyscan_t                 scanner }
+
+%%
+
+/* The start rule: allow one or more commands */
+commands:    /* empty */        { $$ = NULL }
+           | commands command
+             {
+                 $$ = _gmx_sel_append_selection($2, $1, scanner);
+                 if (_gmx_sel_parser_should_finish(scanner))
+                     YYACCEPT;
+             }
+;
+
+/* A command is formed from an actual command and a separator */
+command:     cmd_plain CMD_SEP  { $$ = $1; }
+           | error CMD_SEP
+             {
+                 $$ = NULL;
+                 _gmx_selparser_error(scanner, "invalid selection '%s'",
+                                      _gmx_sel_lexer_pselstr(scanner));
+                 _gmx_sel_lexer_clear_method_stack(scanner);
+                 if (_gmx_sel_is_lexer_interactive(scanner))
+                 {
+                     _gmx_sel_lexer_clear_pselstr(scanner);
+                     yyerrok;
+                 }
+                 else
+                 {
+                     YYABORT;
+                 }
+             }
+;
+
+/* Commands can be selections or variable assignments */
+cmd_plain:   /* empty */
+             {
+                 $$ = NULL;
+                 _gmx_sel_handle_empty_cmd(scanner);
+             }
+           | help_request       { $$ = NULL; }
+           | TOK_INT
+             {
+                 t_selelem *s, *p;
+                 s = _gmx_sel_init_group_by_id($1, scanner);
+                 if (s == NULL) YYERROR;
+                 p = _gmx_sel_init_position(s, NULL, scanner);
+                 if (p == NULL) YYERROR;
+                 $$ = _gmx_sel_init_selection(strdup(s->name), p, scanner);
+             }
+           | string
+             {
+                 t_selelem *s, *p;
+                 s = _gmx_sel_init_group_by_name($1, scanner);
+                 free($1);
+                 if (s == NULL) YYERROR;
+                 p = _gmx_sel_init_position(s, NULL, scanner);
+                 if (p == NULL) YYERROR;
+                 $$ = _gmx_sel_init_selection(strdup(s->name), p, scanner);
+             }
+           | selection
+             { $$ = _gmx_sel_init_selection(NULL, $1, scanner); }
+           | string selection
+             { $$ = _gmx_sel_init_selection($1, $2, scanner);   }
+           | IDENTIFIER '=' sel_expr
+             { $$ = _gmx_sel_assign_variable($1, $3, scanner);  }
+           | IDENTIFIER '=' num_expr
+             { $$ = _gmx_sel_assign_variable($1, $3, scanner);  }
+           | IDENTIFIER '=' pos_expr
+             { $$ = _gmx_sel_assign_variable($1, $3, scanner);  }
+;
+
+/* Help requests */
+help_request:
+             HELP                   { _gmx_sel_handle_help_cmd(NULL, scanner); }
+           | help_topic
+;
+
+help_topic:  HELP HELP_TOPIC        { _gmx_sel_handle_help_cmd($2, scanner); }
+           | help_topic HELP_TOPIC  { _gmx_sel_handle_help_cmd($2, scanner); }
+;
+
+/* Selection is made of an expression and zero or more modifiers */
+selection:   pos_expr           { $$ = $1; }
+           | sel_expr
+             {
+                 $$ = _gmx_sel_init_position($1, NULL, scanner);
+                 if ($$ == NULL) YYERROR;
+             }
+           | '(' selection ')'  { $$ = $2; }
+           | selection MODIFIER method_params
+             {
+                 $$ = _gmx_sel_init_modifier($2, $3, $1, scanner);
+                 if ($$ == NULL) YYERROR;
+             }
+;
+
+/********************************************************************
+ * BASIC NON-TERMINAL SYMBOLS
+ ********************************************************************/
+
+integer_number:
+             TOK_INT            { $$ = $1; }
+           | '-' TOK_INT        { $$ = -$2; }
+;
+
+real_number:
+             TOK_REAL           { $$ = $1; }
+           | '-' TOK_REAL       { $$ = -$2; }
+;
+
+number:      integer_number     { $$ = $1; }
+           | real_number        { $$ = $1; }
+;
+
+string:      STR                { $$ = $1; }
+           | IDENTIFIER         { $$ = $1; }
+;
+
+/********************************************************************
+ * ATOM SELECTION EXPRESSIONS
+ ********************************************************************/
+
+/* Boolean expressions and grouping */
+sel_expr:    NOT sel_expr
+             {
+                 $$ = _gmx_selelem_create(SEL_BOOLEAN);
+                 $$->u.boolt = BOOL_NOT;
+                 $$->child = $2;
+             }
+           | sel_expr AND sel_expr
+             {
+                 $$ = _gmx_selelem_create(SEL_BOOLEAN);
+                 $$->u.boolt = BOOL_AND;
+                 $$->child = $1; $$->child->next = $3;
+             }
+           | sel_expr OR  sel_expr
+             {
+                 $$ = _gmx_selelem_create(SEL_BOOLEAN);
+                 $$->u.boolt = BOOL_OR;
+                 $$->child = $1; $$->child->next = $3;
+             }
+/*           | sel_expr XOR sel_expr
+             {
+                 $$ = _gmx_selelem_create(SEL_BOOLEAN);
+                 $$->u.boolt = BOOL_XOR;
+                 $$->child = $1; $$->child->next = $3;
+             }*/
+           | '(' sel_expr ')'   { $$ = $2; }
+;
+
+/* Numeric comparisons */
+sel_expr:    num_expr CMP_OP num_expr
+             {
+                 $$ = _gmx_sel_init_comparison($1, $3, $2, scanner);
+                 if ($$ == NULL) YYERROR;
+             }
+;
+
+/* External groups */
+sel_expr:    GROUP string
+             {
+                 $$ = _gmx_sel_init_group_by_name($2, scanner);
+                 free($2);
+                 if ($$ == NULL) YYERROR;
+             }
+           | GROUP TOK_INT
+             {
+                 $$ = _gmx_sel_init_group_by_id($2, scanner);
+                 if ($$ == NULL) YYERROR;
+             }
+;
+
+/* Position modifiers for selection methods */
+pos_mod:     EMPTY_POSMOD       { $$ = NULL; }
+           | KEYWORD_POS        { $$ = $1;   }
+;
+
+/* Keyword selections */
+sel_expr:    pos_mod KEYWORD_GROUP
+             {
+                 $$ = _gmx_sel_init_keyword($2, NULL, $1, scanner);
+                 if ($$ == NULL) YYERROR;
+             }
+           | pos_mod KEYWORD_STR basic_value_list
+             {
+                 $$ = _gmx_sel_init_keyword($2, process_value_list($3, NULL), $1, scanner);
+                 if ($$ == NULL) YYERROR;
+             }
+           | pos_mod KEYWORD_NUMERIC basic_value_list
+             {
+                 $$ = _gmx_sel_init_keyword($2, process_value_list($3, NULL), $1, scanner);
+                 if ($$ == NULL) YYERROR;
+             }
+;
+
+/* Custom selection methods */
+sel_expr:    pos_mod METHOD_GROUP method_params
+             {
+                 $$ = _gmx_sel_init_method($2, $3, $1, scanner);
+                 if ($$ == NULL) YYERROR;
+             }
+;
+
+/********************************************************************
+ * NUMERICAL EXPRESSIONS
+ ********************************************************************/
+
+/* Basic numerical values */
+num_expr:    TOK_INT
+             {
+                 $$ = _gmx_selelem_create(SEL_CONST);
+                 _gmx_selelem_set_vtype($$, INT_VALUE);
+                 _gmx_selvalue_reserve(&$$->v, 1);
+                 $$->v.u.i[0] = $1;
+             }
+           | TOK_REAL
+             {
+                 $$ = _gmx_selelem_create(SEL_CONST);
+                 _gmx_selelem_set_vtype($$, REAL_VALUE);
+                 _gmx_selvalue_reserve(&$$->v, 1);
+                 $$->v.u.r[0] = $1;
+             }
+;
+
+/* Numeric selection methods */
+num_expr:    pos_mod KEYWORD_NUMERIC    %prec NUM_REDUCT
+             {
+                 $$ = _gmx_sel_init_keyword($2, NULL, $1, scanner);
+                 if ($$ == NULL) YYERROR;
+             }
+           | pos_mod METHOD_NUMERIC method_params
+             {
+                 $$ = _gmx_sel_init_method($2, $3, $1, scanner);
+                 if ($$ == NULL) YYERROR;
+             }
+;
+
+/* Arithmetic evaluation and grouping */
+num_expr:    num_expr '+' num_expr
+             { $$ = _gmx_sel_init_arithmetic($1, $3, '+', scanner); }
+           | num_expr '-' num_expr
+             { $$ = _gmx_sel_init_arithmetic($1, $3, '-', scanner); }
+           | num_expr '*' num_expr
+             { $$ = _gmx_sel_init_arithmetic($1, $3, '*', scanner); }
+           | num_expr '/' num_expr
+             { $$ = _gmx_sel_init_arithmetic($1, $3, '/', scanner); }
+           | '-' num_expr %prec UNARY_NEG
+             { $$ = _gmx_sel_init_arithmetic($2, NULL, '-', scanner); }
+           | num_expr '^' num_expr
+             { $$ = _gmx_sel_init_arithmetic($1, $3, '^', scanner); }
+           | '(' num_expr ')'   { $$ = $2; }
+;
+
+/********************************************************************
+ * STRING EXPRESSIONS
+ ********************************************************************/
+
+str_expr:    string
+             {
+                 $$ = _gmx_selelem_create(SEL_CONST);
+                 _gmx_selelem_set_vtype($$, STR_VALUE);
+                 _gmx_selvalue_reserve(&$$->v, 1);
+                 $$->v.u.s[0] = $1;
+             }
+           | pos_mod KEYWORD_STR
+             {
+                 $$ = _gmx_sel_init_keyword($2, NULL, $1, scanner);
+                 if ($$ == NULL) YYERROR;
+             }
+;
+
+/********************************************************************
+ * POSITION EXPRESSIONS
+ ********************************************************************/
+
+/* Constant position expressions */
+pos_expr:    '[' number ',' number ',' number ']'
+             { $$ = _gmx_sel_init_const_position($2, $4, $6); }
+;
+
+/* Grouping of position expressions */
+pos_expr:    '(' pos_expr ')'   { $$ = $2; }
+;
+
+/* Expressions with a position value */
+pos_expr:    METHOD_POS method_params
+             {
+                 $$ = _gmx_sel_init_method($1, $2, NULL, scanner);
+                 if ($$ == NULL) YYERROR;
+             }
+;
+
+/* Evaluation of positions using a keyword */
+pos_expr:    KEYWORD_POS OF sel_expr    %prec PARAM_REDUCT
+             {
+                 $$ = _gmx_sel_init_position($3, $1, scanner);
+                 if ($$ == NULL) YYERROR;
+             }
+;
+
+/********************************************************************
+ * VARIABLES
+ ********************************************************************/
+
+sel_expr:    VARIABLE_GROUP
+             { $$ = _gmx_sel_init_variable_ref($1); }
+;
+
+num_expr:    VARIABLE_NUMERIC
+             { $$ = _gmx_sel_init_variable_ref($1); }
+;
+
+pos_expr:    VARIABLE_POS
+             { $$ = _gmx_sel_init_variable_ref($1); }
+;
+
+/********************************************************************
+ * METHOD PARAMETERS
+ ********************************************************************/
+
+method_params:
+             method_param_list
+             { $$ = process_param_list($1); }
+           | method_param_list END_OF_METHOD
+             { $$ = process_param_list($1); }
+;
+
+method_param_list:
+             /* empty */        { $$ = NULL;              }
+           | method_param_list method_param
+                                { $2->next = $1; $$ = $2; }
+;
+
+method_param:
+             PARAM value_list
+             {
+                 $$ = _gmx_selexpr_create_param($1);
+                 $$->value = process_value_list($2, &$$->nval);
+             }
+;
+
+value_list:  /* empty */                         { $$ = NULL; }
+           | value_list_contents                 { $$ = $1;   }
+           | '{' value_list_contents '}'         { $$ = $2;   }
+;
+
+value_list_contents:
+             value_item          { $$ = $1; }
+           | value_list_contents value_item
+                                 { $2->next = $1; $$ = $2; }
+           | value_list_contents ',' value_item
+                                 { $3->next = $1; $$ = $3; }
+;
+
+basic_value_list:
+             basic_value_list_contents           { $$ = $1; }
+           | '{' basic_value_list_contents '}'   { $$ = $2; }
+;
+
+basic_value_list_contents:
+             basic_value_item    { $$ = $1; }
+           | basic_value_list_contents basic_value_item
+                                 { $2->next = $1; $$ = $2; }
+           | basic_value_list_contents ',' basic_value_item
+                                 { $3->next = $1; $$ = $3; }
+;
+
+value_item:  sel_expr            %prec PARAM_REDUCT
+             { $$ = _gmx_selexpr_create_value_expr($1); }
+           | pos_expr            %prec PARAM_REDUCT
+             { $$ = _gmx_selexpr_create_value_expr($1); }
+           | num_expr            %prec PARAM_REDUCT
+             { $$ = _gmx_selexpr_create_value_expr($1); }
+           | str_expr            %prec PARAM_REDUCT
+             { $$ = _gmx_selexpr_create_value_expr($1); }
+           | value_item_range    { $$ = $1; }
+;
+
+basic_value_item:
+             integer_number      %prec PARAM_REDUCT
+             {
+                 $$ = _gmx_selexpr_create_value(INT_VALUE);
+                 $$->u.i.i1 = $$->u.i.i2 = $1;
+             }
+           | real_number         %prec PARAM_REDUCT
+             {
+                 $$ = _gmx_selexpr_create_value(REAL_VALUE);
+                 $$->u.r.r1 = $$->u.r.r2 = $1;
+             }
+           | string              %prec PARAM_REDUCT
+             {
+                 $$ = _gmx_selexpr_create_value(STR_VALUE);
+                 $$->u.s = $1;
+             }
+           | value_item_range    { $$ = $1; }
+;
+
+value_item_range:
+             integer_number TO integer_number
+             {
+                 $$ = _gmx_selexpr_create_value(INT_VALUE);
+                 $$->u.i.i1 = $1; $$->u.i.i2 = $3;
+             }
+           | integer_number TO real_number
+             {
+                 $$ = _gmx_selexpr_create_value(REAL_VALUE);
+                 $$->u.r.r1 = $1; $$->u.r.r2 = $3;
+             }
+           | real_number TO number
+             {
+                 $$ = _gmx_selexpr_create_value(REAL_VALUE);
+                 $$->u.r.r1 = $1; $$->u.r.r2 = $3;
+             }
+;
+
+%%
+
+static t_selexpr_value *
+process_value_list(t_selexpr_value *values, int *nr)
+{
+    t_selexpr_value *val, *pval, *nval;
+
+    /* Count values (if needed) and reverse list */
+    if (nr)
+    {
+        *nr  = 0;
+    }
+    pval = NULL;
+    val  = values;
+    while (val)
+    {
+        if (nr)
+        {
+            ++*nr;
+        }
+        nval = val->next;
+        val->next = pval;
+        pval = val;
+        val = nval;
+    }
+    values = pval;
+
+    return values;
+}
+
+static t_selexpr_param *
+process_param_list(t_selexpr_param *params)
+{
+    t_selexpr_param *par, *ppar, *npar;
+
+    /* Reverse list */
+    ppar = NULL;
+    par  = params;
+    while (par)
+    {
+        npar = par->next;
+        par->next = ppar;
+        ppar = par;
+        par = npar;
+    }
+    params = ppar;
+
+    return params;
+}
+
+static void
+yyerror(yyscan_t scanner, char const *s)
+{
+    _gmx_selparser_error(scanner, "%s", s);
+}
+
+
diff --git a/src/gromacs/selection/parsetree.cpp b/src/gromacs/selection/parsetree.cpp
new file mode 100644 (file)
index 0000000..4597b19
--- /dev/null
@@ -0,0 +1,1379 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * Implements functions in parsetree.h.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_selection
+ */
+/*! \internal
+ * \page page_module_selection_parser Selection parsing
+ *
+ * The selection parser is implemented in the following files:
+ *  - scanner.l:
+ *    Tokenizer implemented using Flex, splits the input into tokens
+ *    (scanner.c and scanner_flex.h are generated from this file).
+ *  - scanner.h, scanner_internal.h, scanner_internal.cpp:
+ *    Helper functions for scanner.l and for interfacing between
+ *    scanner.l and parser.y. Functions in scanner_internal.h are only
+ *    used from scanner.l, while scanner.h is used from the parser.
+ *  - symrec.h, symrec.cpp:
+ *    Functions used by the tokenizer to handle the symbol table, i.e.,
+ *    the recognized keywords. Some basic keywords are hardcoded into
+ *    scanner.l, but all method and variable references go through the
+ *    symbol table, as do position evaluation keywords.
+ *  - parser.y:
+ *    Semantic rules for parsing the grammar
+ *    (parser.cpp and parser.h are generated from this file by Bison).
+ *  - parsetree.h, parsetree.cpp:
+ *    Functions called from actions in parser.y to construct the
+ *    evaluation elements corresponding to different grammar elements.
+ *  - params.c:
+ *    Defines a function that processes the parameters of selection
+ *    methods and initializes the children of the method element.
+ *  - selectioncollection.h, selectioncollection.cpp:
+ *    These files define the high-level public interface to the parser
+ *    through SelectionCollection::parseFromStdin(),
+ *    SelectionCollection::parseFromFile() and
+ *    SelectionCollection::parseFromString().
+ *
+ * The basic control flow in the parser is as follows: when a parser function
+ * in SelectionCollection gets called, it performs some
+ * initialization, and then calls the _gmx_sel_yyparse() function generated
+ * by Bison. This function then calls _gmx_sel_yylex() to repeatedly read
+ * tokens from the input (more complex tasks related to token recognition
+ * and bookkeeping are done by functions in scanner_internal.cpp) and uses the
+ * grammar rules to decide what to do with them. Whenever a grammar rule
+ * matches, a corresponding function in parsetree.cpp is called to construct
+ * either a temporary representation for the object or a ::t_selelem object
+ * (some simple rules are handled internally in parser.y).
+ * When a complete selection has been parsed, the functions in parsetree.cpp
+ * also take care of updating the ::gmx_ana_selcollection_t structure
+ * appropriately.
+ *
+ * The rest of this page describes the resulting ::t_selelem object tree.
+ * Before the selections can be evaluated, this tree needs to be passed to
+ * the selection compiler, which is described on a separate page:
+ * \ref page_module_selection_compiler
+ *
+ *
+ * \section selparser_tree Element tree constructed by the parser
+ *
+ * The parser initializes the following fields in all selection elements:
+ * \c t_selelem::name, \c t_selelem::type, \c t_selelem::v\c .type,
+ * \c t_selelem::flags, \c t_selelem::child, \c t_selelem::next, and
+ * \c t_selelem::refcount.
+ * Some other fields are also initialized for particular element types as
+ * discussed below.
+ * Fields that are not initialized are set to zero, NULL, or other similar
+ * value.
+ *
+ *
+ * \subsection selparser_tree_root Root elements
+ *
+ * The parser creates a \ref SEL_ROOT selection element for each variable
+ * assignment and each selection. However, there are two exceptions that do
+ * not result in a \ref SEL_ROOT element (in these cases, only the symbol
+ * table is modified):
+ *  - Variable assignments that assign a variable to another variable.
+ *  - Variable assignments that assign a non-group constant.
+ *  .
+ * The \ref SEL_ROOT elements are linked together in a chain in the same order
+ * as in the input.
+ *
+ * The children of the \ref SEL_ROOT elements can be used to distinguish
+ * the two types of root elements from each other:
+ *  - For variable assignments, the first and only child is always
+ *    a \ref SEL_SUBEXPR element.
+ *  - For selections, the first child is a \ref SEL_EXPRESSION or a
+ *    \ref SEL_MODIFIER element that evaluates the final positions (if the
+ *    selection defines a constant position, the child is a \ref SEL_CONST).
+ *    The rest of the children are \ref SEL_MODIFIER elements with
+ *    \ref NO_VALUE, in the order given by the user.
+ *  .
+ * The name of the selection/variable is stored in \c t_selelem::cgrp\c .name.
+ * It is set to either the name provided by the user or the selection string
+ * for selections not explicitly named by the user.
+ * \ref SEL_ROOT or \ref SEL_SUBEXPR elements do not appear anywhere else.
+ *
+ *
+ * \subsection selparser_tree_const Constant elements
+ *
+ * \ref SEL_CONST elements are created for every constant that is required
+ * for later evaluation.
+ * Currently, \ref SEL_CONST elements can be present for
+ *  - selections that consist of a constant position,
+ *  - \ref GROUP_VALUE method parameters if provided using external index
+ *    groups,
+ *  .
+ * For group-valued elements, the value is stored in \c t_selelem::cgrp;
+ * other types of values are stored in \c t_selelem::v.
+ * Constants that appear as parameters for selection methods are not present
+ * in the selection tree unless they have \ref GROUP_VALUE.
+ * \ref SEL_CONST elements have no children.
+ *
+ *
+ * \subsection selparser_tree_method Method evaluation elements
+ *
+ * \ref SEL_EXPRESSION and \ref SEL_MODIFIER elements are treated very
+ * similarly. The \c gmx_ana_selmethod_t structure corresponding to the
+ * evaluation method is in \c t_selelem::method, and the method data in
+ * \c t_selelem::mdata has been allocated using sel_datafunc().
+ * If a non-standard reference position type was set, \c t_selelem::pc has
+ * also been created, but only the type has been set.
+ * All children of these elements are of the type \ref SEL_SUBEXPRREF, and
+ * each describes a selection that needs to be evaluated to obtain a value
+ * for one parameter of the method.
+ * No children are present for parameters that were given a constant
+ * non-\ref GROUP_VALUE value.
+ * The children are sorted in the order in which the parameters appear in the
+ * \ref gmx_ana_selmethod_t structure.
+ *
+ * In addition to actual selection keywords, \ref SEL_EXPRESSION elements
+ * are used internally to implement numerical comparisons (e.g., "x < 5")
+ * and keyword matching (e.g., "resnr 1 to 3" or "name CA").
+ *
+ *
+ * \subsection selparser_tree_subexpr Subexpression elements
+ *
+ * \ref SEL_SUBEXPR elements only appear for variables, as described above.
+ * \c t_selelem::name points to the name of the variable (from the
+ * \ref SEL_ROOT element).
+ * The element always has exactly one child, which represents the value of
+ * the variable.
+ * \ref SEL_SUBEXPR element is the only element type that can have
+ * \c t_selelem::refcount different from 1.
+ *
+ * \ref SEL_SUBEXPRREF elements are used for two purposes:
+ *  - Variable references that need to be evaluated (i.e., there is a
+ *    \ref SEL_SUBEXPR element for the variable) are represented using
+ *    \ref SEL_SUBEXPRREF elements.
+ *    In this case, \c t_selelem::param is NULL, and the first and only
+ *    child of the element is the \ref SEL_SUBEXPR element of the variable.
+ *    Such references can appear anywhere where the variable value
+ *    (the child of the \ref SEL_SUBEXPR element) would be valid.
+ *  - Children of \ref SEL_EXPRESSION and \ref SEL_MODIFIER elements are
+ *    always of this type. For these elements, \c t_selelem::param is
+ *    initialized to point to the parameter that receives the value from
+ *    the expression.
+ *    Each such element has exactly one child, which can be of any type;
+ *    the \ref SEL_SUBEXPR element of a variable is used if the value comes
+ *    from a variable, otherwise the child type is not \ref SEL_SUBEXPR.
+ *
+ *
+ * \subsection selparser_tree_gmx_bool Boolean elements
+ *
+ * One \ref SEL_BOOLEAN element is created for each gmx_boolean keyword in the
+ * input, and the tree structure represents the evaluation order.
+ * The \c t_selelem::boolt type gives the type of the operation.
+ * Each element has exactly two children (one for \ref BOOL_NOT elements),
+ * which are in the order given in the input.
+ * The children always have \ref GROUP_VALUE, but different element types
+ * are possible.
+ *
+ *
+ * \subsection selparser_tree_arith Arithmetic elements
+ *
+ * One \ref SEL_ARITHMETIC element is created for each arithmetic operation in
+ * the input, and the tree structure represents the evaluation order.
+ * The \c t_selelem::optype type gives the name of the operation.
+ * Each element has exactly two children (one for unary negation elements),
+ * which are in the order given in the input.
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdarg.h>
+
+#include <futil.h>
+#include <smalloc.h>
+#include <string2.h>
+
+#include "gromacs/errorreporting/abstracterrorreporter.h"
+#include "gromacs/errorreporting/errorcontext.h"
+#include "gromacs/fatalerror/fatalerror.h"
+
+#include "gromacs/selection/poscalc.h"
+#include "gromacs/selection/selection.h"
+#include "gromacs/selection/selmethod.h"
+
+#include "keywords.h"
+#include "parsetree.h"
+#include "selectioncollection-impl.h"
+#include "selelem.h"
+#include "selhelp.h"
+#include "symrec.h"
+
+#include "scanner.h"
+
+void
+_gmx_selparser_warning(yyscan_t scanner, const char *fmt, ...)
+{
+    gmx::AbstractErrorReporter *errors = _gmx_sel_lexer_error_reporter(scanner);
+    char buf[1024];
+    va_list ap;
+    va_start(ap, fmt);
+    vsprintf(buf, fmt, ap);
+    va_end(ap);
+    errors->warning(buf);
+}
+
+void
+_gmx_selparser_error(yyscan_t scanner, const char *fmt, ...)
+{
+    gmx::AbstractErrorReporter *errors = _gmx_sel_lexer_error_reporter(scanner);
+    char buf[1024];
+    va_list ap;
+    va_start(ap, fmt);
+    vsprintf(buf, fmt, ap);
+    va_end(ap);
+    errors->error(buf);
+}
+
+/*!
+ * \param[in] type  Type for the new value.
+ * \returns   Pointer to the newly allocated value.
+ */
+t_selexpr_value *
+_gmx_selexpr_create_value(e_selvalue_t type)
+{
+    t_selexpr_value *value;
+    snew(value, 1);
+    value->type  = type;
+    value->bExpr = FALSE;
+    value->next  = NULL;
+    return value;
+}
+
+/*!
+ * \param[in] expr  Expression for the value.
+ * \returns   Pointer to the newly allocated value.
+ */
+t_selexpr_value *
+_gmx_selexpr_create_value_expr(t_selelem *expr)
+{
+    t_selexpr_value *value;
+    snew(value, 1);
+    value->type   = expr->v.type;
+    value->bExpr  = TRUE;
+    value->u.expr = expr;
+    value->next   = NULL;
+    return value;
+}
+
+/*!
+ * \param[in] name Name for the new parameter.
+ * \returns   Pointer to the newly allocated parameter.
+ *
+ * No copy of \p name is made.
+ */
+t_selexpr_param *
+_gmx_selexpr_create_param(char *name)
+{
+    t_selexpr_param *param;
+    snew(param, 1);
+    param->name = name;
+    param->next = NULL;
+    return param;
+}
+
+/*!
+ * \param value Pointer to the beginning of the value list to free.
+ *
+ * The expressions referenced by the values are also freed
+ * (to prevent this, set the expression to NULL before calling the function).
+ */
+void
+_gmx_selexpr_free_values(t_selexpr_value *value)
+{
+    t_selexpr_value *old;
+
+    while (value)
+    {
+        if (value->bExpr)
+        {
+            if (value->u.expr)
+            {
+                _gmx_selelem_free(value->u.expr);
+            }
+        }
+        else if (value->type == STR_VALUE)
+        {
+            sfree(value->u.s);
+        }
+        old = value;
+        value = value->next;
+        sfree(old);
+    }
+}
+
+/*!
+ * \param param Pointer the the beginning of the parameter list to free.
+ *
+ * The values of the parameters are freed with free_selexpr_values().
+ */
+void
+_gmx_selexpr_free_params(t_selexpr_param *param)
+{
+    t_selexpr_param *old;
+
+    while (param)
+    {
+        _gmx_selexpr_free_values(param->value);
+        old = param;
+        param = param->next;
+        sfree(old->name);
+        sfree(old);
+    }
+}
+
+/*!
+ * \param[in,out] sel  Root of the selection element tree to initialize.
+ * \param[in]     scanner Scanner data structure.
+ * \returns       0 on success, an error code on error.
+ *
+ * Propagates the \ref SEL_DYNAMIC flag from the children of \p sel to \p sel
+ * (if any child of \p sel is dynamic, \p sel is also marked as such).
+ * The \ref SEL_DYNAMIC flag is also set for \ref SEL_EXPRESSION elements with
+ * a dynamic method.
+ * Also, sets one of the \ref SEL_SINGLEVAL, \ref SEL_ATOMVAL, or
+ * \ref SEL_VARNUMVAL flags, either based on the children or on the type of
+ * the selection method.
+ * If the types of the children conflict, an error is returned.
+ *
+ * The flags of the children of \p sel are also updated if not done earlier.
+ * The flags are initialized only once for any element; if \ref SEL_FLAGSSET
+ * is set for an element, the function returns immediately, and the recursive
+ * operation does not descend beyond such elements.
+ */
+int
+_gmx_selelem_update_flags(t_selelem *sel, yyscan_t scanner)
+{
+    t_selelem          *child;
+    int                 rc;
+    gmx_bool                bUseChildType=FALSE;
+    gmx_bool                bOnlySingleChildren;
+
+    /* Return if the flags have already been set */
+    if (sel->flags & SEL_FLAGSSET)
+    {
+        return 0;
+    }
+    /* Set the flags based on the current element type */
+    switch (sel->type)
+    {
+        case SEL_CONST:
+        case SEL_GROUPREF:
+            sel->flags |= SEL_SINGLEVAL;
+            bUseChildType = FALSE;
+            break;
+
+        case SEL_EXPRESSION:
+            if (sel->u.expr.method->flags & SMETH_DYNAMIC)
+            {
+                sel->flags |= SEL_DYNAMIC;
+            }
+            if (sel->u.expr.method->flags & SMETH_SINGLEVAL)
+            {
+                sel->flags |= SEL_SINGLEVAL;
+            }
+            else if (sel->u.expr.method->flags & SMETH_VARNUMVAL)
+            {
+                sel->flags |= SEL_VARNUMVAL;
+            }
+            else
+            {
+                sel->flags |= SEL_ATOMVAL;
+            }
+            bUseChildType = FALSE;
+            break;
+
+        case SEL_ARITHMETIC:
+            sel->flags |= SEL_ATOMVAL;
+            bUseChildType = FALSE;
+            break;
+
+        case SEL_MODIFIER:
+            if (sel->v.type != NO_VALUE)
+            {
+                sel->flags |= SEL_VARNUMVAL;
+            }
+            bUseChildType = FALSE;
+            break;
+
+        case SEL_ROOT:
+            bUseChildType = FALSE;
+            break;
+
+        case SEL_BOOLEAN:
+        case SEL_SUBEXPR:
+        case SEL_SUBEXPRREF:
+            bUseChildType = TRUE;
+            break;
+    }
+    /* Loop through children to propagate their flags upwards */
+    bOnlySingleChildren = TRUE;
+    child = sel->child;
+    while (child)
+    {
+        /* Update the child */
+        rc = _gmx_selelem_update_flags(child, scanner);
+        if (rc != 0)
+        {
+            return rc;
+        }
+        /* Propagate the dynamic flag */
+        sel->flags |= (child->flags & SEL_DYNAMIC);
+        /* Propagate the type flag if necessary and check for problems */
+        if (bUseChildType)
+        {
+            if ((sel->flags & SEL_VALTYPEMASK)
+                && !(sel->flags & child->flags & SEL_VALTYPEMASK))
+            {
+                _gmx_selparser_error(scanner, "invalid combination of selection expressions");
+                return gmx::eeInvalidInput;
+            }
+            sel->flags |= (child->flags & SEL_VALTYPEMASK);
+        }
+        if (!(child->flags & SEL_SINGLEVAL))
+        {
+            bOnlySingleChildren = FALSE;
+        }
+
+        child = child->next;
+    }
+    /* For arithmetic expressions consisting only of single values,
+     * the result is also a single value. */
+    if (sel->type == SEL_ARITHMETIC && bOnlySingleChildren)
+    {
+        sel->flags = (sel->flags & ~SEL_VALTYPEMASK) | SEL_SINGLEVAL;
+    }
+    /* For root elements, the type should be propagated here, after the
+     * children have been updated. */
+    if (sel->type == SEL_ROOT)
+    {
+        sel->flags |= (sel->child->flags & SEL_VALTYPEMASK);
+    }
+    /* Mark that the flags are set */
+    sel->flags |= SEL_FLAGSSET;
+    return 0;
+}
+
+/*!
+ * \param[in,out] sel    Selection element to initialize.
+ * \param[in]     scanner Scanner data structure.
+ *
+ * A deep copy of the parameters is made to allow several
+ * expressions with the same method to coexist peacefully.
+ * Calls sel_datafunc() if one is specified for the method.
+ */
+void
+_gmx_selelem_init_method_params(t_selelem *sel, yyscan_t scanner)
+{
+    int                 nparams;
+    gmx_ana_selparam_t *orgparam;
+    gmx_ana_selparam_t *param;
+    int                 i;
+    void               *mdata;
+
+    nparams   = sel->u.expr.method->nparams;
+    orgparam  = sel->u.expr.method->param;
+    snew(param, nparams);
+    memcpy(param, orgparam, nparams*sizeof(gmx_ana_selparam_t));
+    for (i = 0; i < nparams; ++i)
+    {
+        param[i].flags &= ~SPAR_SET;
+        _gmx_selvalue_setstore(&param[i].val, NULL);
+        if (param[i].flags & SPAR_VARNUM)
+        {
+            param[i].val.nr = -1;
+        }
+        /* Duplicate the enum value array if it is given statically */
+        if ((param[i].flags & SPAR_ENUMVAL) && orgparam[i].val.u.ptr != NULL)
+        {
+            int n;
+
+            /* Count the values */
+            n = 1;
+            while (orgparam[i].val.u.s[n] != NULL)
+            {
+                ++n;
+            }
+            _gmx_selvalue_reserve(&param[i].val, n+1);
+            memcpy(param[i].val.u.s, orgparam[i].val.u.s,
+                   (n+1)*sizeof(param[i].val.u.s[0]));
+        }
+    }
+    mdata = NULL;
+    if (sel->u.expr.method->init_data)
+    {
+        mdata = sel->u.expr.method->init_data(nparams, param);
+        if (mdata == NULL)
+        {
+            GMX_ERROR_NORET(gmx::eeInvalidValue, "Method data initialization failed");
+        }
+    }
+    if (sel->u.expr.method->set_poscoll)
+    {
+        gmx_ana_selcollection_t *sc = _gmx_sel_lexer_selcollection(scanner);
+
+        sel->u.expr.method->set_poscoll(sc->pcc, mdata);
+    }
+    /* Store the values */
+    sel->u.expr.method->param = param;
+    sel->u.expr.mdata         = mdata;
+}
+
+/*!
+ * \param[in,out] sel    Selection element to initialize.
+ * \param[in]     method Selection method to set.
+ * \param[in]     scanner Scanner data structure.
+ *
+ * Makes a copy of \p method and stores it in \p sel->u.expr.method,
+ * and calls _gmx_selelem_init_method_params();
+ */
+void
+_gmx_selelem_set_method(t_selelem *sel, gmx_ana_selmethod_t *method,
+                        yyscan_t scanner)
+{
+    int      i;
+
+    _gmx_selelem_set_vtype(sel, method->type);
+    sel->name   = method->name;
+    snew(sel->u.expr.method, 1);
+    memcpy(sel->u.expr.method, method, sizeof(gmx_ana_selmethod_t));
+    _gmx_selelem_init_method_params(sel, scanner);
+}
+
+/*! \brief
+ * Initializes the reference position calculation for a \ref SEL_EXPRESSION
+ * element.
+ *
+ * \param[in,out] pcc    Position calculation collection to use.
+ * \param[in,out] sel    Selection element to initialize.
+ * \param[in]     rpost  Reference position type to use (NULL = default).
+ * \param[in]     scanner Scanner data structure.
+ * \returns       0 on success, a non-zero error code on error.
+ */
+static int
+set_refpos_type(gmx_ana_poscalc_coll_t *pcc, t_selelem *sel, const char *rpost,
+                yyscan_t scanner)
+{
+    int  rc;
+
+    if (!rpost)
+    {
+        return 0;
+    }
+
+    rc = 0;
+    if (sel->u.expr.method->pupdate)
+    {
+        /* By default, use whole residues/molecules. */
+        rc = gmx_ana_poscalc_create_enum(&sel->u.expr.pc, pcc, rpost,
+                                         POS_COMPLWHOLE);
+    }
+    else
+    {
+        _gmx_selparser_warning(scanner, "modifier '%s' for '%s' ignored",
+                               rpost, sel->u.expr.method->name);
+    }
+    return rc;
+}
+
+/*!
+ * \param[in]  left    Selection element for the left hand side.
+ * \param[in]  right   Selection element for the right hand side.
+ * \param[in]  op      String representation of the operator.
+ * \param[in]  scanner Scanner data structure.
+ * \returns    The created selection element.
+ *
+ * This function handles the creation of a \c t_selelem object for
+ * arithmetic expressions.
+ */
+t_selelem *
+_gmx_sel_init_arithmetic(t_selelem *left, t_selelem *right, char op,
+                         yyscan_t scanner)
+{
+    t_selelem         *sel;
+    char               buf[2];
+
+    buf[0] = op;
+    buf[1] = 0;
+    sel = _gmx_selelem_create(SEL_ARITHMETIC);
+    sel->v.type        = REAL_VALUE;
+    switch(op)
+    {
+        case '+': sel->u.arith.type = ARITH_PLUS; break;
+        case '-': sel->u.arith.type = (right ? ARITH_MINUS : ARITH_NEG); break;
+        case '*': sel->u.arith.type = ARITH_MULT; break;
+        case '/': sel->u.arith.type = ARITH_DIV;  break;
+        case '^': sel->u.arith.type = ARITH_EXP;  break;
+    }
+    sel->u.arith.opstr = strdup(buf);
+    sel->name          = sel->u.arith.opstr;
+    sel->child         = left;
+    sel->child->next   = right;
+    return sel;
+}
+
+/*!
+ * \param[in]  left   Selection element for the left hand side.
+ * \param[in]  right  Selection element for the right hand side.
+ * \param[in]  cmpop  String representation of the comparison operator.
+ * \param[in]  scanner Scanner data structure.
+ * \returns    The created selection element.
+ *
+ * This function handles the creation of a \c t_selelem object for
+ * comparison expressions.
+ */
+t_selelem *
+_gmx_sel_init_comparison(t_selelem *left, t_selelem *right, char *cmpop,
+                         yyscan_t scanner)
+{
+    t_selelem         *sel;
+    t_selexpr_param   *params, *param;
+    const char        *name;
+    int                rc;
+
+    gmx::AbstractErrorReporter *errors = _gmx_sel_lexer_error_reporter(scanner);
+    gmx::ErrorContext  context(errors, "In comparison initialization");
+
+    sel = _gmx_selelem_create(SEL_EXPRESSION);
+    _gmx_selelem_set_method(sel, &sm_compare, scanner);
+    /* Create the parameter for the left expression */
+    name               = left->v.type == INT_VALUE ? "int1" : "real1";
+    params = param     = _gmx_selexpr_create_param(strdup(name));
+    param->nval        = 1;
+    param->value       = _gmx_selexpr_create_value_expr(left);
+    /* Create the parameter for the right expression */
+    name               = right->v.type == INT_VALUE ? "int2" : "real2";
+    param              = _gmx_selexpr_create_param(strdup(name));
+    param->nval        = 1;
+    param->value       = _gmx_selexpr_create_value_expr(right);
+    params->next       = param;
+    /* Create the parameter for the operator */
+    param              = _gmx_selexpr_create_param(strdup("op"));
+    param->nval        = 1;
+    param->value       = _gmx_selexpr_create_value(STR_VALUE);
+    param->value->u.s  = cmpop;
+    params->next->next = param;
+    if (!_gmx_sel_parse_params(params, sel->u.expr.method->nparams,
+                               sel->u.expr.method->param, sel, scanner))
+    {
+        _gmx_selelem_free(sel);
+        return NULL;
+    }
+
+    return sel;
+}
+
+/*!
+ * \param[in]  method Method to use.
+ * \param[in]  args   Pointer to the first argument.
+ * \param[in]  rpost  Reference position type to use (NULL = default).
+ * \param[in]  scanner Scanner data structure.
+ * \returns    The created selection element.
+ *
+ * This function handles the creation of a \c t_selelem object for
+ * selection methods that do not take parameters.
+ */
+t_selelem *
+_gmx_sel_init_keyword(gmx_ana_selmethod_t *method, t_selexpr_value *args,
+                      const char *rpost, yyscan_t scanner)
+{
+    gmx_ana_selcollection_t *sc = _gmx_sel_lexer_selcollection(scanner);
+    t_selelem         *root, *child;
+    t_selexpr_param   *params, *param;
+    t_selexpr_value   *arg;
+    int                nargs;
+    int                rc;
+
+    gmx::AbstractErrorReporter *errors = _gmx_sel_lexer_error_reporter(scanner);
+    char  buf[128];
+    sprintf(buf, "In keyword '%s'", method->name);
+    gmx::ErrorContext  context(errors, buf);
+
+    if (method->nparams > 0)
+    {
+        GMX_ERROR_NORET(gmx::eeInternalError,
+                        "Keyword initialization called with non-keyword method");
+        return NULL;
+    }
+
+    root = _gmx_selelem_create(SEL_EXPRESSION);
+    child = root;
+    _gmx_selelem_set_method(child, method, scanner);
+
+    /* Initialize the evaluation of keyword matching if values are provided */
+    if (args)
+    {
+        gmx_ana_selmethod_t *kwmethod;
+        switch (method->type)
+        {
+            case INT_VALUE:  kwmethod = &sm_keyword_int;  break;
+            case REAL_VALUE: kwmethod = &sm_keyword_real; break;
+            case STR_VALUE:  kwmethod = &sm_keyword_str;  break;
+            default:
+                GMX_ERROR_NORET(gmx::eeInternalError,
+                                "Unknown type for keyword selection");
+                _gmx_selexpr_free_values(args);
+                goto on_error;
+        }
+        /* Count the arguments */
+        nargs = 0;
+        arg   = args;
+        while (arg)
+        {
+            ++nargs;
+            arg = arg->next;
+        }
+        /* Initialize the selection element */
+        root = _gmx_selelem_create(SEL_EXPRESSION);
+        _gmx_selelem_set_method(root, kwmethod, scanner);
+        params = param = _gmx_selexpr_create_param(NULL);
+        param->nval    = 1;
+        param->value   = _gmx_selexpr_create_value_expr(child);
+        param          = _gmx_selexpr_create_param(NULL);
+        param->nval    = nargs;
+        param->value   = args;
+        params->next   = param;
+        if (!_gmx_sel_parse_params(params, root->u.expr.method->nparams,
+                                   root->u.expr.method->param, root, scanner))
+        {
+            goto on_error;
+        }
+    }
+    rc = set_refpos_type(sc->pcc, child, rpost, scanner);
+    if (rc != 0)
+    {
+        goto on_error;
+    }
+
+    return root;
+
+/* On error, free all memory and return NULL. */
+on_error:
+    _gmx_selelem_free(root);
+    return NULL;
+}
+
+/*!
+ * \param[in]  method Method to use for initialization.
+ * \param[in]  params Pointer to the first parameter.
+ * \param[in]  rpost  Reference position type to use (NULL = default).
+ * \param[in]  scanner Scanner data structure.
+ * \returns    The created selection element.
+ *
+ * This function handles the creation of a \c t_selelem object for
+ * selection methods that take parameters.
+ *
+ * Part of the behavior of the \c same selection keyword is hardcoded into
+ * this function (or rather, into _gmx_selelem_custom_init_same()) to allow the
+ * use of any keyword in \c "same KEYWORD as" without requiring special
+ * handling somewhere else (or sacrificing the simple syntax).
+ */
+t_selelem *
+_gmx_sel_init_method(gmx_ana_selmethod_t *method, t_selexpr_param *params,
+                     const char *rpost, yyscan_t scanner)
+{
+    gmx_ana_selcollection_t *sc = _gmx_sel_lexer_selcollection(scanner);
+    t_selelem       *root;
+    int              rc;
+
+    gmx::AbstractErrorReporter *errors = _gmx_sel_lexer_error_reporter(scanner);
+    char  buf[128];
+    sprintf(buf, "In keyword '%s'", method->name);
+    gmx::ErrorContext  context(errors, buf);
+
+    _gmx_sel_finish_method(scanner);
+    /* The "same" keyword needs some custom massaging of the parameters. */
+    rc = _gmx_selelem_custom_init_same(&method, params, scanner);
+    if (rc != 0)
+    {
+        _gmx_selexpr_free_params(params);
+        return NULL;
+    }
+    root = _gmx_selelem_create(SEL_EXPRESSION);
+    _gmx_selelem_set_method(root, method, scanner);
+    /* Process the parameters */
+    if (!_gmx_sel_parse_params(params, root->u.expr.method->nparams,
+                               root->u.expr.method->param, root, scanner))
+    {
+        _gmx_selelem_free(root);
+        return NULL;
+    }
+    rc = set_refpos_type(sc->pcc, root, rpost, scanner);
+    if (rc != 0)
+    {
+        _gmx_selelem_free(root);
+        return NULL;
+    }
+
+    return root;
+}
+
+/*!
+ * \param[in]  method Modifier to use for initialization.
+ * \param[in]  params Pointer to the first parameter.
+ * \param[in]  sel    Selection element that the modifier should act on.
+ * \param[in]  scanner Scanner data structure.
+ * \returns    The created selection element.
+ *
+ * This function handles the creation of a \c t_selelem object for
+ * selection modifiers.
+ */
+t_selelem *
+_gmx_sel_init_modifier(gmx_ana_selmethod_t *method, t_selexpr_param *params,
+                       t_selelem *sel, yyscan_t scanner)
+{
+    t_selelem         *root;
+    t_selelem         *mod;
+    t_selexpr_param   *vparam;
+    int                i;
+
+    gmx::AbstractErrorReporter *errors = _gmx_sel_lexer_error_reporter(scanner);
+    char  buf[128];
+    sprintf(buf, "In keyword '%s'", method->name);
+    gmx::ErrorContext  context(errors, buf);
+
+    _gmx_sel_finish_method(scanner);
+    mod = _gmx_selelem_create(SEL_MODIFIER);
+    _gmx_selelem_set_method(mod, method, scanner);
+    if (method->type == NO_VALUE)
+    {
+        t_selelem *child;
+
+        child = sel;
+        while (child->next)
+        {
+            child = child->next;
+        }
+        child->next = mod;
+        root        = sel;
+    }
+    else
+    {
+        vparam        = _gmx_selexpr_create_param(NULL);
+        vparam->nval  = 1;
+        vparam->value = _gmx_selexpr_create_value_expr(sel);
+        vparam->next  = params;
+        params        = vparam;
+        root          = mod;
+    }
+    /* Process the parameters */
+    if (!_gmx_sel_parse_params(params, mod->u.expr.method->nparams,
+                               mod->u.expr.method->param, mod, scanner))
+    {
+        _gmx_selelem_free(mod);
+        return NULL;
+    }
+
+    return root;
+}
+
+/*!
+ * \param[in]  expr    Input selection element for the position calculation.
+ * \param[in]  type    Reference position type or NULL for default.
+ * \param[in]  scanner Scanner data structure.
+ * \returns    The created selection element.
+ *
+ * This function handles the creation of a \c t_selelem object for
+ * evaluation of reference positions.
+ */
+t_selelem *
+_gmx_sel_init_position(t_selelem *expr, const char *type, yyscan_t scanner)
+{
+    t_selelem       *root;
+    t_selexpr_param *params;
+
+    gmx::AbstractErrorReporter *errors = _gmx_sel_lexer_error_reporter(scanner);
+    char  buf[128];
+    sprintf(buf, "In position evaluation");
+    gmx::ErrorContext  context(errors, buf);
+
+    root = _gmx_selelem_create(SEL_EXPRESSION);
+    _gmx_selelem_set_method(root, &sm_keyword_pos, scanner);
+    _gmx_selelem_set_kwpos_type(root, type);
+    /* Create the parameters for the parameter parser. */
+    params        = _gmx_selexpr_create_param(NULL);
+    params->nval  = 1;
+    params->value = _gmx_selexpr_create_value_expr(expr);
+    /* Parse the parameters. */
+    if (!_gmx_sel_parse_params(params, root->u.expr.method->nparams,
+                               root->u.expr.method->param, root, scanner))
+    {
+        _gmx_selelem_free(root);
+        return NULL;
+    }
+
+    return root;
+}
+
+/*!
+ * \param[in] x,y,z  Coordinates for the position.
+ * \returns   The creates selection element.
+ */
+t_selelem *
+_gmx_sel_init_const_position(real x, real y, real z)
+{
+    t_selelem *sel;
+    rvec       pos;
+
+    sel = _gmx_selelem_create(SEL_CONST);
+    _gmx_selelem_set_vtype(sel, POS_VALUE);
+    _gmx_selvalue_reserve(&sel->v, 1);
+    pos[XX] = x;
+    pos[YY] = y;
+    pos[ZZ] = z;
+    gmx_ana_pos_init_const(sel->v.u.p, pos);
+    return sel;
+}
+
+/*!
+ * \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.
+ *
+ * See gmx_ana_indexgrps_find() for information on how \p name is matched
+ * against the index groups.
+ */
+t_selelem *
+_gmx_sel_init_group_by_name(const char *name, yyscan_t scanner)
+{
+    gmx::AbstractErrorReporter *errors = _gmx_sel_lexer_error_reporter(scanner);
+    char buf[256];
+    gmx_ana_indexgrps_t *grps = _gmx_sel_lexer_indexgrps(scanner);
+    t_selelem *sel;
+
+    if (!_gmx_sel_lexer_has_groups_set(scanner))
+    {
+        sel = _gmx_selelem_create(SEL_GROUPREF);
+        _gmx_selelem_set_vtype(sel, GROUP_VALUE);
+        sel->u.gref.name = strdup(name);
+        sel->u.gref.id = -1;
+        sel->name = name;
+        return sel;
+    }
+    if (!grps)
+    {
+        sprintf(buf, "No index groups set; cannot match 'group %s'", name);
+        errors->error(buf);
+        return NULL;
+    }
+    sel = _gmx_selelem_create(SEL_CONST);
+    _gmx_selelem_set_vtype(sel, GROUP_VALUE); 
+    /* FIXME: The constness should not be cast away */
+    if (!gmx_ana_indexgrps_find(&sel->u.cgrp, grps, (char *)name))
+    {
+        sprintf(buf, "Cannot match 'group %s'", name);
+        errors->error(buf);
+        _gmx_selelem_free(sel);
+        return NULL;
+    }
+    sel->name = sel->u.cgrp.name;
+    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.
+ */
+t_selelem *
+_gmx_sel_init_group_by_id(int id, yyscan_t scanner)
+{
+    gmx::AbstractErrorReporter *errors = _gmx_sel_lexer_error_reporter(scanner);
+    char buf[128];
+    gmx_ana_indexgrps_t *grps = _gmx_sel_lexer_indexgrps(scanner);
+    t_selelem *sel;
+
+    if (!_gmx_sel_lexer_has_groups_set(scanner))
+    {
+        sel = _gmx_selelem_create(SEL_GROUPREF);
+        _gmx_selelem_set_vtype(sel, GROUP_VALUE);
+        sel->u.gref.name = NULL;
+        sel->u.gref.id = id;
+        return sel;
+    }
+    if (!grps)
+    {
+        sprintf(buf, "No index groups set; cannot match 'group %d'", id);
+        errors->error(buf);
+        return NULL;
+    }
+    sel = _gmx_selelem_create(SEL_CONST);
+    _gmx_selelem_set_vtype(sel, GROUP_VALUE);
+    if (!gmx_ana_indexgrps_extract(&sel->u.cgrp, grps, id))
+    {
+        sprintf(buf, "Cannot match 'group %d'", id);
+        errors->error(buf);
+        _gmx_selelem_free(sel);
+        return NULL;
+    }
+    sel->name = sel->u.cgrp.name;
+    return sel;
+}
+
+/*!
+ * \param[in,out] sel  Value of the variable.
+ * \returns       The created selection element that references \p sel.
+ *
+ * The reference count of \p sel is updated, but no other modifications are
+ * made.
+ */
+t_selelem *
+_gmx_sel_init_variable_ref(t_selelem *sel)
+{
+    t_selelem *ref;
+
+    if (sel->v.type == POS_VALUE && sel->type == SEL_CONST)
+    {
+        ref = sel;
+    }
+    else
+    {
+        ref = _gmx_selelem_create(SEL_SUBEXPRREF);
+        _gmx_selelem_set_vtype(ref, sel->v.type);
+        ref->name  = sel->name;
+        ref->child = sel;
+    }
+    sel->refcount++;
+    return ref;
+}
+
+/*!
+ * \param[in]  name     Name for the selection
+ *     (if NULL, a default name is constructed).
+ * \param[in]  sel      The selection element that evaluates the selection.
+ * \param      scanner  Scanner data structure.
+ * \returns    The created root selection element.
+ *
+ * This function handles the creation of root (\ref SEL_ROOT) \c t_selelem
+ * objects for selections.
+ */
+t_selelem *
+_gmx_sel_init_selection(char *name, t_selelem *sel, yyscan_t scanner)
+{
+    gmx_ana_selcollection_t *sc = _gmx_sel_lexer_selcollection(scanner);
+    t_selelem               *root;
+    int                      rc;
+
+    gmx::AbstractErrorReporter *errors = _gmx_sel_lexer_error_reporter(scanner);
+    char  buf[1024];
+    sprintf(buf, "In selection '%s'", _gmx_sel_lexer_pselstr(scanner));
+    gmx::ErrorContext  context(errors, buf);
+
+    if (sel->v.type != POS_VALUE)
+    {
+        GMX_ERROR_NORET(gmx::eeInternalError,
+                        "Each selection must evaluate to a position");
+        /* FIXME: Better handling of this error */
+        sfree(name);
+        return NULL;
+    }
+
+    root = _gmx_selelem_create(SEL_ROOT);
+    root->child = sel;
+    /* Assign the name (this is done here to free it automatically in the case
+     * of an error below). */
+    if (name)
+    {
+        root->name = root->u.cgrp.name = name;
+    }
+    /* Update the flags */
+    rc = _gmx_selelem_update_flags(root, scanner);
+    if (rc != 0)
+    {
+        _gmx_selelem_free(root);
+        return NULL;
+    }
+
+    /* 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)
+    {
+        t_selelem *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->name = root->u.cgrp.name =
+                strdup(child->child->child->u.cgrp.name);
+        }
+    }
+    /* If there still is no name, use the selection string */
+    if (!root->name)
+    {
+        root->name = root->u.cgrp.name
+            = strdup(_gmx_sel_lexer_pselstr(scanner));
+    }
+
+    /* Print out some information if the parser is interactive */
+    if (_gmx_sel_is_lexer_interactive(scanner))
+    {
+        fprintf(stderr, "Selection '%s' parsed\n",
+                _gmx_sel_lexer_pselstr(scanner));
+    }
+
+    return root;
+}
+
+
+/*!
+ * \param[in]  name     Name of the variable (should not be freed after this
+ *   function).
+ * \param[in]  expr     The selection element that evaluates the variable.
+ * \param      scanner  Scanner data structure.
+ * \returns    The created root selection element.
+ *
+ * This function handles the creation of root \c t_selelem objects for
+ * variable assignments. A \ref SEL_ROOT element and a \ref SEL_SUBEXPR
+ * element are both created.
+ */
+t_selelem *
+_gmx_sel_assign_variable(char *name, t_selelem *expr, yyscan_t scanner)
+{
+    gmx_ana_selcollection_t *sc = _gmx_sel_lexer_selcollection(scanner);
+    const char              *pselstr = _gmx_sel_lexer_pselstr(scanner);
+    t_selelem               *root = NULL;
+    int                      rc;
+
+    gmx::AbstractErrorReporter *errors = _gmx_sel_lexer_error_reporter(scanner);
+    char  buf[1024];
+    sprintf(buf, "In selection '%s'", pselstr);
+    gmx::ErrorContext  context(errors, buf);
+
+    rc = _gmx_selelem_update_flags(expr, scanner);
+    if (rc != 0)
+    {
+        sfree(name);
+        _gmx_selelem_free(expr);
+        return NULL;
+    }
+    /* Check if this is a constant non-group value */
+    if (expr->type == SEL_CONST && expr->v.type != GROUP_VALUE)
+    {
+        /* If so, just assign the constant value to the variable */
+        if (!_gmx_sel_add_var_symbol(sc->symtab, name, expr))
+        {
+            _gmx_selelem_free(expr);
+            sfree(name);
+            return NULL;
+        }
+        _gmx_selelem_free(expr);
+        sfree(name);
+        goto finish;
+    }
+    /* Check if we are assigning a variable to another variable */
+    if (expr->type == SEL_SUBEXPRREF)
+    {
+        /* If so, make a simple alias */
+        if (!_gmx_sel_add_var_symbol(sc->symtab, name, expr->child))
+        {
+            _gmx_selelem_free(expr);
+            sfree(name);
+            return NULL;
+        }
+        _gmx_selelem_free(expr);
+        sfree(name);
+        goto finish;
+    }
+    /* Create the root element */
+    root = _gmx_selelem_create(SEL_ROOT);
+    root->name          = name;
+    root->u.cgrp.name   = name;
+    /* Create the subexpression element */
+    root->child = _gmx_selelem_create(SEL_SUBEXPR);
+    _gmx_selelem_set_vtype(root->child, expr->v.type);
+    root->child->name   = name;
+    root->child->child  = expr;
+    /* Update flags */
+    rc = _gmx_selelem_update_flags(root, scanner);
+    if (rc != 0)
+    {
+        _gmx_selelem_free(root);
+        return NULL;
+    }
+    /* Add the variable to the symbol table */
+    if (!_gmx_sel_add_var_symbol(sc->symtab, name, root->child))
+    {
+        _gmx_selelem_free(root);
+        return NULL;
+    }
+finish:
+    srenew(sc->varstrs, sc->nvars + 1);
+    sc->varstrs[sc->nvars] = strdup(pselstr);
+    ++sc->nvars;
+    if (_gmx_sel_is_lexer_interactive(scanner))
+    {
+        fprintf(stderr, "Variable '%s' parsed\n", pselstr);
+    }
+    return root;
+}
+
+/*!
+ * \param         sel   Selection to append (can be NULL, in which
+ *   case nothing is done).
+ * \param         last  Last selection, or NULL if not present or not known.
+ * \param         scanner  Scanner data structure.
+ * \returns       The last selection after the append.
+ *
+ * Appends \p sel after the last root element, and returns either \p sel
+ * (if it was non-NULL) or the last element (if \p sel was NULL).
+ */
+t_selelem *
+_gmx_sel_append_selection(t_selelem *sel, t_selelem *last, yyscan_t scanner)
+{
+    gmx_ana_selcollection_t *sc = _gmx_sel_lexer_selcollection(scanner);
+
+    /* Append sel after last, or the last element of sc if last is NULL */
+    if (last)
+    {
+        last->next = sel;
+    }
+    else
+    {
+        if (sc->root)
+        {
+            last = sc->root;
+            while (last->next)
+            {
+                last = last->next;
+            }
+            last->next = sel;
+        }
+        else
+        {
+            sc->root = sel;
+        }
+    }
+    /* Initialize a selection object if necessary */
+    if (sel)
+    {
+        last = sel;
+        /* Add the new selection to the collection if it is not a variable. */
+        if (sel->child->type != SEL_SUBEXPR)
+        {
+            gmx::Selection *newsel
+                = new gmx::Selection(sel, _gmx_sel_lexer_pselstr(scanner));
+            sc->sel.push_back(newsel);
+        }
+    }
+    /* Clear the selection string now that we've saved it */
+    _gmx_sel_lexer_clear_pselstr(scanner);
+    return last;
+}
+
+/*!
+ * \param[in] scanner Scanner data structure.
+ * \returns   TRUE if the parser should finish, FALSE if parsing should
+ *   continue.
+ *
+ * This function is called always after _gmx_sel_append_selection() to
+ * check whether a sufficient number of selections has already been provided.
+ * This is used to terminate interactive parsers when the correct number of
+ * selections has been provided.
+ */
+gmx_bool
+_gmx_sel_parser_should_finish(yyscan_t scanner)
+{
+    gmx_ana_selcollection_t *sc = _gmx_sel_lexer_selcollection(scanner);
+    return (int)sc->sel.size() == _gmx_sel_lexer_exp_selcount(scanner);
+}
+
+/*!
+ * \param[in] scanner Scanner data structure.
+ */
+void
+_gmx_sel_handle_empty_cmd(yyscan_t scanner)
+{
+    gmx_ana_selcollection_t *sc = _gmx_sel_lexer_selcollection(scanner);
+    gmx_ana_indexgrps_t     *grps = _gmx_sel_lexer_indexgrps(scanner);
+    int                      i;
+
+    if (!_gmx_sel_is_lexer_interactive(scanner))
+        return;
+
+    if (grps)
+    {
+        fprintf(stderr, "Available index groups:\n");
+        gmx_ana_indexgrps_print(_gmx_sel_lexer_indexgrps(scanner), 0);
+    }
+    if (sc->nvars > 0 || !sc->sel.empty())
+    {
+        fprintf(stderr, "Currently provided selections:\n");
+        for (i = 0; i < sc->nvars; ++i)
+        {
+            fprintf(stderr, "     %s\n", sc->varstrs[i]);
+        }
+        for (i = 0; i < (int)sc->sel.size(); ++i)
+        {
+            fprintf(stderr, " %2d. %s\n", i+1, sc->sel[i]->_sel.selstr);
+        }
+    }
+}
+
+/*!
+ * \param[in] topic   Topic for which help was requested, or NULL for general
+ *                    help.
+ * \param[in] scanner Scanner data structure.
+ *
+ * \p topic is freed by this function.
+ */
+void
+_gmx_sel_handle_help_cmd(char *topic, yyscan_t scanner)
+{
+    gmx_ana_selcollection_t *sc = _gmx_sel_lexer_selcollection(scanner);
+
+    _gmx_sel_print_help(sc->symtab, topic);
+    if (topic)
+    {
+        sfree(topic);
+    }
+}
diff --git a/src/gromacs/selection/parsetree.h b/src/gromacs/selection/parsetree.h
new file mode 100644 (file)
index 0000000..525be81
--- /dev/null
@@ -0,0 +1,213 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * Handling of intermediate selection parser data.
+ *
+ * The data types declared in this header are used by the parser to store
+ * intermediate data when constructing method expressions.
+ * In particular, the parameters for the method are stored.
+ * The intermediate data is freed once a \c t_selelem object can be
+ * constructed.
+ *
+ * This is an implementation header: there should be no need to use it outside
+ * this directory.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_selection
+ */
+#ifndef SELECTION_PARSETREE_H
+#define SELECTION_PARSETREE_H
+
+#include <types/simple.h>
+
+#include "gromacs/selection/selvalue.h"
+
+struct t_selelem;
+struct gmx_ana_indexgrps_t;
+struct gmx_ana_selmethod_t;
+struct gmx_ana_selparam_t;
+
+/*! \internal \brief
+ * Describes a parsed value, possibly resulting from expression evaluation.
+ */
+typedef struct t_selexpr_value
+{
+    /** Type of the value. */
+    e_selvalue_t            type;
+    /** TRUE if the value is the result of an expression. */
+    gmx_bool                    bExpr;
+    /** The actual value. */
+    union {
+        /** The integer value/range (\p type INT_VALUE); */
+        struct {
+            /** Beginning of the range. */
+            int             i1;
+            /** End of the range; equals \p i1 for a single integer. */
+            int             i2;
+        }                   i;
+        /** The real value/range (\p type REAL_VALUE); */
+        struct {
+            /** Beginning of the range. */
+            real            r1;
+            /** End of the range; equals \p r1 for a single number. */
+            real            r2;
+        }                   r;
+        /** The string value (\p type STR_VALUE); */
+        char               *s;
+        /** The position value (\p type POS_VALUE); */
+        rvec                x;
+        /** The expression if \p bExpr is TRUE. */
+        struct t_selelem   *expr;
+    }                       u;
+    /** Pointer to the next value. */
+    struct t_selexpr_value *next;
+} t_selexpr_value;
+
+/*! \internal \brief
+ * Describes a parsed method parameter.
+ */
+typedef struct t_selexpr_param
+{
+    /** Name of the parameter. */
+    char                   *name;
+    /** Number of values given for this parameter. */
+    int                     nval;
+    /** Pointer to the first value. */
+    struct t_selexpr_value *value;
+    /** Pointer to the next parameter. */
+    struct t_selexpr_param *next;
+} t_selexpr_param;
+
+/** Error reporting function for the selection parser. */
+void
+_gmx_selparser_warning(void *scanner, const char *fmt, ...);
+/** Error reporting function for the selection parser. */
+void
+_gmx_selparser_error(void *scanner, const char *fmt, ...);
+
+/** Allocates and initializes a constant \c t_selexpr_value. */
+t_selexpr_value *
+_gmx_selexpr_create_value(e_selvalue_t type);
+/** Allocates and initializes an expression \c t_selexpr_value. */
+t_selexpr_value *
+_gmx_selexpr_create_value_expr(struct t_selelem *expr);
+/** Allocates and initializes a \c t_selexpr_param. */
+t_selexpr_param *
+_gmx_selexpr_create_param(char *name);
+
+/** Frees the memory allocated for a chain of values. */
+void
+_gmx_selexpr_free_values(t_selexpr_value *value);
+/** Frees the memory allocated for a chain of parameters. */
+void
+_gmx_selexpr_free_params(t_selexpr_param *param);
+
+/** Propagates the flags for selection elements. */
+int
+_gmx_selelem_update_flags(struct t_selelem *sel, void *scanner);
+
+/** Initializes the method parameter data of \ref SEL_EXPRESSION and
+ * \ref SEL_MODIFIER elements. */
+void
+_gmx_selelem_init_method_params(struct t_selelem *sel, void *scanner);
+/** Initializes the method for a \ref SEL_EXPRESSION selection element. */
+void
+_gmx_selelem_set_method(struct t_selelem *sel,
+                        struct gmx_ana_selmethod_t *method, void *scanner);
+
+/** Creates a \c t_selelem for arithmetic expression evaluation. */
+struct t_selelem *
+_gmx_sel_init_arithmetic(struct t_selelem *left, struct t_selelem *right,
+                         char op, void *scanner);
+/** Creates a \c t_selelem for comparsion expression evaluation. */
+struct t_selelem *
+_gmx_sel_init_comparison(struct t_selelem *left, struct t_selelem *right,
+                         char *cmpop, void *scanner);
+/** Creates a \c t_selelem for a keyword expression from the parsed data. */
+struct t_selelem *
+_gmx_sel_init_keyword(struct gmx_ana_selmethod_t *method,
+                      t_selexpr_value *args, const char *rpost, void *scanner);
+/** Creates a \c t_selelem for a method expression from the parsed data. */
+struct t_selelem *
+_gmx_sel_init_method(struct gmx_ana_selmethod_t *method,
+                     t_selexpr_param *params, const char *rpost,
+                     void *scanner);
+/** Creates a \c t_selelem for a modifier expression from the parsed data. */
+struct t_selelem *
+_gmx_sel_init_modifier(struct gmx_ana_selmethod_t *mod, t_selexpr_param *params,
+                       struct t_selelem *sel, void *scanner);
+/** Creates a \c t_selelem for evaluation of reference positions. */
+struct t_selelem *
+_gmx_sel_init_position(struct t_selelem *expr, const char *type, void *scanner);
+
+/** Creates a \c t_selelem for a constant position. */
+struct t_selelem *
+_gmx_sel_init_const_position(real x, real y, real z);
+/** Creates a \c t_selelem for a index group expression using group name. */
+struct t_selelem *
+_gmx_sel_init_group_by_name(const char *name, void *scanner);
+/** Creates a \c t_selelem for a index group expression using group index. */
+struct t_selelem *
+_gmx_sel_init_group_by_id(int id, void *scanner);
+/** Creates a \c t_selelem for a variable reference */
+struct t_selelem *
+_gmx_sel_init_variable_ref(struct t_selelem *sel);
+
+/** Creates a root \c t_selelem for a selection. */
+struct t_selelem *
+_gmx_sel_init_selection(char *name, struct t_selelem *sel, void *scanner);
+/** Creates a root \c t_selelem elements for a variable assignment. */
+struct t_selelem *
+_gmx_sel_assign_variable(char *name, struct t_selelem *expr, void *scanner);
+/** Appends a root \c t_selelem to a selection collection. */
+struct t_selelem *
+_gmx_sel_append_selection(struct t_selelem *sel, struct t_selelem *last,
+                          void *scanner);
+/** Check whether the parser should finish. */
+gmx_bool
+_gmx_sel_parser_should_finish(void *scanner);
+
+/** Handle empty commands. */
+void
+_gmx_sel_handle_empty_cmd(void *scanner);
+/** Process help commands. */
+void
+_gmx_sel_handle_help_cmd(char *topic, void *scanner);
+
+/* In params.c */
+/** Initializes an array of parameters based on input from the selection parser. */
+gmx_bool
+_gmx_sel_parse_params(t_selexpr_param *pparams, int nparam,
+                      struct gmx_ana_selparam_t *param, struct t_selelem *root,
+                      void *scanner);
+
+#endif
diff --git a/src/gromacs/selection/poscalc.cpp b/src/gromacs/selection/poscalc.cpp
new file mode 100644 (file)
index 0000000..8f2b1be
--- /dev/null
@@ -0,0 +1,1469 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal
+ * \page poscalcengine Position calculation engine
+ *
+ * The header file \ref poscalc.h defines an API for calculating positions
+ * in an automated way. This is useful mostly in the selection engine, in
+ * particular with dynamic selections, because the same COM/COG positions
+ * may be needed in several contexts. The API makes it possible to
+ * optimize the evaluation such that any heavy calculation is only done once,
+ * and the results just copied if needed more than once.
+ * The functions also provide a convenient interface for keeping the whole
+ * \c gmx_ana_pos_t structure up-to-date.
+ *
+ * A new collection of position calculations is allocated with
+ * gmx_ana_poscalc_coll_create().
+ * Calculations within one collection should share the same topology, and
+ * they are optimized. Calculations in different collections do not interact.
+ * The topology for a collection can be set with
+ * gmx_ana_poscalc_coll_set_topology().
+ * This needs to be done before calling gmx_ana_poscalc_set_maxindex() for
+ * any calculation in the collection, unless that calculation does not
+ * require topology information.
+ * All memory allocated for a collection and the calculations in it can be
+ * freed with gmx_ana_poscalc_coll_free().
+ *
+ * A new calculation is created with gmx_ana_poscalc_create().
+ * If flags need to be adjusted later, gmx_ana_poscalc_set_flags() can be
+ * used.
+ * After the flags are final, the largest possible index group for which the
+ * positions are needed has to be set with gmx_ana_poscalc_set_maxindex().
+ * gmx_ana_poscalc_coll_set_topology() should have been called before this
+ * function is called.
+ * After the above calls, gmx_ana_poscalc_init_pos() can be used to initialize
+ * output to a \c gmx_ana_pos_t structure. Several different structures can be
+ * initialized for the same calculation; the only requirement is that the
+ * structure passed later to gmx_ana_poscalc_update() has been initialized
+ * properly.
+ * The memory allocated for a calculation can be freed with
+ * gmx_ana_poscalc_free().
+ *
+ * The position evaluation is simple: gmx_ana_poscalc_init_frame() should be
+ * called once for each frame, and gmx_ana_poscalc_update() can then be called
+ * for each calculation that is needed for that frame.
+ *
+ * It is also possible to initialize the calculations based on a type provided
+ * as a string.
+ * The possible strings are returned by gmx_ana_poscalc_create_type_enum(),
+ * and the string can be converted to the parameters for
+ * gmx_ana_poscalc_create() using gmx_ana_poscalc_type_from_enum().
+ * gmx_ana_poscalc_create_enum() is also provided for convenience.
+ */
+/*! \internal \file
+ * \brief
+ * Implements functions in poscalc.h.
+ *
+ * \todo
+ * There is probably some room for optimization in the calculation of
+ * positions with bases.
+ * In particular, the current implementation may do a lot of unnecessary
+ * copying.
+ * The interface would need to be changed to make it possible to use the
+ * same output positions for several calculations.
+ *
+ * \todo
+ * The current algorithm for setting up base calculations could be improved
+ * in cases when there are calculations that cannot use a common base but
+ * still overlap partially (e.g., with three calculations A, B, and C
+ * such that A could use both B and C as a base, but B and C cannot use the
+ * same base).
+ * Setting up the bases in an optimal manner in every possible situation can
+ * be quite difficult unless several bases are allowed for one calculation,
+ * but better heuristics could probably be implemented.
+ * For best results, the setup should probably be postponed (at least
+ * partially) to gmx_ana_poscalc_init_eval().
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_selection
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#include <macros.h>
+#include <smalloc.h>
+#include <typedefs.h>
+#include <pbc.h>
+#include <vec.h>
+
+#include "gromacs/selection/centerofmass.h"
+#include "gromacs/selection/indexutil.h"
+#include "gromacs/selection/poscalc.h"
+#include "gromacs/selection/position.h"
+
+/*! \internal \brief
+ * Collection of \c gmx_ana_poscalc_t structures for the same topology.
+ *
+ * Calculations within the same structure are optimized to eliminate duplicate
+ * calculations.
+ */
+struct gmx_ana_poscalc_coll_t
+{
+    /*! \brief
+     * Topology data.
+     *
+     * Can be NULL if none of the calculations require topology data or if
+     * gmx_ana_poscalc_coll_set_topology() has not been called.
+     */
+    t_topology               *top;
+    /** Pointer to the first data structure. */
+    gmx_ana_poscalc_t        *first;
+    /** Pointer to the last data structure. */
+    gmx_ana_poscalc_t        *last;
+    /** Whether the collection has been initialized for evaluation. */
+    gmx_bool                      bInit;
+};
+
+/*! \internal \brief
+ * Data structure for position calculation.
+ */
+struct gmx_ana_poscalc_t
+{
+    /*! \brief
+     * Type of calculation.
+     *
+     * This field may differ from the type requested by the user, because
+     * it is changed internally to the most effective calculation.
+     * For example, if the user requests a COM calculation for residues
+     * consisting of single atoms, it is simply set to POS_ATOM.
+     * To provide a consistent interface to the user, the field \p itype
+     * should be used when information should be given out.
+     */
+    e_poscalc_t               type;
+    /*! \brief
+     * Flags for calculation options.
+     *
+     * See \ref poscalc_flags "documentation of the flags".
+     */
+    int                       flags;
+
+    /*! \brief
+     * Type for the created indices.
+     *
+     * This field always agrees with the type that the user requested, but
+     * may differ from \p type.
+     */
+    e_index_t                 itype;
+    /*! \brief
+     * Block data for the calculation.
+     */
+    t_blocka                  b;
+    /*! \brief
+     * Mapping from the blocks to the blocks of \p sbase.
+     *
+     * If \p sbase is NULL, this field is also.
+     */
+    int                      *baseid;
+    /*! \brief
+     * Maximum evaluation group.
+     */
+    gmx_ana_index_t           gmax;
+
+    /** Position storage for calculations that are used as a base. */
+    gmx_ana_pos_t            *p;
+
+    /** TRUE if the positions have been evaluated for the current frame. */
+    gmx_bool                      bEval;
+    /*! \brief
+     * Base position data for this calculation.
+     *
+     * If not NULL, the centers required by this calculation have
+     * already been calculated in \p sbase.
+     * The structure pointed by \p sbase is always a static calculation.
+     */
+    struct gmx_ana_poscalc_t *sbase;
+    /** Next structure in the linked list of calculations. */
+    struct gmx_ana_poscalc_t *next;
+    /** Previous structure in the linked list of calculations. */
+    struct gmx_ana_poscalc_t *prev;
+    /** Number of references to this structure. */
+    int                       refcount;
+    /** Collection this calculation belongs to. */
+    gmx_ana_poscalc_coll_t   *coll;
+};
+
+//! Strings returned by gmx_ana_poscalc_create_type_enum().
+static const char *const poscalc_enum_strings[] = {
+    "atom",
+    "res_com",       "res_cog",
+    "mol_com",       "mol_cog",
+    "whole_res_com", "whole_res_cog",
+    "whole_mol_com", "whole_mol_cog",
+    "part_res_com",  "part_res_cog",
+    "part_mol_com",  "part_mol_cog",
+    "dyn_res_com",   "dyn_res_cog",
+    "dyn_mol_com",   "dyn_mol_cog",
+    NULL,
+};
+//! Number of elements in ::poscalc_enum_strings.
+#define NENUM asize(poscalc_enum_strings)
+
+/*! \brief
+ * Returns the partition type for a given position type.
+ *
+ * \param [in] type  \c e_poscalc_t value to convert.
+ * \returns    Corresponding \c e_indet_t.
+ */
+static e_index_t
+index_type_for_poscalc(e_poscalc_t type)
+{
+    switch(type)
+    {
+        case POS_ATOM:    return INDEX_ATOM;
+        case POS_RES:     return INDEX_RES;
+        case POS_MOL:     return INDEX_MOL;
+        case POS_ALL:     return INDEX_ALL;
+        case POS_ALL_PBC: return INDEX_ALL;
+    }
+    return INDEX_UNKNOWN;
+}
+
+/*!
+ * \param[in]     post  String (typically an enum command-line argument).
+ *   Allowed values: 'atom', 'res_com', 'res_cog', 'mol_com', 'mol_cog',
+ *   or one of the last four prepended by 'whole_', 'part_', or 'dyn_'.
+ * \param[out]    type  \c e_poscalc_t corresponding to \p post.
+ * \param[in,out] flags Flags corresponding to \p post.
+ *   On input, the flags should contain the default flags.
+ *   On exit, the flags \ref POS_MASS, \ref POS_COMPLMAX and
+ *   \ref POS_COMPLWHOLE have been set according to \p post
+ *   (the completion flags are left at the default values if no completion
+ *   prefix is given).
+ * \returns       0 if \p post is one of the valid strings, EINVAL otherwise.
+ *
+ * \attention
+ * Checking is not complete, and other values than those listed above
+ * may be accepted for \p post, but the results are undefined.
+ */
+int
+gmx_ana_poscalc_type_from_enum(const char *post, e_poscalc_t *type, int *flags)
+{
+    const char *ptr;
+
+    if (post[0] == 'a')
+    {
+        *type   = POS_ATOM;
+        *flags &= ~(POS_MASS | POS_COMPLMAX | POS_COMPLWHOLE);
+        return 0;
+    }
+
+    /* Process the prefix */
+    ptr = post;
+    if (post[0] == 'w')
+    {
+        *flags &= ~POS_COMPLMAX;
+        *flags |= POS_COMPLWHOLE;
+        ptr = post + 6;
+    }
+    else if (post[0] == 'p')
+    {
+        *flags &= ~POS_COMPLWHOLE;
+        *flags |= POS_COMPLMAX;
+        ptr = post + 5;
+    }
+    else if (post[0] == 'd')
+    {
+        *flags &= ~(POS_COMPLMAX | POS_COMPLWHOLE);
+        ptr = post + 4;
+    }
+
+    if (ptr[0] == 'r')
+    {
+        *type = POS_RES;
+    }
+    else if (ptr[0] == 'm')
+    {
+        *type = POS_MOL;
+    }
+    else
+    {
+        gmx_incons("unknown position calculation type");
+        return EINVAL;
+    }
+    if (ptr[6] == 'm')
+    {
+        *flags |= POS_MASS;
+    }
+    else if (ptr[6] == 'g')
+    {
+        *flags &= ~POS_MASS;
+    }
+    else
+    {
+        gmx_incons("unknown position calculation type");
+        return EINVAL;
+    }
+    return 0;
+}
+
+/*!
+ * \param[in]  bAtom    If TRUE, the "atom" value is included.
+ * \returns    NULL-terminated array of strings that contains the string
+ *   values acceptable for gmx_ana_poscalc_type_from_enum().
+ *
+ * The first string in the returned list is always NULL to allow the list to
+ * be used with Gromacs command-line parsing.
+ */
+const char **
+gmx_ana_poscalc_create_type_enum(gmx_bool bAtom)
+{
+    const char **pcenum;
+    size_t       i;
+
+    if (bAtom)
+    {
+        snew(pcenum, NENUM+1);
+        for (i = 0; i < NENUM; ++i)
+        {
+            pcenum[i+1] = poscalc_enum_strings[i];
+        }
+    }
+    else
+    {
+        snew(pcenum, NENUM+1-1);
+        for (i = 1; i < NENUM; ++i)
+        {
+            pcenum[i] = poscalc_enum_strings[i];
+        }
+    }
+    pcenum[0] = NULL;
+    return pcenum;
+}
+
+/*!
+ * \param[out] pccp   Allocated position calculation collection.
+ * \returns    0 for success.
+ */
+int
+gmx_ana_poscalc_coll_create(gmx_ana_poscalc_coll_t **pccp)
+{
+    gmx_ana_poscalc_coll_t *pcc;
+
+    snew(pcc, 1);
+    pcc->top   = NULL;
+    pcc->first = NULL;
+    pcc->last  = NULL;
+    pcc->bInit = FALSE;
+    *pccp = pcc;
+    return 0;
+}
+
+/*!
+ * \param[in,out] pcc   Position calculation collection data structure.
+ * \param[in]     top   Topology data structure.
+ *
+ * This function should be called to set the topology before using
+ * gmx_ana_poscalc_set_maxindex() for any calculation that requires
+ * topology information.
+ */
+void
+gmx_ana_poscalc_coll_set_topology(gmx_ana_poscalc_coll_t *pcc, t_topology *top)
+{
+    pcc->top = top;
+}
+
+/*!
+ * \param[in] pcc   Position calculation collection to free.
+ *
+ * The pointer \p pcc is invalid after the call.
+ * Any calculations in the collection are also freed, no matter how many
+ * references to them are left.
+ */
+void
+gmx_ana_poscalc_coll_free(gmx_ana_poscalc_coll_t *pcc)
+{
+    while (pcc->first)
+    {
+        gmx_ana_poscalc_free(pcc->first);
+    }
+    sfree(pcc);
+}
+
+/*!
+ * \param[in] fp    File handle to receive the output.
+ * \param[in] pcc   Position calculation collection to print.
+ *
+ * The output is very technical, making this function mainly useful for
+ * debugging purposes.
+ */
+void
+gmx_ana_poscalc_coll_print_tree(FILE *fp, gmx_ana_poscalc_coll_t *pcc)
+{
+    gmx_ana_poscalc_t *pc;
+    int                i, j;
+
+    fprintf(fp, "Position calculations:\n");
+    i  = 1;
+    pc = pcc->first;
+    while (pc)
+    {
+        fprintf(fp, "%2d ", i);
+        switch (pc->type)
+        {
+            case POS_ATOM:    fprintf(fp, "ATOM");    break;
+            case POS_RES:     fprintf(fp, "RES");     break;
+            case POS_MOL:     fprintf(fp, "MOL");     break;
+            case POS_ALL:     fprintf(fp, "ALL");     break;
+            case POS_ALL_PBC: fprintf(fp, "ALL_PBC"); break;
+        }
+        if (pc->itype != index_type_for_poscalc(pc->type))
+        {
+            fprintf(fp, " (");
+            switch (pc->itype)
+            {
+                case INDEX_UNKNOWN: fprintf(fp, "???");  break;
+                case INDEX_ATOM:    fprintf(fp, "ATOM"); break;
+                case INDEX_RES:     fprintf(fp, "RES");  break;
+                case INDEX_MOL:     fprintf(fp, "MOL");  break;
+                case INDEX_ALL:     fprintf(fp, "ALL");  break;
+            }
+            fprintf(fp, ")");
+        }
+        fprintf(fp, " flg=");
+        if (pc->flags & POS_MASS)
+        {
+            fprintf(fp, "M");
+        }
+        if (pc->flags & POS_DYNAMIC)
+        {
+            fprintf(fp, "D");
+        }
+        if (pc->flags & POS_MASKONLY)
+        {
+            fprintf(fp, "A");
+        }
+        if (pc->flags & POS_COMPLMAX)
+        {
+            fprintf(fp, "Cm");
+        }
+        if (pc->flags & POS_COMPLWHOLE)
+        {
+            fprintf(fp, "Cw");
+        }
+        if (!pc->flags)
+        {
+            fprintf(fp, "0");
+        }
+        fprintf(fp, " nr=%d nra=%d", pc->b.nr, pc->b.nra);
+        fprintf(fp, " refc=%d", pc->refcount);
+        fprintf(fp, "\n");
+        if (pc->gmax.nalloc_index > 0)
+        {
+            fprintf(fp, "   Group: ");
+            if (pc->gmax.isize > 20)
+            {
+                fprintf(fp, " %d atoms", pc->gmax.isize);
+            }
+            else
+            {
+                for (j = 0; j < pc->gmax.isize; ++j)
+                {
+                    fprintf(fp, " %d", pc->gmax.index[j] + 1);
+                }
+            }
+            fprintf(fp, "\n");
+        }
+        if (pc->b.nalloc_a > 0)
+        {
+            fprintf(fp, "   Atoms: ");
+            if (pc->b.nra > 20)
+            {
+                fprintf(fp, " %d atoms", pc->b.nra);
+            }
+            else
+            {
+                for (j = 0; j < pc->b.nra; ++j)
+                {
+                    fprintf(fp, " %d", pc->b.a[j] + 1);
+                }
+            }
+            fprintf(fp, "\n");
+        }
+        if (pc->b.nalloc_index > 0)
+        {
+            fprintf(fp, "   Blocks:");
+            if (pc->b.nr > 20)
+            {
+                fprintf(fp, " %d pcs", pc->b.nr);
+            }
+            else
+            {
+                for (j = 0; j <= pc->b.nr; ++j)
+                {
+                    fprintf(fp, " %d", pc->b.index[j]);
+                }
+            }
+            fprintf(fp, "\n");
+        }
+        if (pc->sbase)
+        {
+            gmx_ana_poscalc_t *base;
+
+            fprintf(fp, "   Base: ");
+            j = 1;
+            base = pcc->first;
+            while (base && base != pc->sbase)
+            {
+                ++j;
+                base = base->next;
+            }
+            fprintf(fp, "%d", j);
+            if (pc->baseid && pc->b.nr <= 20)
+            {
+                fprintf(fp, " id:");
+                for (j = 0; j < pc->b.nr; ++j)
+                {
+                    fprintf(fp, " %d", pc->baseid[j]+1);
+                }
+            }
+            fprintf(fp, "\n");
+        }
+        ++i;
+        pc = pc->next;
+    }
+}
+
+/*! \brief
+ * Inserts a position calculation structure into its collection.
+ *
+ * \param pc     Data structure to insert.
+ * \param before Data structure before which to insert
+ *   (NULL = insert at end).
+ *
+ * Inserts \p pc to its collection before \p before.
+ * If \p before is NULL, \p pc is appended to the list.
+ */
+static void
+insert_poscalc(gmx_ana_poscalc_t *pc, gmx_ana_poscalc_t *before)
+{
+    if (before == NULL)
+    {
+        pc->next = NULL;
+        pc->prev = pc->coll->last;
+        if (pc->coll->last)
+        {
+            pc->coll->last->next = pc;
+        }
+        pc->coll->last = pc;
+    }
+    else
+    {
+        pc->prev     = before->prev;
+        pc->next     = before;
+        if (before->prev)
+        {
+            before->prev->next = pc;
+        }
+        before->prev = pc;
+    }
+    if (!pc->prev)
+    {
+        pc->coll->first = pc;
+    }
+}
+
+/*! \brief
+ * Removes a position calculation structure from its collection.
+ *
+ * \param pc    Data structure to remove.
+ *
+ * Removes \p pc from its collection.
+ */
+static void
+remove_poscalc(gmx_ana_poscalc_t *pc)
+{
+    if (pc->prev)
+    {
+        pc->prev->next = pc->next;
+    }
+    else if (pc == pc->coll->first)
+    {
+        pc->coll->first = pc->next;
+    }
+    if (pc->next)
+    {
+        pc->next->prev = pc->prev;
+    }
+    else if (pc == pc->coll->last)
+    {
+        pc->coll->last = pc->prev;
+    }
+    pc->prev = pc->next = NULL;
+}
+
+/*! \brief
+ * Initializes position calculation using the maximum possible input index.
+ *
+ * \param[in,out] pc  Position calculation data structure.
+ * \param[in]     g   Maximum index group for the calculation.
+ * \param[in]     bBase Whether \p pc will be used as a base or not.
+ *
+ * \p bBase affects on how the \p pc->gmax field is initialized.
+ */
+static void
+set_poscalc_maxindex(gmx_ana_poscalc_t *pc, gmx_ana_index_t *g, gmx_bool bBase)
+{
+    gmx_ana_index_make_block(&pc->b, pc->coll->top, g, pc->itype, pc->flags & POS_COMPLWHOLE);
+    /* Set the type to POS_ATOM if the calculation in fact is such. */
+    if (pc->b.nr == pc->b.nra)
+    {
+        pc->type   = POS_ATOM; 
+        pc->flags &= ~(POS_MASS | POS_COMPLMAX | POS_COMPLWHOLE);
+    }
+    /* Set the POS_COMPLWHOLE flag if the calculation in fact always uses
+     * complete residues and molecules. */
+    if (!(pc->flags & POS_COMPLWHOLE)
+        && (!(pc->flags & POS_DYNAMIC) || (pc->flags & POS_COMPLMAX))
+        && (pc->type == POS_RES || pc->type == POS_MOL)
+        && gmx_ana_index_has_complete_elems(g, pc->itype, pc->coll->top))
+    {
+        pc->flags &= ~POS_COMPLMAX;
+        pc->flags |= POS_COMPLWHOLE;
+    }
+    /* Setup the gmax field */
+    if ((pc->flags & POS_COMPLWHOLE) && !bBase && pc->b.nra > g->isize)
+    {
+        gmx_ana_index_copy(&pc->gmax, g, TRUE);
+        sfree(pc->gmax.name);
+        pc->gmax.name  = NULL;
+    }
+    else
+    {
+        gmx_ana_index_set(&pc->gmax, pc->b.nra, pc->b.a, NULL, 0);
+    }
+}
+
+/*! \brief
+ * Checks whether a position calculation should use a base at all.
+ *
+ * \param[in] pc   Position calculation data to check.
+ * \returns   TRUE if \p pc can use a base and gets some benefit out of it,
+ *   FALSE otherwise.
+ */
+static gmx_bool
+can_use_base(gmx_ana_poscalc_t *pc)
+{
+    /* For atoms, it should be faster to do a simple copy, so don't use a
+     * base. */
+    if (pc->type == POS_ATOM)
+    {
+        return FALSE;
+    }
+    /* For dynamic selections that do not use completion, it is not possible
+     * to use a base. */
+    if ((pc->type == POS_RES || pc->type == POS_MOL)
+        && (pc->flags & POS_DYNAMIC) && !(pc->flags & (POS_COMPLMAX | POS_COMPLWHOLE)))
+    {
+        return FALSE;
+    }
+    /* Dynamic calculations for a single position cannot use a base. */
+    if ((pc->type == POS_ALL || pc->type == POS_ALL_PBC)
+        && (pc->flags & POS_DYNAMIC))
+    {
+        return FALSE;
+    }
+    return TRUE;
+}
+
+/*! \brief
+ * Checks whether two position calculations should use a common base.
+ *
+ * \param[in]     pc1 Calculation 1 to check for.
+ * \param[in]     pc2 Calculation 2 to check for.
+ * \param[in]     g1  Index group structure that contains the atoms from
+ *   \p pc1.
+ * \param[in,out] g   Working space, should have enough allocated memory to
+ *   contain the intersection of the atoms in \p pc1 and \p pc2.
+ * \returns   TRUE if the two calculations should be merged to use a common
+ *   base, FALSE otherwise.
+ */
+static gmx_bool
+should_merge(gmx_ana_poscalc_t *pc1, gmx_ana_poscalc_t *pc2,
+             gmx_ana_index_t *g1, gmx_ana_index_t *g)
+{
+    gmx_ana_index_t  g2;
+
+    /* Do not merge calculations with different mass weighting. */
+    if ((pc1->flags & POS_MASS) != (pc2->flags & POS_MASS))
+    {
+        return FALSE;
+    }
+    /* Avoid messing up complete calculations. */
+    if ((pc1->flags & POS_COMPLWHOLE) != (pc2->flags & POS_COMPLWHOLE))
+    {
+        return FALSE;
+    }
+    /* Find the overlap between the calculations. */
+    gmx_ana_index_set(&g2, pc2->b.nra, pc2->b.a, NULL, 0);
+    gmx_ana_index_intersection(g, g1, &g2);
+    /* Do not merge if there is no overlap. */
+    if (g->isize == 0)
+    {
+        return FALSE;
+    }
+    /* Full completion calculations always match if the type is correct. */
+    if ((pc1->flags & POS_COMPLWHOLE) && (pc2->flags & POS_COMPLWHOLE)
+        && pc1->type == pc2->type)
+    {
+        return TRUE;
+    }
+    /* The calculations also match if the intersection consists of full
+     * blocks. */
+    if (gmx_ana_index_has_full_ablocks(g, &pc1->b)
+        && gmx_ana_index_has_full_ablocks(g, &pc2->b))
+    {
+        return TRUE;
+    }
+    return FALSE;
+}
+
+/*! \brief
+ * Creates a static base for position calculation.
+ *
+ * \param     pc  Data structure to copy.
+ * \returns   Pointer to a newly allocated base for \p pc.
+ *
+ * Creates and returns a deep copy of \p pc, but clears the
+ * \ref POS_DYNAMIC and \ref POS_MASKONLY flags.
+ * The newly created structure is set as the base (\c gmx_ana_poscalc_t::sbase)
+ * of \p pc and inserted in the collection before \p pc.
+ */
+static gmx_ana_poscalc_t *
+create_simple_base(gmx_ana_poscalc_t *pc)
+{
+    gmx_ana_poscalc_t *base;
+    int                flags;
+    int                rc;
+
+    flags = pc->flags & ~(POS_DYNAMIC | POS_MASKONLY);
+    rc = gmx_ana_poscalc_create(&base, pc->coll, pc->type, flags);
+    if (rc != 0)
+    {
+        gmx_fatal(FARGS, "position calculation base creation failed");
+    }
+    set_poscalc_maxindex(base, &pc->gmax, TRUE);
+
+    snew(base->p, 1);
+
+    pc->sbase = base;
+    remove_poscalc(base);
+    insert_poscalc(base, pc);
+
+    return base;
+}
+
+/*! \brief
+ * Merges a calculation into another calculation such that the new calculation
+ * can be used as a base.
+ *
+ * \param[in,out] base Base calculation to merge to.
+ * \param[in,out] pc   Position calculation to merge to \p base.
+ *
+ * After the call, \p base can be used as a base for \p pc (or any calculation
+ * that used it as a base).
+ * It is assumed that any overlap between \p base and \p pc is in complete
+ * blocks, i.e., that the merge is possible.
+ */
+static void
+merge_to_base(gmx_ana_poscalc_t *base, gmx_ana_poscalc_t *pc)
+{
+    gmx_ana_index_t  gp, gb, g;
+    int              isize, bnr;
+    int              i, j, bi, bj, bo;
+
+    base->flags |= pc->flags & (POS_VELOCITIES | POS_FORCES);
+    gmx_ana_index_set(&gp, pc->b.nra, pc->b.a, NULL, 0);
+    gmx_ana_index_set(&gb, base->b.nra, base->b.a, NULL, 0);
+    isize = gmx_ana_index_difference_size(&gp, &gb);
+    if (isize > 0)
+    {
+        gmx_ana_index_clear(&g);
+        gmx_ana_index_reserve(&g, base->b.nra + isize);
+        /* Find the new blocks */
+        gmx_ana_index_difference(&g, &gp, &gb);
+        /* Count the blocks in g */
+        i = bi = bnr = 0;
+        while (i < g.isize)
+        {
+            while (pc->b.a[pc->b.index[bi]] != g.index[i])
+            {
+                ++bi;
+            }
+            i += pc->b.index[bi+1] - pc->b.index[bi];
+            ++bnr;
+            ++bi;
+        }
+        /* Merge the atoms into a temporary structure */
+        gmx_ana_index_merge(&g, &gb, &g);
+        /* Merge the blocks */
+        srenew(base->b.index, base->b.nr + bnr + 1);
+        i  = g.isize - 1;
+        bi = base->b.nr - 1;
+        bj = pc->b.nr - 1;
+        bo = base->b.nr + bnr - 1;
+        base->b.index[bo+1] = i + 1;
+        while (bo >= 0)
+        {
+            if (bi < 0 || base->b.a[base->b.index[bi+1]-1] != g.index[i])
+            {
+                i -= pc->b.index[bj+1] - pc->b.index[bj];
+                --bj;
+            }
+            else
+            {
+                if (bj >= 0 && pc->b.a[pc->b.index[bj+1]-1] == g.index[i])
+                {
+                    --bj;
+                }
+                i -= base->b.index[bi+1] - base->b.index[bi];
+                --bi;
+            }
+            base->b.index[bo] = i + 1;
+            --bo;
+        }
+        base->b.nr           += bnr;
+        base->b.nalloc_index += bnr;
+        sfree(base->b.a);
+        base->b.nra      = g.isize;
+        base->b.a        = g.index;
+        base->b.nalloc_a = g.isize;
+        /* Refresh the gmax field */
+        gmx_ana_index_set(&base->gmax, base->b.nra, base->b.a, NULL, 0);
+    }
+}
+
+/*! \brief
+ * Merges two bases into one.
+ *
+ * \param[in,out] tbase Base calculation to merge to.
+ * \param[in]     mbase Base calculation to merge to \p tbase.
+ *
+ * After the call, \p mbase has been freed and \p tbase is used as the base
+ * for all calculations that previously had \p mbase as their base.
+ * It is assumed that any overlap between \p tbase and \p mbase is in complete
+ * blocks, i.e., that the merge is possible.
+ */
+static void
+merge_bases(gmx_ana_poscalc_t *tbase, gmx_ana_poscalc_t *mbase)
+{
+    gmx_ana_poscalc_t *pc;
+
+    merge_to_base(tbase, mbase);
+    remove_poscalc(mbase);
+    /* Set tbase as the base for all calculations that had mbase */
+    pc = tbase->coll->first;
+    while (pc)
+    {
+        if (pc->sbase == mbase)
+        {
+            pc->sbase = tbase;
+            tbase->refcount++;
+        }
+        pc = pc->next;
+    }
+    /* Free mbase */
+    mbase->refcount = 0;
+    gmx_ana_poscalc_free(mbase);
+}
+
+/*! \brief
+ * Setups the static base calculation for a position calculation.
+ *
+ * \param[in,out] pc   Position calculation to setup the base for.
+ */
+static void
+setup_base(gmx_ana_poscalc_t *pc)
+{
+    gmx_ana_poscalc_t *base, *pbase, *next;
+    gmx_ana_index_t    gp, g;
+
+    /* Exit immediately if pc should not have a base. */
+    if (!can_use_base(pc))
+    {
+        return;
+    }
+
+    gmx_ana_index_set(&gp, pc->b.nra, pc->b.a, NULL, 0);
+    gmx_ana_index_clear(&g);
+    gmx_ana_index_reserve(&g, pc->b.nra);
+    pbase = pc;
+    base = pc->coll->first;
+    while (base)
+    {
+        /* Save the next calculation so that we can safely delete base */
+        next = base->next;
+        /* Skip pc, calculations that already have a base (we should match the
+         * base instead), as well as calculations that should not have a base.
+         * If the above conditions are met, check whether we should do a
+         * merge.
+         */
+        if (base != pc && !base->sbase && can_use_base(base)
+            && should_merge(pbase, base, &gp, &g))
+        {
+            /* Check whether this is the first base found */
+            if (pbase == pc)
+            {
+                /* Create a real base if one is not present */
+                if (!base->p)
+                {
+                    pbase = create_simple_base(base);
+                }
+                else
+                {
+                    pbase = base;
+                }
+                /* Make it a base for pc as well */
+                merge_to_base(pbase, pc);
+                pc->sbase = pbase;
+                pbase->refcount++;
+            }
+            else /* This was not the first base */
+            {
+                if (!base->p)
+                {
+                    /* If it is not a real base, just make the new base as
+                     * the base for it as well. */
+                    merge_to_base(pbase, base);
+                    base->sbase = pbase;
+                    pbase->refcount++;
+                }
+                else
+                {
+                    /* If base is a real base, merge it with the new base
+                     * and delete it. */
+                    merge_bases(pbase, base);
+                }
+            }
+            gmx_ana_index_set(&gp, pbase->b.nra, pbase->b.a, NULL, 0);
+            gmx_ana_index_reserve(&g, pc->b.nra);
+        }
+        /* Proceed to the next unchecked calculation */
+        base = next;
+    }
+
+    gmx_ana_index_deinit(&g);
+
+    /* If no base was found, create one if one is required */
+    if (!pc->sbase && (pc->flags & POS_DYNAMIC)
+        && (pc->flags & (POS_COMPLMAX | POS_COMPLWHOLE)))
+    {
+        create_simple_base(pc);
+    }
+}
+
+/*!
+ * \param[out] pcp   Position calculation data structure pointer to initialize.
+ * \param[in,out] pcc   Position calculation collection.
+ * \param[in]  type  Type of calculation.
+ * \param[in]  flags Flags for setting calculation options
+ *   (see \ref poscalc_flags "documentation of the flags").
+ * \returns    0 on success.
+ */
+int
+gmx_ana_poscalc_create(gmx_ana_poscalc_t **pcp, gmx_ana_poscalc_coll_t *pcc,
+                       e_poscalc_t type, int flags)
+{
+    gmx_ana_poscalc_t *pc;
+
+    snew(pc, 1);
+    pc->type     = type;
+    pc->itype    = index_type_for_poscalc(type);
+    gmx_ana_poscalc_set_flags(pc, flags);
+    pc->refcount = 1;
+    pc->coll     = pcc;
+    insert_poscalc(pc, NULL);
+    *pcp = pc;
+    return 0;
+}
+
+/*!
+ * \param[out] pcp   Position calculation data structure pointer to initialize.
+ * \param[in,out] pcc   Position calculation collection.
+ * \param[in]  post  One of the strings acceptable for
+ *   gmx_ana_poscalc_type_from_enum().
+ * \param[in]  flags Flags for setting calculation options
+ *   (see \ref poscalc_flags "documentation of the flags").
+ * \returns    0 on success, a non-zero error value on error.
+ *
+ * This is a convenience wrapper for gmx_ana_poscalc_create().
+ * \p flags sets the default calculation options if not overridden by \p post;
+ * see gmx_ana_poscalc_type_from_enum().
+ *
+ * \see gmx_ana_poscalc_create(), gmx_ana_poscalc_type_from_enum()
+ */
+int
+gmx_ana_poscalc_create_enum(gmx_ana_poscalc_t **pcp, gmx_ana_poscalc_coll_t *pcc,
+                            const char *post, int flags)
+{
+    e_poscalc_t  type;
+    int          cflags;
+    int          rc;
+
+    cflags = flags;
+    rc = gmx_ana_poscalc_type_from_enum(post, &type, &cflags);
+    if (rc != 0)
+    {
+        *pcp = NULL;
+        return rc;
+    }
+    return gmx_ana_poscalc_create(pcp, pcc, type, cflags);
+}
+
+/*!
+ * \param[in,out] pc    Position calculation data structure.
+ * \param[in]     flags New flags.
+ *
+ * \p flags are added to the old flags.
+ * If calculation type is \ref POS_ATOM, \ref POS_MASS is automatically
+ * cleared.
+ * If both \ref POS_DYNAMIC and \ref POS_MASKONLY are provided,
+ * \ref POS_DYNAMIC is cleared.
+ * If calculation type is not \ref POS_RES or \ref POS_MOL,
+ * \ref POS_COMPLMAX and \ref POS_COMPLWHOLE are automatically cleared.
+ */
+void
+gmx_ana_poscalc_set_flags(gmx_ana_poscalc_t *pc, int flags)
+{
+    if (pc->type == POS_ATOM)
+    {
+        flags &= ~POS_MASS;
+    }
+    if (flags & POS_MASKONLY)
+    {
+        flags &= ~POS_DYNAMIC;
+    }
+    if (pc->type != POS_RES && pc->type != POS_MOL)
+    {
+        flags &= ~(POS_COMPLMAX | POS_COMPLWHOLE);
+    }
+    pc->flags |= flags;
+}
+
+/*!
+ * \param[in,out] pc  Position calculation data structure.
+ * \param[in]     g   Maximum index group for the calculation.
+ *
+ * Subsequent calls to gmx_ana_poscalc_update() should use only subsets of
+ * \p g for evaluation.
+ *
+ * The topology should have been set for the collection of which \p pc is
+ * a member.
+ */
+void
+gmx_ana_poscalc_set_maxindex(gmx_ana_poscalc_t *pc, gmx_ana_index_t *g)
+{
+    set_poscalc_maxindex(pc, g, FALSE);
+    setup_base(pc);
+}
+
+/*!
+ * \param[in]  pc  Position calculation data structure.
+ * \param[out] p   Output positions.
+ *
+ * Calls to gmx_ana_poscalc_update() using \p pc should use only positions
+ * initialized with this function.
+ * The \c p->g pointer is initialized to point to an internal group that
+ * contains the maximum index group set with gmx_ana_poscalc_set_maxindex().
+ */
+void
+gmx_ana_poscalc_init_pos(gmx_ana_poscalc_t *pc, gmx_ana_pos_t *p)
+{
+    gmx_ana_indexmap_init(&p->m, &pc->gmax, pc->coll->top, pc->itype);
+    if (!(pc->flags & POS_DYNAMIC))
+    {
+        gmx_ana_indexmap_set_static(&p->m, &pc->b);
+    }
+    gmx_ana_pos_reserve(p, p->m.nr, 0);
+    if (pc->flags & POS_VELOCITIES)
+    {
+        gmx_ana_pos_reserve_velocities(p);
+    }
+    if (pc->flags & POS_FORCES)
+    {
+        gmx_ana_pos_reserve_forces(p);
+    }
+    gmx_ana_pos_set_nr(p, p->m.nr);
+    gmx_ana_pos_set_evalgrp(p, &pc->gmax);
+}
+
+/*!
+ * \param  pc  Position calculation data to be freed.
+ *
+ * The \p pc pointer is invalid after the call.
+ */
+void
+gmx_ana_poscalc_free(gmx_ana_poscalc_t *pc)
+{
+    if (!pc)
+    {
+        return;
+    }
+
+    pc->refcount--;
+    if (pc->refcount > 0)
+    {
+        return;
+    }
+
+    remove_poscalc(pc);
+    if (pc->b.nalloc_index > 0)
+    {
+        sfree(pc->b.index);
+    }
+    if (pc->b.nalloc_a > 0)
+    {
+        sfree(pc->b.a);
+    }
+    if (pc->flags & POS_COMPLWHOLE)
+    {
+        gmx_ana_index_deinit(&pc->gmax);
+    }
+    if (pc->p)
+    {
+        gmx_ana_pos_free(pc->p);
+    }
+    if (pc->sbase)
+    {
+        gmx_ana_poscalc_free(pc->sbase);
+        sfree(pc->baseid);
+    }
+    sfree(pc);
+}
+
+/*!
+ * \param[in] pc  Position calculation data to query.
+ * \returns   TRUE if \p pc requires topology for initialization and/or
+ *   evaluation, FALSE otherwise.
+ */
+gmx_bool
+gmx_ana_poscalc_requires_top(gmx_ana_poscalc_t *pc)
+{
+    if ((pc->flags & POS_MASS) || pc->type == POS_RES || pc->type == POS_MOL)
+    {
+        return TRUE;
+    }
+    return FALSE;
+}
+
+/*!
+ * \param[in,out] pcc Position calculation collection to initialize.
+ *
+ * This function does some final initialization of the data structures in the
+ * collection to prepare them for evaluation.
+ * After this function has been called, it is no longer possible to add new
+ * calculations to the collection.
+ *
+ * This function is automatically called by gmx_ana_poscalc_init_frame() 
+ * if not called by the user earlier.
+ * Multiple calls to the function are ignored.
+ */
+void
+gmx_ana_poscalc_init_eval(gmx_ana_poscalc_coll_t *pcc)
+{
+    gmx_ana_poscalc_t      *pc;
+    int                     bi, bj;
+
+    if (pcc->bInit)
+    {
+        return;
+    }
+    pc = pcc->first;
+    while (pc)
+    {
+        /* Initialize position storage for base calculations */
+        if (pc->p)
+        {
+            gmx_ana_poscalc_init_pos(pc, pc->p);
+        }
+        /* Construct the mapping of the base positions */
+        if (pc->sbase)
+        {
+            snew(pc->baseid, pc->b.nr);
+            for (bi = bj = 0; bi < pc->b.nr; ++bi, ++bj)
+            {
+                while (pc->sbase->b.a[pc->sbase->b.index[bj]] != pc->b.a[pc->b.index[bi]])
+                {
+                    ++bj;
+                }
+                pc->baseid[bi] = bj;
+            }
+        }
+        /* Free the block data for dynamic calculations */
+        if (pc->flags & POS_DYNAMIC)
+        {
+            if (pc->b.nalloc_index > 0)
+            {
+                sfree(pc->b.index);
+                pc->b.nalloc_index = 0;
+            }
+            if (pc->b.nalloc_a > 0)
+            {
+                sfree(pc->b.a);
+                pc->b.nalloc_a = 0;
+            }
+        }
+        pc = pc->next;
+    }
+    pcc->bInit = TRUE;
+}
+
+/*!
+ * \param[in,out] pcc Position calculation collection to initialize.
+ *
+ * Clears the evaluation flag for all calculations.
+ * Should be called for each frame before calling gmx_ana_poscalc_update().
+ *
+ * This function is automatically called by gmx_ana_do() for each
+ * frame, and should not be called by the user unless gmx_ana_do() is
+ * not being used.
+ *
+ * This function calls gmx_ana_poscalc_init_eval() automatically if it has
+ * not been called earlier.
+ */
+void
+gmx_ana_poscalc_init_frame(gmx_ana_poscalc_coll_t *pcc)
+{
+    gmx_ana_poscalc_t      *pc;
+
+    if (!pcc->bInit)
+    {
+        gmx_ana_poscalc_init_eval(pcc);
+    }
+    /* Clear the evaluation flags */
+    pc = pcc->first;
+    while (pc)
+    {
+        pc->bEval = FALSE;
+        pc = pc->next;
+    }
+}
+
+/*!
+ * \param[in]     pc   Position calculation data.
+ * \param[in,out] p    Output positions, initialized previously with
+ *   gmx_ana_poscalc_init_pos() using \p pc.
+ * \param[in]     g    Index group to use for the update.
+ * \param[in]     fr   Current frame.
+ * \param[in]     pbc  PBC data, or NULL if no PBC should be used.
+ *
+ * gmx_ana_poscalc_init_frame() should be called for each frame before calling
+ * this function.
+ */
+void
+gmx_ana_poscalc_update(gmx_ana_poscalc_t *pc, gmx_ana_pos_t *p,
+                       gmx_ana_index_t *g, t_trxframe *fr, t_pbc *pbc)
+{
+    int  i, j, bi, bj;
+    
+    if (pc->bEval == TRUE && !(pc->flags & POS_MASKONLY))
+    {
+        return;
+    }
+    if (pc->sbase)
+    {
+        gmx_ana_poscalc_update(pc->sbase, NULL, NULL, fr, pbc);
+    }
+    if (!p)
+    {
+        p = pc->p;
+    }
+    if (!g)
+    {
+        g = &pc->gmax;
+    }
+    gmx_ana_pos_set_evalgrp(p, g);
+
+    /* Update the index map */
+    if (pc->flags & POS_DYNAMIC)
+    {
+        gmx_ana_indexmap_update(&p->m, g, FALSE);
+        p->nr = p->m.nr;
+    }
+    else if (pc->flags & POS_MASKONLY)
+    {
+        gmx_ana_indexmap_update(&p->m, g, TRUE);
+        if (pc->bEval)
+            return;
+    }
+    if (!(pc->flags & POS_DYNAMIC))
+    {
+        pc->bEval = TRUE;
+    }
+
+    /* Evaluate the positions */
+    if (pc->sbase)
+    {
+        /* TODO: It might be faster to evaluate the positions within this
+         * loop instead of in the beginning. */
+        if (pc->flags & POS_DYNAMIC)
+        {
+            for (bi = 0; bi < p->nr; ++bi)
+            {
+                bj = pc->baseid[p->m.refid[bi]];
+                copy_rvec(pc->sbase->p->x[bj], p->x[bi]);
+            }
+            if (p->v)
+            {
+                for (bi = 0; bi < p->nr; ++bi)
+                {
+                    bj = pc->baseid[p->m.refid[bi]];
+                    copy_rvec(pc->sbase->p->v[bj], p->v[bi]);
+                }
+            }
+            if (p->f)
+            {
+                for (bi = 0; bi < p->nr; ++bi)
+                {
+                    bj = pc->baseid[p->m.refid[bi]];
+                    copy_rvec(pc->sbase->p->f[bj], p->f[bi]);
+                }
+            }
+        }
+        else
+        {
+            for (bi = 0; bi < p->nr; ++bi)
+            {
+                bj = pc->baseid[bi];
+                copy_rvec(pc->sbase->p->x[bj], p->x[bi]);
+            }
+            if (p->v)
+            {
+                for (bi = 0; bi < p->nr; ++bi)
+                {
+                    bj = pc->baseid[bi];
+                    copy_rvec(pc->sbase->p->v[bj], p->v[bi]);
+                }
+            }
+            if (p->f)
+            {
+                for (bi = 0; bi < p->nr; ++bi)
+                {
+                    bj = pc->baseid[bi];
+                    copy_rvec(pc->sbase->p->f[bj], p->f[bi]);
+                }
+            }
+        }
+    }
+    else /* pc->sbase is NULL */
+    {
+        if (pc->flags & POS_DYNAMIC)
+        {
+            pc->b.nr    = p->m.mapb.nr;
+            pc->b.index = p->m.mapb.index;
+            pc->b.nra   = g->isize;
+            pc->b.a     = g->index;
+        }
+        if (p->v && !fr->bV)
+        {
+            for (i = 0; i < pc->b.nra; ++i)
+            {
+                clear_rvec(p->v[i]);
+            }
+        }
+        if (p->f && !fr->bF)
+        {
+            for (i = 0; i < pc->b.nra; ++i)
+            {
+                clear_rvec(p->f[i]);
+            }
+        }
+        /* Here, we assume that the topology has been properly initialized,
+         * and do not check the return values of gmx_calc_comg*(). */
+        switch (pc->type)
+        {
+        case POS_ATOM:
+            for (i = 0; i < pc->b.nra; ++i)
+            {
+                copy_rvec(fr->x[pc->b.a[i]], p->x[i]);
+            }
+            if (p->v && fr->bV)
+            {
+                for (i = 0; i < pc->b.nra; ++i)
+                {
+                    copy_rvec(fr->v[pc->b.a[i]], p->v[i]);
+                }
+            }
+            if (p->f && fr->bF)
+            {
+                for (i = 0; i < pc->b.nra; ++i)
+                {
+                    copy_rvec(fr->f[pc->b.a[i]], p->f[i]);
+                }
+            }
+            break;
+        case POS_ALL:
+            gmx_calc_comg(pc->coll->top, fr->x, pc->b.nra, pc->b.a,
+                          pc->flags & POS_MASS, p->x[0]);
+            if (p->v && fr->bV)
+            {
+                gmx_calc_comg(pc->coll->top, fr->v, pc->b.nra, pc->b.a,
+                              pc->flags & POS_MASS, p->v[0]);
+            }
+            if (p->f && fr->bF)
+            {
+                gmx_calc_comg_f(pc->coll->top, fr->f, pc->b.nra, pc->b.a,
+                                pc->flags & POS_MASS, p->f[0]);
+            }
+            break;
+        case POS_ALL_PBC:
+            gmx_calc_comg_pbc(pc->coll->top, fr->x, pbc, pc->b.nra, pc->b.a,
+                              pc->flags & POS_MASS, p->x[0]);
+            if (p->v && fr->bV)
+            {
+                gmx_calc_comg(pc->coll->top, fr->v, pc->b.nra, pc->b.a,
+                              pc->flags & POS_MASS, p->v[0]);
+            }
+            if (p->f && fr->bF)
+            {
+                gmx_calc_comg_f(pc->coll->top, fr->f, pc->b.nra, pc->b.a,
+                                pc->flags & POS_MASS, p->f[0]);
+            }
+            break;
+        default:
+            gmx_calc_comg_blocka(pc->coll->top, fr->x, &pc->b,
+                                 pc->flags & POS_MASS, p->x);
+            if (p->v && fr->bV)
+            {
+                gmx_calc_comg_blocka(pc->coll->top, fr->v, &pc->b,
+                                     pc->flags & POS_MASS, p->v);
+            }
+            if (p->f && fr->bF)
+            {
+                gmx_calc_comg_blocka(pc->coll->top, fr->f, &pc->b,
+                                     pc->flags & POS_MASS, p->f);
+            }
+            break;
+        }
+    }
+}
diff --git a/src/gromacs/selection/poscalc.h b/src/gromacs/selection/poscalc.h
new file mode 100644 (file)
index 0000000..1ebd5c0
--- /dev/null
@@ -0,0 +1,193 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief API for structured and optimized calculation of positions.
+ *
+ * The functions in this header are used internally by the analysis library
+ * to calculate positions.
+ * They can also be used in user code, but in most cases there should be no
+ * need. Instead, one should write an analysis tool such that it gets all
+ * positions through selections.
+ *
+ * The API is documented in more detail on a separate page:
+ * \ref poscalcengine.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_selection
+ */
+#ifndef GMX_SELECTION_POSCALC_H
+#define GMX_SELECTION_POSCALC_H
+
+#include "../legacyheaders/typedefs.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*! \name Flags for position calculation.
+ * \anchor poscalc_flags
+ */
+/*@{*/
+/*! \brief
+ * Use mass weighting.
+ *
+ * If this flag is set, the positions will be calculated using mass weighting,
+ * i.e., one gets center-of-mass positions.
+ * Without the flag, center-of-geometry positions are calculated.
+ * Does not have any effect if the calculation type is \ref POS_ATOM.
+ */
+#define POS_MASS        1
+/*! \brief
+ * Calculate positions for the same atoms in residues/molecules.
+ *
+ * If this flag is set, the positions are always calculated using the same
+ * atoms for each residue/molecule, even if the evaluation group contains only
+ * some of the atoms for some frames.
+ * The group passed to gmx_ana_poscalc_set_maxindex() is used to determine
+ * the atoms to use for the calculation.
+ *
+ * Has no effect unless \ref POS_DYNAMIC is set or if the calculation type
+ * is not \ref POS_RES of \ref POS_MOL.
+ */
+#define POS_COMPLMAX    2
+/*! \brief
+ * Calculate positions for whole residues/molecules.
+ *
+ * If this flag is set, the positions will be calculated for whole
+ * residues/molecules, even if the group contains only some of the atoms in
+ * the residue/molecule.
+ *
+ * Has no effect unless the calculation type is \ref POS_RES or \ref POS_MOL.
+ */
+#define POS_COMPLWHOLE  4
+/*! \brief
+ * Enable handling of changing calculation groups.
+ *
+ * Can be used for static calculations as well, but implies a small
+ * performance penalty.
+ */
+#define POS_DYNAMIC     16
+/*! \brief
+ * Update \c gmx_ana_pos_t::m dynamically for an otherwise static
+ * calculation.
+ *
+ * Has effect only if \ref POS_DYNAMIC is not set.
+ */
+#define POS_MASKONLY    32
+/*! \brief
+ * Calculate velocities of the positions.
+ */
+#define POS_VELOCITIES  64
+/*! \brief
+ * Calculate forces on the positions.
+ */
+#define POS_FORCES      128
+/*@}*/
+
+/** Specifies the type of positions to be calculated. */
+typedef enum
+{
+    POS_ATOM,    /**< Copy atomic coordinates. */
+    POS_RES,     /**< Calculate center for each residue. */
+    POS_MOL,     /**< Calculate center for each molecule. */
+    POS_ALL,     /**< Calculate center for the whole group. */
+    POS_ALL_PBC  /**< Calculate center for the whole group with PBC. */
+} e_poscalc_t;
+
+/** Collection of \c gmx_ana_poscalc_t structures for the same topology. */
+typedef struct gmx_ana_poscalc_coll_t gmx_ana_poscalc_coll_t;
+/** Data structure for position calculation. */
+typedef struct gmx_ana_poscalc_t gmx_ana_poscalc_t;
+
+struct gmx_ana_index_t;
+struct gmx_ana_pos_t;
+
+/** Converts a string to parameters for gmx_ana_poscalc_create(). */
+int
+gmx_ana_poscalc_type_from_enum(const char *post, e_poscalc_t *type, int *flags);
+/** Creates a list of strings for position enum parameter handling. */
+const char **
+gmx_ana_poscalc_create_type_enum(gmx_bool bAtom);
+
+/** Creates a new position calculation collection object. */
+int
+gmx_ana_poscalc_coll_create(gmx_ana_poscalc_coll_t **pccp);
+/** Sets the topology for a position calculation collection. */
+void
+gmx_ana_poscalc_coll_set_topology(gmx_ana_poscalc_coll_t *pcc, t_topology *top);
+/** Frees memory allocated for a position calculation collection. */
+void
+gmx_ana_poscalc_coll_free(gmx_ana_poscalc_coll_t *pcc);
+/** Prints information about calculations in a position calculation collection. */
+void
+gmx_ana_poscalc_coll_print_tree(FILE *fp, gmx_ana_poscalc_coll_t *pcc);
+
+/** Creates a new position calculation. */
+int
+gmx_ana_poscalc_create(gmx_ana_poscalc_t **pcp, gmx_ana_poscalc_coll_t *pcc,
+                       e_poscalc_t type, int flags);
+/** Creates a new position calculation based on an enum value. */
+int
+gmx_ana_poscalc_create_enum(gmx_ana_poscalc_t **pcp, gmx_ana_poscalc_coll_t *pcc,
+                            const char *post, int flags);
+/** Sets the flags for position calculation. */
+void
+gmx_ana_poscalc_set_flags(gmx_ana_poscalc_t *pc, int flags);
+/** Sets the maximum possible input index group for position calculation. */
+void
+gmx_ana_poscalc_set_maxindex(gmx_ana_poscalc_t *pc, struct gmx_ana_index_t *g);
+/** Initializes positions for position calculation output. */
+void
+gmx_ana_poscalc_init_pos(gmx_ana_poscalc_t *pc, struct gmx_ana_pos_t *p);
+/** Frees the memory allocated for position calculation. */
+void
+gmx_ana_poscalc_free(gmx_ana_poscalc_t *pc);
+/** Returns TRUE if the position calculation requires topology information. */
+gmx_bool
+gmx_ana_poscalc_requires_top(gmx_ana_poscalc_t *pc);
+
+/** Initializes evaluation for a position calculation collection. */
+void
+gmx_ana_poscalc_init_eval(gmx_ana_poscalc_coll_t *pcc);
+/** Initializes a position calculation collection for a new frame. */
+void
+gmx_ana_poscalc_init_frame(gmx_ana_poscalc_coll_t *pcc);
+/** Updates a single COM/COG structure for a frame. */
+void
+gmx_ana_poscalc_update(gmx_ana_poscalc_t *pc,
+                       struct gmx_ana_pos_t *p, struct gmx_ana_index_t *g,
+                       t_trxframe *fr, t_pbc *pbc);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/gromacs/selection/position.cpp b/src/gromacs/selection/position.cpp
new file mode 100644 (file)
index 0000000..f7dabf2
--- /dev/null
@@ -0,0 +1,430 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * Implements functions in position.h.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_selection
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <assert.h>
+#include <string.h>
+
+#include <smalloc.h>
+#include <typedefs.h>
+#include <vec.h>
+
+#include "gromacs/selection/indexutil.h"
+#include "gromacs/selection/position.h"
+
+/*!
+ * \param[out] pos      Output structure.
+ *
+ * Any contents of \p pos are discarded without freeing.
+ */
+void
+gmx_ana_pos_clear(gmx_ana_pos_t *pos)
+{
+    pos->nr = 0;
+    pos->x  = NULL;
+    pos->v  = NULL;
+    pos->f  = NULL;
+    gmx_ana_indexmap_clear(&pos->m);
+    pos->g  = NULL;
+    pos->nalloc_x = 0;
+}
+
+/*!
+ * \param[in,out] pos   Position data structure.
+ * \param[in]     n     Maximum number of positions.
+ * \param[in]     isize Maximum number of atoms.
+ *
+ * Ensures that enough memory is allocated in \p pos to calculate \p n
+ * positions from \p isize atoms.
+ */
+void
+gmx_ana_pos_reserve(gmx_ana_pos_t *pos, int n, int isize)
+{
+    if (pos->nalloc_x < n)
+    {
+        pos->nalloc_x = n;
+        srenew(pos->x, n);
+        if (pos->v)
+        {
+            srenew(pos->v, n);
+        }
+        if (pos->f)
+        {
+            srenew(pos->f, n);
+        }
+    }
+    if (isize > 0)
+    {
+        gmx_ana_indexmap_reserve(&pos->m, n, isize);
+    }
+}
+
+/*!
+ * \param[in,out] pos   Position data structure.
+ *
+ * Currently, this function can only be called after gmx_ana_pos_reserve()
+ * has been called at least once with a \p n > 0.
+ */
+void
+gmx_ana_pos_reserve_velocities(gmx_ana_pos_t *pos)
+{
+    assert(pos->nalloc_x > 0);
+    if (!pos->v)
+    {
+        snew(pos->v, pos->nalloc_x);
+    }
+}
+
+/*!
+ * \param[in,out] pos   Position data structure.
+ *
+ * Currently, this function can only be called after gmx_ana_pos_reserve()
+ * has been called at least once with a \p n > 0.
+ */
+void
+gmx_ana_pos_reserve_forces(gmx_ana_pos_t *pos)
+{
+    assert(pos->nalloc_x > 0);
+    if (!pos->f)
+    {
+        snew(pos->f, pos->nalloc_x);
+    }
+}
+
+/*!
+ * \param[out]    pos  Position data structure to initialize.
+ * \param[in]     x    Position vector to use.
+ */
+void
+gmx_ana_pos_init_const(gmx_ana_pos_t *pos, rvec x)
+{
+    gmx_ana_pos_clear(pos);
+    pos->nr = 1;
+    snew(pos->x, 1);
+    snew(pos->v, 1);
+    snew(pos->f, 1);
+    pos->nalloc_x = 1;
+    copy_rvec(x, pos->x[0]);
+    clear_rvec(pos->v[0]);
+    clear_rvec(pos->f[0]);
+    gmx_ana_indexmap_init(&pos->m, NULL, NULL, INDEX_UNKNOWN);
+}
+
+/*!
+ * \param[in,out] pos   Position data structure.
+ *
+ * Frees any memory allocated within \p pos.
+ * The pointer \p pos itself is not freed.
+ *
+ * \see gmx_ana_pos_free()
+ */
+void
+gmx_ana_pos_deinit(gmx_ana_pos_t *pos)
+{
+    pos->nr = 0;
+    sfree(pos->x); pos->x = NULL;
+    sfree(pos->v); pos->v = NULL;
+    sfree(pos->f); pos->f = NULL;
+    pos->nalloc_x = 0;
+    gmx_ana_indexmap_deinit(&pos->m);
+}
+
+/*!
+ * \param[in,out] pos   Position data structure.
+ *
+ * Frees any memory allocated for \p pos.
+ * The pointer \p pos is also freed, and is invalid after the call.
+ *
+ * \see gmx_ana_pos_deinit()
+ */
+void
+gmx_ana_pos_free(gmx_ana_pos_t *pos)
+{
+    gmx_ana_pos_deinit(pos);
+    sfree(pos);
+}
+
+/*!
+ * \param[in,out] dest   Destination positions.
+ * \param[in]     src    Source positions.
+ * \param[in]     bFirst If TRUE, memory is allocated for \p dest and a full
+ *   copy is made; otherwise, only variable parts are copied, and no memory
+ *   is allocated.
+ *
+ * \p dest should have been initialized somehow (calloc() is enough).
+ */
+void
+gmx_ana_pos_copy(gmx_ana_pos_t *dest, gmx_ana_pos_t *src, gmx_bool bFirst)
+{
+    if (bFirst)
+    {
+        gmx_ana_pos_reserve(dest, src->nr, 0);
+        if (src->v)
+        {
+            gmx_ana_pos_reserve_velocities(dest);
+        }
+        if (src->f)
+        {
+            gmx_ana_pos_reserve_forces(dest);
+        }
+    }
+    dest->nr = src->nr;
+    memcpy(dest->x, src->x, dest->nr*sizeof(*dest->x));
+    if (dest->v)
+    {
+        memcpy(dest->v, src->v, dest->nr*sizeof(*dest->v));
+    }
+    if (dest->f)
+    {
+        memcpy(dest->f, src->f, dest->nr*sizeof(*dest->f));
+    }
+    gmx_ana_indexmap_copy(&dest->m, &src->m, bFirst);
+    dest->g = src->g;
+}
+
+/*!
+ * \param[in,out] pos  Position data structure.
+ * \param[in]     nr   Number of positions.
+ */
+void
+gmx_ana_pos_set_nr(gmx_ana_pos_t *pos, int nr)
+{
+    pos->nr = nr;
+}
+
+/*!
+ * \param[in,out] pos  Position data structure.
+ * \param         g    Evaluation group.
+ *
+ * The old group, if any, is discarded.
+ * Note that only a pointer to \p g is stored; it is the responsibility of
+ * the caller to ensure that \p g is not freed while it can be accessed
+ * through \p pos.
+ */
+void
+gmx_ana_pos_set_evalgrp(gmx_ana_pos_t *pos, gmx_ana_index_t *g)
+{
+    pos->g = g;
+}
+
+/*!
+ * \param[in,out] pos   Position data structure.
+ *
+ * Sets the number of positions to 0.
+ */
+void
+gmx_ana_pos_empty_init(gmx_ana_pos_t *pos)
+{
+    pos->nr = 0;
+    pos->m.nr = 0;
+    pos->m.mapb.nr = 0;
+    pos->m.b.nr = 0;
+    pos->m.b.nra = 0;
+    /* This should not really be necessary, but do it for safety... */
+    pos->m.mapb.index[0] = 0;
+    pos->m.b.index[0] = 0;
+    /* This function should only be used to construct all the possible
+     * positions, so the result should always be static. */
+    pos->m.bStatic = TRUE;
+    pos->m.bMapStatic = TRUE;
+}
+
+/*!
+ * \param[in,out] pos   Position data structure.
+ *
+ * Sets the number of positions to 0.
+ */
+void
+gmx_ana_pos_empty(gmx_ana_pos_t *pos)
+{
+    pos->nr = 0;
+    pos->m.nr = 0;
+    pos->m.mapb.nr = 0;
+    /* This should not really be necessary, but do it for safety... */
+    pos->m.mapb.index[0] = 0;
+    /* We set the flags to TRUE, although really in the empty state they
+     * should be FALSE. This makes it possible to update the flags in
+     * gmx_ana_pos_append(), and just make a simple check in
+     * gmx_ana_pos_append_finish(). */
+    pos->m.bStatic = TRUE;
+    pos->m.bMapStatic = TRUE;
+}
+
+/*!
+ * \param[in,out] dest  Data structure to which the new position is appended.
+ * \param[in,out] g     Data structure to which the new atoms are appended.
+ * \param[in]     src   Data structure from which the position is copied.
+ * \param[in]     i     Index in \p from to copy.
+ */
+void
+gmx_ana_pos_append_init(gmx_ana_pos_t *dest, gmx_ana_index_t *g,
+                        gmx_ana_pos_t *src, int i)
+{
+    int  j, k;
+
+    j = dest->nr;
+    copy_rvec(src->x[i], dest->x[j]);
+    if (dest->v)
+    {
+        if (src->v)
+        {
+            copy_rvec(src->v[i], dest->v[j]);
+        }
+        else
+        {
+            clear_rvec(dest->v[j]);
+        }
+    }
+    if (dest->f)
+    {
+        if (src->f)
+        {
+            copy_rvec(src->f[i], dest->f[j]);
+        }
+        else
+        {
+            clear_rvec(dest->f[j]);
+        }
+    }
+    dest->m.refid[j] = j;
+    dest->m.mapid[j] = src->m.mapid[i];
+    dest->m.orgid[j] = src->m.orgid[i];
+    for (k = src->m.mapb.index[i]; k < src->m.mapb.index[i+1]; ++k)
+    {
+        g->index[g->isize++]         = src->g->index[k];
+        dest->m.b.a[dest->m.b.nra++] = src->m.b.a[k];
+    }
+    dest->m.mapb.index[j+1] = g->isize;
+    dest->m.b.index[j+1]    = g->isize;
+    dest->nr++;
+    dest->m.nr = dest->nr;
+    dest->m.mapb.nr = dest->nr;
+    dest->m.b.nr = dest->nr;
+}
+
+/*!
+ * \param[in,out] dest  Data structure to which the new position is appended
+ *      (can be NULL, in which case only \p g is updated).
+ * \param[in,out] g     Data structure to which the new atoms are appended.
+ * \param[in]     src   Data structure from which the position is copied.
+ * \param[in]     i     Index in \p src to copy.
+ * \param[in]     refid Reference ID in \p out
+ *   (all negative values are treated as -1).
+ *
+ * If \p dest is NULL, the value of \p refid is not used.
+ */
+void
+gmx_ana_pos_append(gmx_ana_pos_t *dest, gmx_ana_index_t *g,
+                   gmx_ana_pos_t *src, int i, int refid)
+{
+    int  j, k;
+
+    for (k = src->m.mapb.index[i]; k < src->m.mapb.index[i+1]; ++k)
+    {
+        g->index[g->isize++] = src->g->index[k];
+    }
+    if (dest)
+    {
+        j = dest->nr;
+        if (dest->v)
+        {
+            if (src->v)
+            {
+                copy_rvec(src->v[i], dest->v[j]);
+            }
+            else
+            {
+                clear_rvec(dest->v[j]);
+            }
+        }
+        if (dest->f)
+        {
+            if (src->f)
+            {
+                copy_rvec(src->f[i], dest->f[j]);
+            }
+            else
+            {
+                clear_rvec(dest->f[j]);
+            }
+        }
+        copy_rvec(src->x[i], dest->x[j]);
+        if (refid < 0)
+        {
+            dest->m.refid[j] = -1;
+            dest->m.bStatic = FALSE;
+            /* If we are using masks, there is no need to alter the
+             * mapid field. */
+        }
+        else
+        {
+            if (refid != j)
+            {
+                dest->m.bStatic = FALSE;
+                dest->m.bMapStatic = FALSE;
+            }
+            dest->m.refid[j] = refid;
+            /* Use the original IDs from the output structure to correctly
+             * handle user customization. */
+            dest->m.mapid[j] = dest->m.orgid[refid];
+        }
+        dest->m.mapb.index[j+1] = g->isize;
+        dest->nr++;
+        dest->m.nr = dest->nr;
+        dest->m.mapb.nr = dest->nr;
+    }
+}
+
+/*!
+ * \param[in,out] pos   Position data structure.
+ *
+ * After gmx_ana_pos_empty(), internal state of the position data structure
+ * is not consistent before this function is called. This function should be
+ * called after any gmx_ana_pos_append() calls have been made.
+ */
+void
+gmx_ana_pos_append_finish(gmx_ana_pos_t *pos)
+{
+    if (pos->m.nr != pos->m.b.nr)
+    {
+        pos->m.bStatic = FALSE;
+        pos->m.bMapStatic = FALSE;
+    }
+}
diff --git a/src/gromacs/selection/position.h b/src/gromacs/selection/position.h
new file mode 100644 (file)
index 0000000..8b5adca
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \file
+ * \brief API for handling positions.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_selection
+ */
+#ifndef GMX_SELECTION_POSITION_H
+#define GMX_SELECTION_POSITION_H
+
+#include "../legacyheaders/types/simple.h"
+
+#include "indexutil.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*! \brief
+ * Stores a set of positions together with their origins.
+ */
+typedef struct gmx_ana_pos_t
+{
+    /*! \brief
+     * Number of positions.
+     */
+    int                 nr;
+    /*! \brief
+     * Array of positions.
+     */
+    rvec               *x;
+    /*! \brief
+     * Velocities (can be NULL).
+     */
+    rvec               *v;
+    /*! \brief
+     * Forces (can be NULL).
+     */
+    rvec               *f;
+    /*! \brief
+     * Mapping of the current positions to the original group.
+     *
+     * \see gmx_ana_indexmap_t
+     */
+    gmx_ana_indexmap_t  m;
+    /*! \brief
+     * Pointer to the current evaluation group.
+     */
+    gmx_ana_index_t    *g;
+    /*! \brief
+     * Number of elements allocated for \c x.
+     */
+    int                 nalloc_x;
+} gmx_ana_pos_t;
+
+/** Initializes an empty position structure. */
+void
+gmx_ana_pos_clear(gmx_ana_pos_t *pos);
+/** Ensures that enough memory has been allocated to store positions. */
+void
+gmx_ana_pos_reserve(gmx_ana_pos_t *pos, int n, int isize);
+/** Request memory allocation for velocities. */
+void
+gmx_ana_pos_reserve_velocities(gmx_ana_pos_t *pos);
+/** Request memory allocation for forces. */
+void
+gmx_ana_pos_reserve_forces(gmx_ana_pos_t *pos);
+/** Initializes a \c gmx_ana_pos_t to represent a constant position. */
+void
+gmx_ana_pos_init_const(gmx_ana_pos_t *pos, rvec x);
+/** Frees the memory allocated for position storage. */
+void
+gmx_ana_pos_deinit(gmx_ana_pos_t *pos);
+/** Frees the memory allocated for positions. */
+void
+gmx_ana_pos_free(gmx_ana_pos_t *pos);
+/** Copies the evaluated positions to a preallocated data structure. */
+void
+gmx_ana_pos_copy(gmx_ana_pos_t *dest, gmx_ana_pos_t *src, gmx_bool bFirst);
+
+/** Sets the number of positions in a position structure. */
+void
+gmx_ana_pos_set_nr(gmx_ana_pos_t *pos, int n);
+/** Sets the evaluation group of a position data structure. */
+void
+gmx_ana_pos_set_evalgrp(gmx_ana_pos_t *pos, gmx_ana_index_t *g);
+/** Empties a position data structure with full initialization. */
+void
+gmx_ana_pos_empty_init(gmx_ana_pos_t *pos);
+/** Empties a position data structure. */
+void
+gmx_ana_pos_empty(gmx_ana_pos_t *pos);
+/** Appends a position to a preallocated data structure with full
+ * initialization. */
+void
+gmx_ana_pos_append_init(gmx_ana_pos_t *dest, gmx_ana_index_t *g,
+                        gmx_ana_pos_t *src, int i);
+/** Appends a position to a preallocated data structure. */
+void
+gmx_ana_pos_append(gmx_ana_pos_t *dest, gmx_ana_index_t *g,
+                   gmx_ana_pos_t *src, int i, int refid);
+/** Updates position data structure state after appends. */
+void
+gmx_ana_pos_append_finish(gmx_ana_pos_t *pos);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/gromacs/selection/regenerate_parser.sh b/src/gromacs/selection/regenerate_parser.sh
new file mode 100755 (executable)
index 0000000..e8af512
--- /dev/null
@@ -0,0 +1,22 @@
+#!/bin/bash
+#
+# This script runs Bison and/or Flex to regenerate the files as follows:
+#   parser.y  -> parser.c, parser.h
+#   scanner.l -> scanner.c, scanner_flex.h
+# The commands are run only if the generated files are older than the
+# Bison/Flex input files, or if a '-f' flag is provided.
+
+FORCE=
+if [ "x$1" == "x-f" ] ; then
+    FORCE=1
+fi
+
+# For convenience, change to the directory where the files are located
+# if the script is run from the root of the source tree.
+dirname=src/gromacs/selection
+if [[ -f $dirname/parser.y && -f $dirname/scanner.l ]] ; then
+    cd $dirname
+fi
+
+[[ $FORCE || parser.y  -nt parser.cpp ]]  && bison -t -o parser.cpp --defines=parser.h parser.y
+[[ $FORCE || scanner.l -nt scanner.cpp ]] && flex -o scanner.cpp scanner.l
diff --git a/src/gromacs/selection/scanner.cpp b/src/gromacs/selection/scanner.cpp
new file mode 100644 (file)
index 0000000..8f1c439
--- /dev/null
@@ -0,0 +1,2220 @@
+#line 2 "scanner.cpp"
+
+#line 4 "scanner.cpp"
+
+#define  YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+#define YY_FLEX_SUBMINOR_VERSION 35
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+/* First, we deal with  platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types. 
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t; 
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN               (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN              (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN              (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX               (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX              (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX              (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX              (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX             (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX             (4294967295U)
+#endif
+
+#endif /* ! C99 */
+
+#endif /* ! FLEXINT_H */
+
+#ifdef __cplusplus
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else  /* ! __cplusplus */
+
+/* C99 requires __STDC__ to be defined as 1. */
+#if defined (__STDC__)
+
+#define YY_USE_CONST
+
+#endif /* defined (__STDC__) */
+#endif /* ! __cplusplus */
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index.  If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* An opaque pointer. */
+#ifndef YY_TYPEDEF_YY_SCANNER_T
+#define YY_TYPEDEF_YY_SCANNER_T
+typedef void* yyscan_t;
+#endif
+
+/* For convenience, these vars (plus the bison vars far below)
+   are macros in the reentrant scanner. */
+#define yyin yyg->yyin_r
+#define yyout yyg->yyout_r
+#define yyextra yyg->yyextra_r
+#define yyleng yyg->yyleng_r
+#define yytext yyg->yytext_r
+#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno)
+#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column)
+#define yy_flex_debug yyg->yy_flex_debug_r
+
+/* Enter a start condition.  This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN yyg->yy_start = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state.  The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START ((yyg->yy_start - 1) / 2)
+#define YYSTATE YY_START
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE _gmx_sel_yyrestart(yyin ,yyscanner )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#ifdef __ia64__
+/* On IA-64, the buffer size is 16k, not 8k.
+ * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case.
+ * Ditto for the __ia64__ case accordingly.
+ */
+#define YY_BUF_SIZE 32768
+#else
+#define YY_BUF_SIZE 16384
+#endif /* __ia64__ */
+#endif
+
+/* The state buf must be large enough to hold one state per character in the main buffer.
+ */
+#define YY_STATE_BUF_SIZE   ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+    #define YY_LESS_LINENO(n)
+    
+/* Return all but the first "n" matched characters back to the input stream. */
+#define yyless(n) \
+       do \
+               { \
+               /* Undo effects of setting up yytext. */ \
+        int yyless_macro_arg = (n); \
+        YY_LESS_LINENO(yyless_macro_arg);\
+               *yy_cp = yyg->yy_hold_char; \
+               YY_RESTORE_YY_MORE_OFFSET \
+               yyg->yy_c_buf_p = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
+               YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+               } \
+       while ( 0 )
+
+#define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner )
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
+#endif
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+       {
+       FILE *yy_input_file;
+
+       char *yy_ch_buf;                /* input buffer */
+       char *yy_buf_pos;               /* current position in input buffer */
+
+       /* Size of input buffer in bytes, not including room for EOB
+        * characters.
+        */
+       yy_size_t yy_buf_size;
+
+       /* Number of characters read into yy_ch_buf, not including EOB
+        * characters.
+        */
+       int yy_n_chars;
+
+       /* Whether we "own" the buffer - i.e., we know we created it,
+        * and can realloc() it to grow it, and should free() it to
+        * delete it.
+        */
+       int yy_is_our_buffer;
+
+       /* Whether this is an "interactive" input source; if so, and
+        * if we're using stdio for input, then we want to use getc()
+        * instead of fread(), to make sure we stop fetching input after
+        * each newline.
+        */
+       int yy_is_interactive;
+
+       /* Whether we're considered to be at the beginning of a line.
+        * If so, '^' rules will be active on the next match, otherwise
+        * not.
+        */
+       int yy_at_bol;
+
+    int yy_bs_lineno; /**< The line count. */
+    int yy_bs_column; /**< The column count. */
+    
+       /* Whether to try to fill the input buffer when we reach the
+        * end of it.
+        */
+       int yy_fill_buffer;
+
+       int yy_buffer_status;
+
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+       /* When an EOF's been seen but there's still some text to process
+        * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+        * shouldn't try reading from the input source any more.  We might
+        * still have a bunch of tokens to match, though, because of
+        * possible backing-up.
+        *
+        * When we actually see the EOF, we change the status to "new"
+        * (via _gmx_sel_yyrestart()), so that the user can continue scanning by
+        * just pointing yyin at a new input file.
+        */
+#define YY_BUFFER_EOF_PENDING 2
+
+       };
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ *
+ * Returns the top of the stack, or NULL.
+ */
+#define YY_CURRENT_BUFFER ( yyg->yy_buffer_stack \
+                          ? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] \
+                          : NULL)
+
+/* Same as previous macro, but useful when we know that the buffer stack is not
+ * NULL or when we need an lvalue. For internal use only.
+ */
+#define YY_CURRENT_BUFFER_LVALUE yyg->yy_buffer_stack[yyg->yy_buffer_stack_top]
+
+void _gmx_sel_yyrestart (FILE *input_file ,yyscan_t yyscanner );
+void _gmx_sel_yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner );
+YY_BUFFER_STATE _gmx_sel_yy_create_buffer (FILE *file,int size ,yyscan_t yyscanner );
+void _gmx_sel_yy_delete_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
+void _gmx_sel_yy_flush_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
+void _gmx_sel_yypush_buffer_state (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner );
+void _gmx_sel_yypop_buffer_state (yyscan_t yyscanner );
+
+static void _gmx_sel_yyensure_buffer_stack (yyscan_t yyscanner );
+static void _gmx_sel_yy_load_buffer_state (yyscan_t yyscanner );
+static void _gmx_sel_yy_init_buffer (YY_BUFFER_STATE b,FILE *file ,yyscan_t yyscanner );
+
+#define YY_FLUSH_BUFFER _gmx_sel_yy_flush_buffer(YY_CURRENT_BUFFER ,yyscanner)
+
+YY_BUFFER_STATE _gmx_sel_yy_scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner );
+YY_BUFFER_STATE _gmx_sel_yy_scan_string (yyconst char *yy_str ,yyscan_t yyscanner );
+YY_BUFFER_STATE _gmx_sel_yy_scan_bytes (yyconst char *bytes,int len ,yyscan_t yyscanner );
+
+void *_gmx_sel_yyalloc (yy_size_t ,yyscan_t yyscanner );
+void *_gmx_sel_yyrealloc (void *,yy_size_t ,yyscan_t yyscanner );
+void _gmx_sel_yyfree (void * ,yyscan_t yyscanner );
+
+#define yy_new_buffer _gmx_sel_yy_create_buffer
+
+#define yy_set_interactive(is_interactive) \
+       { \
+       if ( ! YY_CURRENT_BUFFER ){ \
+        _gmx_sel_yyensure_buffer_stack (yyscanner); \
+               YY_CURRENT_BUFFER_LVALUE =    \
+            _gmx_sel_yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \
+       } \
+       YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
+       }
+
+#define yy_set_bol(at_bol) \
+       { \
+       if ( ! YY_CURRENT_BUFFER ){\
+        _gmx_sel_yyensure_buffer_stack (yyscanner); \
+               YY_CURRENT_BUFFER_LVALUE =    \
+            _gmx_sel_yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \
+       } \
+       YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
+       }
+
+#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
+
+#define _gmx_sel_yywrap(n) 1
+#define YY_SKIP_YYWRAP
+
+typedef unsigned char YY_CHAR;
+
+typedef int yy_state_type;
+
+#define yytext_ptr yytext_r
+
+static yy_state_type yy_get_previous_state (yyscan_t yyscanner );
+static yy_state_type yy_try_NUL_trans (yy_state_type current_state  ,yyscan_t yyscanner);
+static int yy_get_next_buffer (yyscan_t yyscanner );
+static void yy_fatal_error (yyconst char msg[] ,yyscan_t yyscanner );
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext.
+ */
+#define YY_DO_BEFORE_ACTION \
+       yyg->yytext_ptr = yy_bp; \
+       yyleng = (size_t) (yy_cp - yy_bp); \
+       yyg->yy_hold_char = *yy_cp; \
+       *yy_cp = '\0'; \
+       yyg->yy_c_buf_p = yy_cp;
+
+#define YY_NUM_RULES 26
+#define YY_END_OF_BUFFER 27
+/* This struct is not used in this scanner,
+   but its presence is necessary. */
+struct yy_trans_info
+       {
+       flex_int32_t yy_verify;
+       flex_int32_t yy_nxt;
+       };
+static yyconst flex_int16_t yy_accept[89] =
+    {   0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+       27,   25,   23,    6,   20,   25,    1,   25,   25,    2,
+        6,   21,   25,   22,   25,   24,   22,   22,   22,   22,
+       22,   22,   25,   22,   22,   22,   22,   22,   11,    8,
+       10,   10,    9,   23,   21,    0,    4,    0,    1,   17,
+        3,    3,    2,   24,   24,   22,    5,   22,   22,   22,
+       18,   15,   22,   18,   16,   13,   22,   12,   22,   22,
+        8,    9,    0,    0,    3,   17,   22,   20,   19,   13,
+       22,    0,    3,    3,   22,    7,   14,    0
+    } ;
+
+static yyconst flex_int32_t yy_ec[256] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    2,    3,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    2,    4,    5,    6,    1,    1,    7,    1,    1,
+        1,    1,    8,    1,    8,    9,    1,   10,   10,   10,
+       10,   10,   10,   10,   10,   10,   10,    1,   11,   12,
+       13,   12,    1,    1,   14,   14,   14,   14,   15,   14,
+       14,   14,   14,   14,   14,   14,   14,   14,   14,   14,
+       14,   14,   14,   14,   14,   14,   14,   14,   14,   14,
+        1,   16,    1,    1,   17,    1,   18,   14,   14,   19,
+
+       20,   21,   22,   23,   14,   14,   14,   24,   14,   25,
+       26,   27,   14,   28,   29,   30,   31,   14,   14,   32,
+       33,   14,    1,   34,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1
+    } ;
+
+static yyconst flex_int32_t yy_meta[35] =
+    {   0,
+        1,    1,    2,    1,    1,    1,    1,    1,    3,    4,
+        1,    1,    1,    4,    4,    1,    4,    4,    4,    4,
+        4,    4,    4,    4,    4,    4,    4,    4,    4,    4,
+        4,    4,    4,    1
+    } ;
+
+static yyconst flex_int16_t yy_base[94] =
+    {   0,
+        0,    0,  131,  130,   10,   12,  132,  131,   45,    0,
+      153,  158,  150,  158,  138,   75,    0,  143,  139,   72,
+      158,  135,  134,    0,  143,  136,  119,  115,  116,  113,
+      114,  113,  104,   62,  111,   68,  116,  115,  158,  132,
+      158,  158,    0,  131,  158,   79,  158,  127,    0,  158,
+       84,   87,   91,  122,   31,    0,  158,  111,  103,   98,
+        0,    0,   99,  158,    0,   96,  104,    0,   95,   99,
+      120,    0,   34,  107,   76,    0,   82,    0,    0,    0,
+       83,   99,   98,   95,   76,    0,    0,  158,  111,  115,
+      117,   94,   84
+
+    } ;
+
+static yyconst flex_int16_t yy_def[94] =
+    {   0,
+       88,    1,    1,    1,    1,    1,    1,    1,   88,    9,
+       88,   88,   88,   88,   88,   89,   90,   88,   88,   91,
+       88,   88,   88,   92,   88,   91,   92,   92,   92,   92,
+       92,   92,   88,   92,   92,   92,   92,   92,   88,   88,
+       88,   88,   93,   88,   88,   89,   88,   88,   90,   88,
+       88,   88,   91,   91,   91,   92,   88,   92,   92,   92,
+       92,   92,   92,   88,   92,   92,   92,   92,   92,   92,
+       88,   93,   88,   88,   91,   92,   92,   92,   92,   92,
+       92,   88,   88,   88,   92,   92,   92,    0,   88,   88,
+       88,   88,   88
+
+    } ;
+
+static yyconst flex_int16_t yy_nxt[193] =
+    {   0,
+       12,   13,   14,   15,   16,   17,   18,   12,   19,   20,
+       21,   22,   23,   24,   24,   25,   26,   27,   24,   24,
+       24,   28,   24,   24,   29,   30,   24,   24,   24,   31,
+       24,   32,   24,   33,   35,   36,   35,   36,   74,   88,
+       75,   82,   37,   83,   37,   39,   40,   41,   39,   39,
+       39,   39,   39,   39,   39,   42,   39,   39,   43,   43,
+       39,   39,   43,   43,   43,   43,   43,   43,   43,   43,
+       43,   43,   43,   43,   43,   43,   43,   43,   39,   47,
+       52,   53,   65,   47,   88,   75,   55,   72,   67,   61,
+       48,   55,   68,   51,   48,   61,   51,   56,   73,   52,
+
+       53,   73,   87,   73,   84,   55,   73,   83,   83,   86,
+       55,   46,   85,   46,   46,   49,   84,   49,   49,   54,
+       54,   71,   81,   68,   80,   78,   79,   78,   77,   76,
+       88,   46,   44,   71,   70,   69,   66,   64,   63,   62,
+       61,   60,   59,   58,   88,   57,   45,   45,   51,   50,
+       45,   44,   88,   38,   38,   34,   34,   11,   88,   88,
+       88,   88,   88,   88,   88,   88,   88,   88,   88,   88,
+       88,   88,   88,   88,   88,   88,   88,   88,   88,   88,
+       88,   88,   88,   88,   88,   88,   88,   88,   88,   88,
+       88,   88
+
+    } ;
+
+static yyconst flex_int16_t yy_chk[193] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    5,    5,    6,    6,   55,   55,
+       55,   73,    5,   73,    6,    9,    9,    9,    9,    9,
+        9,    9,    9,    9,    9,    9,    9,    9,    9,    9,
+        9,    9,    9,    9,    9,    9,    9,    9,    9,    9,
+        9,    9,    9,    9,    9,    9,    9,    9,    9,   16,
+       20,   20,   34,   46,   75,   75,   20,   93,   36,   34,
+       16,   20,   36,   51,   46,   36,   52,   92,   51,   53,
+
+       53,   52,   85,   51,   84,   53,   52,   83,   82,   81,
+       53,   89,   77,   89,   89,   90,   74,   90,   90,   91,
+       91,   71,   70,   69,   67,   66,   63,   60,   59,   58,
+       54,   48,   44,   40,   38,   37,   35,   33,   32,   31,
+       30,   29,   28,   27,   26,   25,   23,   22,   19,   18,
+       15,   13,   11,    8,    7,    4,    3,   88,   88,   88,
+       88,   88,   88,   88,   88,   88,   88,   88,   88,   88,
+       88,   88,   88,   88,   88,   88,   88,   88,   88,   88,
+       88,   88,   88,   88,   88,   88,   88,   88,   88,   88,
+       88,   88
+
+    } ;
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+#line 1 "scanner.l"
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \cond \internal \file scanner.l
+ * \brief
+ * Tokenizer for the selection language.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_selection
+ * \endcond
+ */
+/*! \internal \file scanner.cpp
+ * \brief
+ * Generated (from scanner.l by Flex) tokenizer for the selection language.
+ *
+ * \ingroup module_selection
+ */
+#line 46 "scanner.l"
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string2.h>
+
+#include "parser.h"
+#include "scanner.h"
+#include "scanner_internal.h"
+
+/* This macro is here to make the actions a bit shorter, since nearly every
+ * action needs this call. */
+#define ADD_TOKEN _gmx_sel_lexer_add_token(yytext, yyleng, state)
+
+#define YY_NO_UNISTD_H 1
+
+
+
+
+#line 576 "scanner.cpp"
+
+#define INITIAL 0
+#define matchof 1
+#define matchbool 2
+#define cmdstart 3
+#define help 4
+
+#ifndef YY_NO_UNISTD_H
+/* Special case for "unistd.h", since it is non-ANSI. We include it way
+ * down here because we want the user's section 1 to have been scanned first.
+ * The user has a chance to override it with an option.
+ */
+#include <unistd.h>
+#endif
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+/* Holds the entire state of the reentrant scanner. */
+struct yyguts_t
+    {
+
+    /* User-defined. Not touched by flex. */
+    YY_EXTRA_TYPE yyextra_r;
+
+    /* The rest are the same as the globals declared in the non-reentrant scanner. */
+    FILE *yyin_r, *yyout_r;
+    size_t yy_buffer_stack_top; /**< index of top of stack. */
+    size_t yy_buffer_stack_max; /**< capacity of stack. */
+    YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */
+    char yy_hold_char;
+    int yy_n_chars;
+    int yyleng_r;
+    char *yy_c_buf_p;
+    int yy_init;
+    int yy_start;
+    int yy_did_buffer_switch_on_eof;
+    int yy_start_stack_ptr;
+    int yy_start_stack_depth;
+    int *yy_start_stack;
+    yy_state_type yy_last_accepting_state;
+    char* yy_last_accepting_cpos;
+
+    int yylineno_r;
+    int yy_flex_debug_r;
+
+    char *yytext_r;
+    int yy_more_flag;
+    int yy_more_len;
+
+    }; /* end struct yyguts_t */
+
+static int yy_init_globals (yyscan_t yyscanner );
+
+int _gmx_sel_yylex_init (yyscan_t* scanner);
+
+int _gmx_sel_yylex_init_extra (YY_EXTRA_TYPE user_defined,yyscan_t* scanner);
+
+/* Accessor methods to globals.
+   These are made visible to non-reentrant scanners for convenience. */
+
+int _gmx_sel_yylex_destroy (yyscan_t yyscanner );
+
+int _gmx_sel_yyget_debug (yyscan_t yyscanner );
+
+void _gmx_sel_yyset_debug (int debug_flag ,yyscan_t yyscanner );
+
+YY_EXTRA_TYPE _gmx_sel_yyget_extra (yyscan_t yyscanner );
+
+void _gmx_sel_yyset_extra (YY_EXTRA_TYPE user_defined ,yyscan_t yyscanner );
+
+FILE *_gmx_sel_yyget_in (yyscan_t yyscanner );
+
+void _gmx_sel_yyset_in  (FILE * in_str ,yyscan_t yyscanner );
+
+FILE *_gmx_sel_yyget_out (yyscan_t yyscanner );
+
+void _gmx_sel_yyset_out  (FILE * out_str ,yyscan_t yyscanner );
+
+int _gmx_sel_yyget_leng (yyscan_t yyscanner );
+
+char *_gmx_sel_yyget_text (yyscan_t yyscanner );
+
+int _gmx_sel_yyget_lineno (yyscan_t yyscanner );
+
+void _gmx_sel_yyset_lineno (int line_number ,yyscan_t yyscanner );
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int _gmx_sel_yywrap (yyscan_t yyscanner );
+#else
+extern int _gmx_sel_yywrap (yyscan_t yyscanner );
+#endif
+#endif
+
+    static void yyunput (int c,char *buf_ptr  ,yyscan_t yyscanner);
+    
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char *,yyconst char *,int ,yyscan_t yyscanner);
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * ,yyscan_t yyscanner);
+#endif
+
+#ifndef YY_NO_INPUT
+
+#ifdef __cplusplus
+static int yyinput (yyscan_t yyscanner );
+#else
+static int input (yyscan_t yyscanner );
+#endif
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#ifdef __ia64__
+/* On IA-64, the buffer size is 16k, not 8k */
+#define YY_READ_BUF_SIZE 16384
+#else
+#define YY_READ_BUF_SIZE 8192
+#endif /* __ia64__ */
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO do { if (fwrite( yytext, yyleng, 1, yyout )) {} } while (0)
+#endif
+
+/* Gets input and stuffs it into "buf".  number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+       if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
+               { \
+               int c = '*'; \
+               size_t n; \
+               for ( n = 0; n < max_size && \
+                            (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
+                       buf[n] = (char) c; \
+               if ( c == '\n' ) \
+                       buf[n++] = (char) c; \
+               if ( c == EOF && ferror( yyin ) ) \
+                       YY_FATAL_ERROR( "input in flex scanner failed" ); \
+               result = n; \
+               } \
+       else \
+               { \
+               errno=0; \
+               while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \
+                       { \
+                       if( errno != EINTR) \
+                               { \
+                               YY_FATAL_ERROR( "input in flex scanner failed" ); \
+                               break; \
+                               } \
+                       errno=0; \
+                       clearerr(yyin); \
+                       } \
+               }\
+\
+
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg , yyscanner)
+#endif
+
+/* end tables serialization structures and prototypes */
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int _gmx_sel_yylex (yyscan_t yyscanner);
+
+#define YY_DECL int _gmx_sel_yylex (yyscan_t yyscanner)
+#endif /* !YY_DECL */
+
+/* Code executed at the beginning of each rule, after yytext and yyleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+#define YY_RULE_SETUP \
+       YY_USER_ACTION
+
+/** The main scanner function which does all the work.
+ */
+YY_DECL
+{
+       register yy_state_type yy_current_state;
+       register char *yy_cp, *yy_bp;
+       register int yy_act;
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+#line 85 "scanner.l"
+
+
+
+    gmx_sel_lexer_t *state = _gmx_sel_yyget_extra(yyscanner);
+    int              retval;
+    /* Return a token if one is pending */
+    retval = _gmx_sel_lexer_process_pending(yylval, state);
+    if (retval != 0)
+    {
+        return retval;
+    }
+    /* Handle the start conditions for 'of' matching */
+    if (state->bMatchOf)
+    {
+        BEGIN(matchof);
+        state->bMatchOf = FALSE;
+    }
+    else if (state->bMatchBool)
+    {
+        BEGIN(matchbool);
+        state->bMatchBool = FALSE;
+    }
+    else if (state->bCmdStart)
+    {
+        BEGIN(cmdstart);
+    }
+    else if (YYSTATE != help)
+    {
+        BEGIN(0);
+    }
+
+
+#line 839 "scanner.cpp"
+
+       if ( !yyg->yy_init )
+               {
+               yyg->yy_init = 1;
+
+#ifdef YY_USER_INIT
+               YY_USER_INIT;
+#endif
+
+               if ( ! yyg->yy_start )
+                       yyg->yy_start = 1;      /* first start state */
+
+               if ( ! yyin )
+                       yyin = stdin;
+
+               if ( ! yyout )
+                       yyout = stdout;
+
+               if ( ! YY_CURRENT_BUFFER ) {
+                       _gmx_sel_yyensure_buffer_stack (yyscanner);
+                       YY_CURRENT_BUFFER_LVALUE =
+                               _gmx_sel_yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner);
+               }
+
+               _gmx_sel_yy_load_buffer_state(yyscanner );
+               }
+
+       while ( 1 )             /* loops until end-of-file is reached */
+               {
+               yy_cp = yyg->yy_c_buf_p;
+
+               /* Support of yytext. */
+               *yy_cp = yyg->yy_hold_char;
+
+               /* yy_bp points to the position in yy_ch_buf of the start of
+                * the current run.
+                */
+               yy_bp = yy_cp;
+
+               yy_current_state = yyg->yy_start;
+yy_match:
+               do
+                       {
+                       register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
+                       if ( yy_accept[yy_current_state] )
+                               {
+                               yyg->yy_last_accepting_state = yy_current_state;
+                               yyg->yy_last_accepting_cpos = yy_cp;
+                               }
+                       while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+                               {
+                               yy_current_state = (int) yy_def[yy_current_state];
+                               if ( yy_current_state >= 89 )
+                                       yy_c = yy_meta[(unsigned int) yy_c];
+                               }
+                       yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+                       ++yy_cp;
+                       }
+               while ( yy_current_state != 88 );
+               yy_cp = yyg->yy_last_accepting_cpos;
+               yy_current_state = yyg->yy_last_accepting_state;
+
+yy_find_action:
+               yy_act = yy_accept[yy_current_state];
+
+               YY_DO_BEFORE_ACTION;
+
+do_action:     /* This label is used only to access EOF actions. */
+
+               switch ( yy_act )
+       { /* beginning of action switch */
+                       case 0: /* must back up */
+                       /* undo the effects of YY_DO_BEFORE_ACTION */
+                       *yy_cp = yyg->yy_hold_char;
+                       yy_cp = yyg->yy_last_accepting_cpos;
+                       yy_current_state = yyg->yy_last_accepting_state;
+                       goto yy_find_action;
+
+case 1:
+YY_RULE_SETUP
+#line 117 "scanner.l"
+
+       YY_BREAK
+case 2:
+YY_RULE_SETUP
+#line 118 "scanner.l"
+{ yylval->i   = strtol(yytext, NULL, 10);    ADD_TOKEN; return TOK_INT; }
+       YY_BREAK
+case 3:
+YY_RULE_SETUP
+#line 119 "scanner.l"
+{ yylval->r   = strtod(yytext, NULL);        ADD_TOKEN; return TOK_REAL; }
+       YY_BREAK
+case 4:
+YY_RULE_SETUP
+#line 120 "scanner.l"
+{ yylval->str = gmx_strndup(yytext+1, yyleng-2); ADD_TOKEN; return STR;  }
+       YY_BREAK
+case 5:
+/* rule 5 can match eol */
+YY_RULE_SETUP
+#line 122 "scanner.l"
+{ _gmx_sel_lexer_add_token(" ", 1, state); }
+       YY_BREAK
+case 6:
+/* rule 6 can match eol */
+YY_RULE_SETUP
+#line 123 "scanner.l"
+{
+                    if (yytext[0] == ';' || state->bInteractive)
+                    {
+                        rtrim(state->pselstr);
+                        return CMD_SEP;
+                    }
+                    else
+                    {
+                        _gmx_sel_lexer_add_token(" ", 1, state);
+                    }
+                }
+       YY_BREAK
+case 7:
+YY_RULE_SETUP
+#line 135 "scanner.l"
+{ BEGIN(help); return HELP; }
+       YY_BREAK
+
+case 8:
+YY_RULE_SETUP
+#line 137 "scanner.l"
+
+       YY_BREAK
+case 9:
+YY_RULE_SETUP
+#line 138 "scanner.l"
+{ yylval->str = gmx_strndup(yytext, yyleng); return HELP_TOPIC; }
+       YY_BREAK
+case 10:
+/* rule 10 can match eol */
+YY_RULE_SETUP
+#line 139 "scanner.l"
+{ return CMD_SEP; }
+       YY_BREAK
+case 11:
+YY_RULE_SETUP
+#line 140 "scanner.l"
+{ return INVALID; }
+       YY_BREAK
+
+
+case 12:
+YY_RULE_SETUP
+#line 144 "scanner.l"
+{ ADD_TOKEN; yylval->i = 1; return TOK_INT; }
+       YY_BREAK
+case 13:
+YY_RULE_SETUP
+#line 145 "scanner.l"
+{ ADD_TOKEN; yylval->i = 0; return TOK_INT; }
+       YY_BREAK
+
+case 14:
+YY_RULE_SETUP
+#line 147 "scanner.l"
+{ ADD_TOKEN; return GROUP; }
+       YY_BREAK
+case 15:
+YY_RULE_SETUP
+#line 148 "scanner.l"
+{ ADD_TOKEN; return TO; }
+       YY_BREAK
+case 16:
+YY_RULE_SETUP
+#line 149 "scanner.l"
+{ ADD_TOKEN; BEGIN(0); return OF; }
+       YY_BREAK
+case 17:
+YY_RULE_SETUP
+#line 150 "scanner.l"
+{ ADD_TOKEN; return AND; }
+       YY_BREAK
+case 18:
+YY_RULE_SETUP
+#line 151 "scanner.l"
+{ ADD_TOKEN; return OR; }
+       YY_BREAK
+case 19:
+YY_RULE_SETUP
+#line 152 "scanner.l"
+{ ADD_TOKEN; return XOR; }
+       YY_BREAK
+case 20:
+YY_RULE_SETUP
+#line 153 "scanner.l"
+{ ADD_TOKEN; return NOT; }
+       YY_BREAK
+case 21:
+YY_RULE_SETUP
+#line 154 "scanner.l"
+{ yylval->str = gmx_strndup(yytext, yyleng); ADD_TOKEN; return CMP_OP; }
+       YY_BREAK
+case 22:
+YY_RULE_SETUP
+#line 156 "scanner.l"
+{ return _gmx_sel_lexer_process_identifier(yylval, yytext, yyleng, state); }
+       YY_BREAK
+case 23:
+YY_RULE_SETUP
+#line 158 "scanner.l"
+{ _gmx_sel_lexer_add_token(" ", 1, state); }
+       YY_BREAK
+case 24:
+YY_RULE_SETUP
+#line 159 "scanner.l"
+{ yylval->str = gmx_strndup(yytext, yyleng); ADD_TOKEN; return STR; }
+       YY_BREAK
+case 25:
+YY_RULE_SETUP
+#line 160 "scanner.l"
+{ ADD_TOKEN; return yytext[0]; }
+       YY_BREAK
+case 26:
+YY_RULE_SETUP
+#line 161 "scanner.l"
+YY_FATAL_ERROR( "flex scanner jammed" );
+       YY_BREAK
+#line 1065 "scanner.cpp"
+case YY_STATE_EOF(INITIAL):
+case YY_STATE_EOF(matchof):
+case YY_STATE_EOF(matchbool):
+case YY_STATE_EOF(cmdstart):
+case YY_STATE_EOF(help):
+       yyterminate();
+
+       case YY_END_OF_BUFFER:
+               {
+               /* Amount of text matched not including the EOB char. */
+               int yy_amount_of_matched_text = (int) (yy_cp - yyg->yytext_ptr) - 1;
+
+               /* Undo the effects of YY_DO_BEFORE_ACTION. */
+               *yy_cp = yyg->yy_hold_char;
+               YY_RESTORE_YY_MORE_OFFSET
+
+               if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
+                       {
+                       /* We're scanning a new file or input source.  It's
+                        * possible that this happened because the user
+                        * just pointed yyin at a new source and called
+                        * _gmx_sel_yylex().  If so, then we have to assure
+                        * consistency between YY_CURRENT_BUFFER and our
+                        * globals.  Here is the right place to do so, because
+                        * this is the first action (other than possibly a
+                        * back-up) that will match for the new input source.
+                        */
+                       yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+                       YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin;
+                       YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
+                       }
+
+               /* Note that here we test for yy_c_buf_p "<=" to the position
+                * of the first EOB in the buffer, since yy_c_buf_p will
+                * already have been incremented past the NUL character
+                * (since all states make transitions on EOB to the
+                * end-of-buffer state).  Contrast this with the test
+                * in input().
+                */
+               if ( yyg->yy_c_buf_p <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] )
+                       { /* This was really a NUL. */
+                       yy_state_type yy_next_state;
+
+                       yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text;
+
+                       yy_current_state = yy_get_previous_state( yyscanner );
+
+                       /* Okay, we're now positioned to make the NUL
+                        * transition.  We couldn't have
+                        * yy_get_previous_state() go ahead and do it
+                        * for us because it doesn't know how to deal
+                        * with the possibility of jamming (and we don't
+                        * want to build jamming into it because then it
+                        * will run more slowly).
+                        */
+
+                       yy_next_state = yy_try_NUL_trans( yy_current_state , yyscanner);
+
+                       yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+
+                       if ( yy_next_state )
+                               {
+                               /* Consume the NUL. */
+                               yy_cp = ++yyg->yy_c_buf_p;
+                               yy_current_state = yy_next_state;
+                               goto yy_match;
+                               }
+
+                       else
+                               {
+                               yy_cp = yyg->yy_last_accepting_cpos;
+                               yy_current_state = yyg->yy_last_accepting_state;
+                               goto yy_find_action;
+                               }
+                       }
+
+               else switch ( yy_get_next_buffer( yyscanner ) )
+                       {
+                       case EOB_ACT_END_OF_FILE:
+                               {
+                               yyg->yy_did_buffer_switch_on_eof = 0;
+
+                               if ( _gmx_sel_yywrap(yyscanner ) )
+                                       {
+                                       /* Note: because we've taken care in
+                                        * yy_get_next_buffer() to have set up
+                                        * yytext, we can now set up
+                                        * yy_c_buf_p so that if some total
+                                        * hoser (like flex itself) wants to
+                                        * call the scanner after we return the
+                                        * YY_NULL, it'll still work - another
+                                        * YY_NULL will get returned.
+                                        */
+                                       yyg->yy_c_buf_p = yyg->yytext_ptr + YY_MORE_ADJ;
+
+                                       yy_act = YY_STATE_EOF(YY_START);
+                                       goto do_action;
+                                       }
+
+                               else
+                                       {
+                                       if ( ! yyg->yy_did_buffer_switch_on_eof )
+                                               YY_NEW_FILE;
+                                       }
+                               break;
+                               }
+
+                       case EOB_ACT_CONTINUE_SCAN:
+                               yyg->yy_c_buf_p =
+                                       yyg->yytext_ptr + yy_amount_of_matched_text;
+
+                               yy_current_state = yy_get_previous_state( yyscanner );
+
+                               yy_cp = yyg->yy_c_buf_p;
+                               yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+                               goto yy_match;
+
+                       case EOB_ACT_LAST_MATCH:
+                               yyg->yy_c_buf_p =
+                               &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars];
+
+                               yy_current_state = yy_get_previous_state( yyscanner );
+
+                               yy_cp = yyg->yy_c_buf_p;
+                               yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+                               goto yy_find_action;
+                       }
+               break;
+               }
+
+       default:
+               YY_FATAL_ERROR(
+                       "fatal flex scanner internal error--no action found" );
+       } /* end of action switch */
+               } /* end of scanning one token */
+} /* end of _gmx_sel_yylex */
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ *     EOB_ACT_LAST_MATCH -
+ *     EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ *     EOB_ACT_END_OF_FILE - end of file
+ */
+static int yy_get_next_buffer (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+       register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
+       register char *source = yyg->yytext_ptr;
+       register int number_to_move, i;
+       int ret_val;
+
+       if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] )
+               YY_FATAL_ERROR(
+               "fatal flex scanner internal error--end of buffer missed" );
+
+       if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
+               { /* Don't try to fill the buffer, so this is an EOF. */
+               if ( yyg->yy_c_buf_p - yyg->yytext_ptr - YY_MORE_ADJ == 1 )
+                       {
+                       /* We matched a single character, the EOB, so
+                        * treat this as a final EOF.
+                        */
+                       return EOB_ACT_END_OF_FILE;
+                       }
+
+               else
+                       {
+                       /* We matched some text prior to the EOB, first
+                        * process it.
+                        */
+                       return EOB_ACT_LAST_MATCH;
+                       }
+               }
+
+       /* Try to read more data. */
+
+       /* First move last chars to start of buffer. */
+       number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr) - 1;
+
+       for ( i = 0; i < number_to_move; ++i )
+               *(dest++) = *(source++);
+
+       if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+               /* don't do the read, it's not guaranteed to return an EOF,
+                * just force an EOF
+                */
+               YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars = 0;
+
+       else
+               {
+                       int num_to_read =
+                       YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+
+               while ( num_to_read <= 0 )
+                       { /* Not enough room in the buffer - grow it. */
+
+                       /* just a shorter name for the current buffer */
+                       YY_BUFFER_STATE b = YY_CURRENT_BUFFER;
+
+                       int yy_c_buf_p_offset =
+                               (int) (yyg->yy_c_buf_p - b->yy_ch_buf);
+
+                       if ( b->yy_is_our_buffer )
+                               {
+                               int new_size = b->yy_buf_size * 2;
+
+                               if ( new_size <= 0 )
+                                       b->yy_buf_size += b->yy_buf_size / 8;
+                               else
+                                       b->yy_buf_size *= 2;
+
+                               b->yy_ch_buf = (char *)
+                                       /* Include room in for 2 EOB chars. */
+                                       _gmx_sel_yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ,yyscanner );
+                               }
+                       else
+                               /* Can't grow it, we don't own it. */
+                               b->yy_ch_buf = 0;
+
+                       if ( ! b->yy_ch_buf )
+                               YY_FATAL_ERROR(
+                               "fatal error - scanner input buffer overflow" );
+
+                       yyg->yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+                       num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
+                                               number_to_move - 1;
+
+                       }
+
+               if ( num_to_read > YY_READ_BUF_SIZE )
+                       num_to_read = YY_READ_BUF_SIZE;
+
+               /* Read in more data. */
+               YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
+                       yyg->yy_n_chars, (size_t) num_to_read );
+
+               YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+               }
+
+       if ( yyg->yy_n_chars == 0 )
+               {
+               if ( number_to_move == YY_MORE_ADJ )
+                       {
+                       ret_val = EOB_ACT_END_OF_FILE;
+                       _gmx_sel_yyrestart(yyin  ,yyscanner);
+                       }
+
+               else
+                       {
+                       ret_val = EOB_ACT_LAST_MATCH;
+                       YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
+                               YY_BUFFER_EOF_PENDING;
+                       }
+               }
+
+       else
+               ret_val = EOB_ACT_CONTINUE_SCAN;
+
+       if ((yy_size_t) (yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
+               /* Extend the array by 50%, plus the number we really need. */
+               yy_size_t new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1);
+               YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) _gmx_sel_yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ,yyscanner );
+               if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+                       YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
+       }
+
+       yyg->yy_n_chars += number_to_move;
+       YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] = YY_END_OF_BUFFER_CHAR;
+       YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR;
+
+       yyg->yytext_ptr = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
+
+       return ret_val;
+}
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+    static yy_state_type yy_get_previous_state (yyscan_t yyscanner)
+{
+       register yy_state_type yy_current_state;
+       register char *yy_cp;
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+       yy_current_state = yyg->yy_start;
+
+       for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp )
+               {
+               register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+               if ( yy_accept[yy_current_state] )
+                       {
+                       yyg->yy_last_accepting_state = yy_current_state;
+                       yyg->yy_last_accepting_cpos = yy_cp;
+                       }
+               while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+                       {
+                       yy_current_state = (int) yy_def[yy_current_state];
+                       if ( yy_current_state >= 89 )
+                               yy_c = yy_meta[(unsigned int) yy_c];
+                       }
+               yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+               }
+
+       return yy_current_state;
+}
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ *     next_state = yy_try_NUL_trans( current_state );
+ */
+    static yy_state_type yy_try_NUL_trans  (yy_state_type yy_current_state , yyscan_t yyscanner)
+{
+       register int yy_is_jam;
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */
+       register char *yy_cp = yyg->yy_c_buf_p;
+
+       register YY_CHAR yy_c = 1;
+       if ( yy_accept[yy_current_state] )
+               {
+               yyg->yy_last_accepting_state = yy_current_state;
+               yyg->yy_last_accepting_cpos = yy_cp;
+               }
+       while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+               {
+               yy_current_state = (int) yy_def[yy_current_state];
+               if ( yy_current_state >= 89 )
+                       yy_c = yy_meta[(unsigned int) yy_c];
+               }
+       yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+       yy_is_jam = (yy_current_state == 88);
+
+       return yy_is_jam ? 0 : yy_current_state;
+}
+
+    static void yyunput (int c, register char * yy_bp , yyscan_t yyscanner)
+{
+       register char *yy_cp;
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+    yy_cp = yyg->yy_c_buf_p;
+
+       /* undo effects of setting up yytext */
+       *yy_cp = yyg->yy_hold_char;
+
+       if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
+               { /* need to shift things up to make room */
+               /* +2 for EOB chars. */
+               register int number_to_move = yyg->yy_n_chars + 2;
+               register char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[
+                                       YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2];
+               register char *source =
+                               &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move];
+
+               while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+                       *--dest = *--source;
+
+               yy_cp += (int) (dest - source);
+               yy_bp += (int) (dest - source);
+               YY_CURRENT_BUFFER_LVALUE->yy_n_chars =
+                       yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_buf_size;
+
+               if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
+                       YY_FATAL_ERROR( "flex scanner push-back overflow" );
+               }
+
+       *--yy_cp = (char) c;
+
+       yyg->yytext_ptr = yy_bp;
+       yyg->yy_hold_char = *yy_cp;
+       yyg->yy_c_buf_p = yy_cp;
+}
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+    static int yyinput (yyscan_t yyscanner)
+#else
+    static int input  (yyscan_t yyscanner)
+#endif
+
+{
+       int c;
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+       *yyg->yy_c_buf_p = yyg->yy_hold_char;
+
+       if ( *yyg->yy_c_buf_p == YY_END_OF_BUFFER_CHAR )
+               {
+               /* yy_c_buf_p now points to the character we want to return.
+                * If this occurs *before* the EOB characters, then it's a
+                * valid NUL; if not, then we've hit the end of the buffer.
+                */
+               if ( yyg->yy_c_buf_p < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] )
+                       /* This was really a NUL. */
+                       *yyg->yy_c_buf_p = '\0';
+
+               else
+                       { /* need more input */
+                       int offset = yyg->yy_c_buf_p - yyg->yytext_ptr;
+                       ++yyg->yy_c_buf_p;
+
+                       switch ( yy_get_next_buffer( yyscanner ) )
+                               {
+                               case EOB_ACT_LAST_MATCH:
+                                       /* This happens because yy_g_n_b()
+                                        * sees that we've accumulated a
+                                        * token and flags that we need to
+                                        * try matching the token before
+                                        * proceeding.  But for input(),
+                                        * there's no matching to consider.
+                                        * So convert the EOB_ACT_LAST_MATCH
+                                        * to EOB_ACT_END_OF_FILE.
+                                        */
+
+                                       /* Reset buffer status. */
+                                       _gmx_sel_yyrestart(yyin ,yyscanner);
+
+                                       /*FALLTHROUGH*/
+
+                               case EOB_ACT_END_OF_FILE:
+                                       {
+                                       if ( _gmx_sel_yywrap(yyscanner ) )
+                                               return EOF;
+
+                                       if ( ! yyg->yy_did_buffer_switch_on_eof )
+                                               YY_NEW_FILE;
+#ifdef __cplusplus
+                                       return yyinput(yyscanner);
+#else
+                                       return input(yyscanner);
+#endif
+                                       }
+
+                               case EOB_ACT_CONTINUE_SCAN:
+                                       yyg->yy_c_buf_p = yyg->yytext_ptr + offset;
+                                       break;
+                               }
+                       }
+               }
+
+       c = *(unsigned char *) yyg->yy_c_buf_p; /* cast for 8-bit char's */
+       *yyg->yy_c_buf_p = '\0';        /* preserve yytext */
+       yyg->yy_hold_char = *++yyg->yy_c_buf_p;
+
+       return c;
+}
+#endif /* ifndef YY_NO_INPUT */
+
+/** Immediately switch to a different input stream.
+ * @param input_file A readable stream.
+ * @param yyscanner The scanner object.
+ * @note This function does not reset the start condition to @c INITIAL .
+ */
+    void _gmx_sel_yyrestart  (FILE * input_file , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+       if ( ! YY_CURRENT_BUFFER ){
+        _gmx_sel_yyensure_buffer_stack (yyscanner);
+               YY_CURRENT_BUFFER_LVALUE =
+            _gmx_sel_yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner);
+       }
+
+       _gmx_sel_yy_init_buffer(YY_CURRENT_BUFFER,input_file ,yyscanner);
+       _gmx_sel_yy_load_buffer_state(yyscanner );
+}
+
+/** Switch to a different input buffer.
+ * @param new_buffer The new input buffer.
+ * @param yyscanner The scanner object.
+ */
+    void _gmx_sel_yy_switch_to_buffer  (YY_BUFFER_STATE  new_buffer , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+       /* TODO. We should be able to replace this entire function body
+        * with
+        *              _gmx_sel_yypop_buffer_state();
+        *              _gmx_sel_yypush_buffer_state(new_buffer);
+     */
+       _gmx_sel_yyensure_buffer_stack (yyscanner);
+       if ( YY_CURRENT_BUFFER == new_buffer )
+               return;
+
+       if ( YY_CURRENT_BUFFER )
+               {
+               /* Flush out information for old buffer. */
+               *yyg->yy_c_buf_p = yyg->yy_hold_char;
+               YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p;
+               YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+               }
+
+       YY_CURRENT_BUFFER_LVALUE = new_buffer;
+       _gmx_sel_yy_load_buffer_state(yyscanner );
+
+       /* We don't actually know whether we did this switch during
+        * EOF (_gmx_sel_yywrap()) processing, but the only time this flag
+        * is looked at is after _gmx_sel_yywrap() is called, so it's safe
+        * to go ahead and always set it.
+        */
+       yyg->yy_did_buffer_switch_on_eof = 1;
+}
+
+static void _gmx_sel_yy_load_buffer_state  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+       yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+       yyg->yytext_ptr = yyg->yy_c_buf_p = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
+       yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
+       yyg->yy_hold_char = *yyg->yy_c_buf_p;
+}
+
+/** Allocate and initialize an input buffer state.
+ * @param file A readable stream.
+ * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
+ * @param yyscanner The scanner object.
+ * @return the allocated buffer state.
+ */
+    YY_BUFFER_STATE _gmx_sel_yy_create_buffer  (FILE * file, int  size , yyscan_t yyscanner)
+{
+       YY_BUFFER_STATE b;
+    
+       b = (YY_BUFFER_STATE) _gmx_sel_yyalloc(sizeof( struct yy_buffer_state ) ,yyscanner );
+       if ( ! b )
+               YY_FATAL_ERROR( "out of dynamic memory in _gmx_sel_yy_create_buffer()" );
+
+       b->yy_buf_size = size;
+
+       /* yy_ch_buf has to be 2 characters longer than the size given because
+        * we need to put in 2 end-of-buffer characters.
+        */
+       b->yy_ch_buf = (char *) _gmx_sel_yyalloc(b->yy_buf_size + 2 ,yyscanner );
+       if ( ! b->yy_ch_buf )
+               YY_FATAL_ERROR( "out of dynamic memory in _gmx_sel_yy_create_buffer()" );
+
+       b->yy_is_our_buffer = 1;
+
+       _gmx_sel_yy_init_buffer(b,file ,yyscanner);
+
+       return b;
+}
+
+/** Destroy the buffer.
+ * @param b a buffer created with _gmx_sel_yy_create_buffer()
+ * @param yyscanner The scanner object.
+ */
+    void _gmx_sel_yy_delete_buffer (YY_BUFFER_STATE  b , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+       if ( ! b )
+               return;
+
+       if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
+               YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
+
+       if ( b->yy_is_our_buffer )
+               _gmx_sel_yyfree((void *) b->yy_ch_buf ,yyscanner );
+
+       _gmx_sel_yyfree((void *) b ,yyscanner );
+}
+
+/* Initializes or reinitializes a buffer.
+ * This function is sometimes called more than once on the same buffer,
+ * such as during a _gmx_sel_yyrestart() or at EOF.
+ */
+    static void _gmx_sel_yy_init_buffer  (YY_BUFFER_STATE  b, FILE * file , yyscan_t yyscanner)
+
+{
+       int oerrno = errno;
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+       _gmx_sel_yy_flush_buffer(b ,yyscanner);
+
+       b->yy_input_file = file;
+       b->yy_fill_buffer = 1;
+
+    /* If b is the current buffer, then _gmx_sel_yy_init_buffer was _probably_
+     * called from _gmx_sel_yyrestart() or through yy_get_next_buffer.
+     * In that case, we don't want to reset the lineno or column.
+     */
+    if (b != YY_CURRENT_BUFFER){
+        b->yy_bs_lineno = 1;
+        b->yy_bs_column = 0;
+    }
+
+        b->yy_is_interactive = 0;
+    
+       errno = oerrno;
+}
+
+/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
+ * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
+ * @param yyscanner The scanner object.
+ */
+    void _gmx_sel_yy_flush_buffer (YY_BUFFER_STATE  b , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+       if ( ! b )
+               return;
+
+       b->yy_n_chars = 0;
+
+       /* We always need two end-of-buffer characters.  The first causes
+        * a transition to the end-of-buffer state.  The second causes
+        * a jam in that state.
+        */
+       b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+       b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+       b->yy_buf_pos = &b->yy_ch_buf[0];
+
+       b->yy_at_bol = 1;
+       b->yy_buffer_status = YY_BUFFER_NEW;
+
+       if ( b == YY_CURRENT_BUFFER )
+               _gmx_sel_yy_load_buffer_state(yyscanner );
+}
+
+/** Pushes the new state onto the stack. The new state becomes
+ *  the current state. This function will allocate the stack
+ *  if necessary.
+ *  @param new_buffer The new state.
+ *  @param yyscanner The scanner object.
+ */
+void _gmx_sel_yypush_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+       if (new_buffer == NULL)
+               return;
+
+       _gmx_sel_yyensure_buffer_stack(yyscanner);
+
+       /* This block is copied from _gmx_sel_yy_switch_to_buffer. */
+       if ( YY_CURRENT_BUFFER )
+               {
+               /* Flush out information for old buffer. */
+               *yyg->yy_c_buf_p = yyg->yy_hold_char;
+               YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p;
+               YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+               }
+
+       /* Only push if top exists. Otherwise, replace top. */
+       if (YY_CURRENT_BUFFER)
+               yyg->yy_buffer_stack_top++;
+       YY_CURRENT_BUFFER_LVALUE = new_buffer;
+
+       /* copied from _gmx_sel_yy_switch_to_buffer. */
+       _gmx_sel_yy_load_buffer_state(yyscanner );
+       yyg->yy_did_buffer_switch_on_eof = 1;
+}
+
+/** Removes and deletes the top of the stack, if present.
+ *  The next element becomes the new top.
+ *  @param yyscanner The scanner object.
+ */
+void _gmx_sel_yypop_buffer_state (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+       if (!YY_CURRENT_BUFFER)
+               return;
+
+       _gmx_sel_yy_delete_buffer(YY_CURRENT_BUFFER ,yyscanner);
+       YY_CURRENT_BUFFER_LVALUE = NULL;
+       if (yyg->yy_buffer_stack_top > 0)
+               --yyg->yy_buffer_stack_top;
+
+       if (YY_CURRENT_BUFFER) {
+               _gmx_sel_yy_load_buffer_state(yyscanner );
+               yyg->yy_did_buffer_switch_on_eof = 1;
+       }
+}
+
+/* Allocates the stack if it does not exist.
+ *  Guarantees space for at least one push.
+ */
+static void _gmx_sel_yyensure_buffer_stack (yyscan_t yyscanner)
+{
+       int num_to_alloc;
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+       if (!yyg->yy_buffer_stack) {
+
+               /* First allocation is just for 2 elements, since we don't know if this
+                * scanner will even need a stack. We use 2 instead of 1 to avoid an
+                * immediate realloc on the next call.
+         */
+               num_to_alloc = 1;
+               yyg->yy_buffer_stack = (struct yy_buffer_state**)_gmx_sel_yyalloc
+                                                               (num_to_alloc * sizeof(struct yy_buffer_state*)
+                                                               , yyscanner);
+               if ( ! yyg->yy_buffer_stack )
+                       YY_FATAL_ERROR( "out of dynamic memory in _gmx_sel_yyensure_buffer_stack()" );
+                                                                 
+               memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*));
+                               
+               yyg->yy_buffer_stack_max = num_to_alloc;
+               yyg->yy_buffer_stack_top = 0;
+               return;
+       }
+
+       if (yyg->yy_buffer_stack_top >= (yyg->yy_buffer_stack_max) - 1){
+
+               /* Increase the buffer to prepare for a possible push. */
+               int grow_size = 8 /* arbitrary grow size */;
+
+               num_to_alloc = yyg->yy_buffer_stack_max + grow_size;
+               yyg->yy_buffer_stack = (struct yy_buffer_state**)_gmx_sel_yyrealloc
+                                                               (yyg->yy_buffer_stack,
+                                                               num_to_alloc * sizeof(struct yy_buffer_state*)
+                                                               , yyscanner);
+               if ( ! yyg->yy_buffer_stack )
+                       YY_FATAL_ERROR( "out of dynamic memory in _gmx_sel_yyensure_buffer_stack()" );
+
+               /* zero only the new slots.*/
+               memset(yyg->yy_buffer_stack + yyg->yy_buffer_stack_max, 0, grow_size * sizeof(struct yy_buffer_state*));
+               yyg->yy_buffer_stack_max = num_to_alloc;
+       }
+}
+
+/** Setup the input buffer state to scan directly from a user-specified character buffer.
+ * @param base the character buffer
+ * @param size the size in bytes of the character buffer
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object. 
+ */
+YY_BUFFER_STATE _gmx_sel_yy_scan_buffer  (char * base, yy_size_t  size , yyscan_t yyscanner)
+{
+       YY_BUFFER_STATE b;
+    
+       if ( size < 2 ||
+            base[size-2] != YY_END_OF_BUFFER_CHAR ||
+            base[size-1] != YY_END_OF_BUFFER_CHAR )
+               /* They forgot to leave room for the EOB's. */
+               return 0;
+
+       b = (YY_BUFFER_STATE) _gmx_sel_yyalloc(sizeof( struct yy_buffer_state ) ,yyscanner );
+       if ( ! b )
+               YY_FATAL_ERROR( "out of dynamic memory in _gmx_sel_yy_scan_buffer()" );
+
+       b->yy_buf_size = size - 2;      /* "- 2" to take care of EOB's */
+       b->yy_buf_pos = b->yy_ch_buf = base;
+       b->yy_is_our_buffer = 0;
+       b->yy_input_file = 0;
+       b->yy_n_chars = b->yy_buf_size;
+       b->yy_is_interactive = 0;
+       b->yy_at_bol = 1;
+       b->yy_fill_buffer = 0;
+       b->yy_buffer_status = YY_BUFFER_NEW;
+
+       _gmx_sel_yy_switch_to_buffer(b ,yyscanner );
+
+       return b;
+}
+
+/** Setup the input buffer state to scan a string. The next call to _gmx_sel_yylex() will
+ * scan from a @e copy of @a str.
+ * @param yystr a NUL-terminated string to scan
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ * @note If you want to scan bytes that may contain NUL values, then use
+ *       _gmx_sel_yy_scan_bytes() instead.
+ */
+YY_BUFFER_STATE _gmx_sel_yy_scan_string (yyconst char * yystr , yyscan_t yyscanner)
+{
+    
+       return _gmx_sel_yy_scan_bytes(yystr,strlen(yystr) ,yyscanner);
+}
+
+/** Setup the input buffer state to scan the given bytes. The next call to _gmx_sel_yylex() will
+ * scan from a @e copy of @a bytes.
+ * @param yybytes the byte buffer to scan
+ * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes.
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE _gmx_sel_yy_scan_bytes  (yyconst char * yybytes, int  _yybytes_len , yyscan_t yyscanner)
+{
+       YY_BUFFER_STATE b;
+       char *buf;
+       yy_size_t n;
+       int i;
+    
+       /* Get memory for full buffer, including space for trailing EOB's. */
+       n = _yybytes_len + 2;
+       buf = (char *) _gmx_sel_yyalloc(n ,yyscanner );
+       if ( ! buf )
+               YY_FATAL_ERROR( "out of dynamic memory in _gmx_sel_yy_scan_bytes()" );
+
+       for ( i = 0; i < _yybytes_len; ++i )
+               buf[i] = yybytes[i];
+
+       buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
+
+       b = _gmx_sel_yy_scan_buffer(buf,n ,yyscanner);
+       if ( ! b )
+               YY_FATAL_ERROR( "bad buffer in _gmx_sel_yy_scan_bytes()" );
+
+       /* It's okay to grow etc. this buffer, and we should throw it
+        * away when we're done.
+        */
+       b->yy_is_our_buffer = 1;
+
+       return b;
+}
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+static void yy_fatal_error (yyconst char* msg , yyscan_t yyscanner)
+{
+       (void) fprintf( stderr, "%s\n", msg );
+       exit( YY_EXIT_FAILURE );
+}
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+       do \
+               { \
+               /* Undo effects of setting up yytext. */ \
+        int yyless_macro_arg = (n); \
+        YY_LESS_LINENO(yyless_macro_arg);\
+               yytext[yyleng] = yyg->yy_hold_char; \
+               yyg->yy_c_buf_p = yytext + yyless_macro_arg; \
+               yyg->yy_hold_char = *yyg->yy_c_buf_p; \
+               *yyg->yy_c_buf_p = '\0'; \
+               yyleng = yyless_macro_arg; \
+               } \
+       while ( 0 )
+
+/* Accessor  methods (get/set functions) to struct members. */
+
+/** Get the user-defined data for this scanner.
+ * @param yyscanner The scanner object.
+ */
+YY_EXTRA_TYPE _gmx_sel_yyget_extra  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    return yyextra;
+}
+
+/** Get the current line number.
+ * @param yyscanner The scanner object.
+ */
+int _gmx_sel_yyget_lineno  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    
+        if (! YY_CURRENT_BUFFER)
+            return 0;
+    
+    return yylineno;
+}
+
+/** Get the current column number.
+ * @param yyscanner The scanner object.
+ */
+int _gmx_sel_yyget_column  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    
+        if (! YY_CURRENT_BUFFER)
+            return 0;
+    
+    return yycolumn;
+}
+
+/** Get the input stream.
+ * @param yyscanner The scanner object.
+ */
+FILE *_gmx_sel_yyget_in  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    return yyin;
+}
+
+/** Get the output stream.
+ * @param yyscanner The scanner object.
+ */
+FILE *_gmx_sel_yyget_out  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    return yyout;
+}
+
+/** Get the length of the current token.
+ * @param yyscanner The scanner object.
+ */
+int _gmx_sel_yyget_leng  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    return yyleng;
+}
+
+/** Get the current token.
+ * @param yyscanner The scanner object.
+ */
+
+char *_gmx_sel_yyget_text  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    return yytext;
+}
+
+/** Set the user-defined data. This data is never touched by the scanner.
+ * @param user_defined The data to be associated with this scanner.
+ * @param yyscanner The scanner object.
+ */
+void _gmx_sel_yyset_extra (YY_EXTRA_TYPE  user_defined , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    yyextra = user_defined ;
+}
+
+/** Set the current line number.
+ * @param line_number
+ * @param yyscanner The scanner object.
+ */
+void _gmx_sel_yyset_lineno (int  line_number , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+        /* lineno is only valid if an input buffer exists. */
+        if (! YY_CURRENT_BUFFER )
+           yy_fatal_error( "_gmx_sel_yyset_lineno called with no buffer" , yyscanner); 
+    
+    yylineno = line_number;
+}
+
+/** Set the current column.
+ * @param line_number
+ * @param yyscanner The scanner object.
+ */
+void _gmx_sel_yyset_column (int  column_no , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+        /* column is only valid if an input buffer exists. */
+        if (! YY_CURRENT_BUFFER )
+           yy_fatal_error( "_gmx_sel_yyset_column called with no buffer" , yyscanner); 
+    
+    yycolumn = column_no;
+}
+
+/** Set the input stream. This does not discard the current
+ * input buffer.
+ * @param in_str A readable stream.
+ * @param yyscanner The scanner object.
+ * @see _gmx_sel_yy_switch_to_buffer
+ */
+void _gmx_sel_yyset_in (FILE *  in_str , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    yyin = in_str ;
+}
+
+void _gmx_sel_yyset_out (FILE *  out_str , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    yyout = out_str ;
+}
+
+int _gmx_sel_yyget_debug  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    return yy_flex_debug;
+}
+
+void _gmx_sel_yyset_debug (int  bdebug , yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    yy_flex_debug = bdebug ;
+}
+
+/* Accessor methods for yylval and yylloc */
+
+/* User-visible API */
+
+/* _gmx_sel_yylex_init is special because it creates the scanner itself, so it is
+ * the ONLY reentrant function that doesn't take the scanner as the last argument.
+ * That's why we explicitly handle the declaration, instead of using our macros.
+ */
+
+int _gmx_sel_yylex_init(yyscan_t* ptr_yy_globals)
+
+{
+    if (ptr_yy_globals == NULL){
+        errno = EINVAL;
+        return 1;
+    }
+
+    *ptr_yy_globals = (yyscan_t) _gmx_sel_yyalloc ( sizeof( struct yyguts_t ), NULL );
+
+    if (*ptr_yy_globals == NULL){
+        errno = ENOMEM;
+        return 1;
+    }
+
+    /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */
+    memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t));
+
+    return yy_init_globals ( *ptr_yy_globals );
+}
+
+/* _gmx_sel_yylex_init_extra has the same functionality as _gmx_sel_yylex_init, but follows the
+ * convention of taking the scanner as the last argument. Note however, that
+ * this is a *pointer* to a scanner, as it will be allocated by this call (and
+ * is the reason, too, why this function also must handle its own declaration).
+ * The user defined value in the first argument will be available to _gmx_sel_yyalloc in
+ * the yyextra field.
+ */
+
+int _gmx_sel_yylex_init_extra(YY_EXTRA_TYPE yy_user_defined,yyscan_t* ptr_yy_globals )
+
+{
+    struct yyguts_t dummy_yyguts;
+
+    _gmx_sel_yyset_extra (yy_user_defined, &dummy_yyguts);
+
+    if (ptr_yy_globals == NULL){
+        errno = EINVAL;
+        return 1;
+    }
+       
+    *ptr_yy_globals = (yyscan_t) _gmx_sel_yyalloc ( sizeof( struct yyguts_t ), &dummy_yyguts );
+       
+    if (*ptr_yy_globals == NULL){
+        errno = ENOMEM;
+        return 1;
+    }
+    
+    /* By setting to 0xAA, we expose bugs in
+    yy_init_globals. Leave at 0x00 for releases. */
+    memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t));
+    
+    _gmx_sel_yyset_extra (yy_user_defined, *ptr_yy_globals);
+    
+    return yy_init_globals ( *ptr_yy_globals );
+}
+
+static int yy_init_globals (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+    /* Initialization is the same as for the non-reentrant scanner.
+     * This function is called from _gmx_sel_yylex_destroy(), so don't allocate here.
+     */
+
+    yyg->yy_buffer_stack = 0;
+    yyg->yy_buffer_stack_top = 0;
+    yyg->yy_buffer_stack_max = 0;
+    yyg->yy_c_buf_p = (char *) 0;
+    yyg->yy_init = 0;
+    yyg->yy_start = 0;
+
+    yyg->yy_start_stack_ptr = 0;
+    yyg->yy_start_stack_depth = 0;
+    yyg->yy_start_stack =  NULL;
+
+/* Defined in main.c */
+#ifdef YY_STDINIT
+    yyin = stdin;
+    yyout = stdout;
+#else
+    yyin = (FILE *) 0;
+    yyout = (FILE *) 0;
+#endif
+
+    /* For future reference: Set errno on error, since we are called by
+     * _gmx_sel_yylex_init()
+     */
+    return 0;
+}
+
+/* _gmx_sel_yylex_destroy is for both reentrant and non-reentrant scanners. */
+int _gmx_sel_yylex_destroy  (yyscan_t yyscanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+    /* Pop the buffer stack, destroying each element. */
+       while(YY_CURRENT_BUFFER){
+               _gmx_sel_yy_delete_buffer(YY_CURRENT_BUFFER ,yyscanner );
+               YY_CURRENT_BUFFER_LVALUE = NULL;
+               _gmx_sel_yypop_buffer_state(yyscanner);
+       }
+
+       /* Destroy the stack itself. */
+       _gmx_sel_yyfree(yyg->yy_buffer_stack ,yyscanner);
+       yyg->yy_buffer_stack = NULL;
+
+    /* Destroy the start condition stack. */
+        _gmx_sel_yyfree(yyg->yy_start_stack ,yyscanner );
+        yyg->yy_start_stack = NULL;
+
+    /* Reset the globals. This is important in a non-reentrant scanner so the next time
+     * _gmx_sel_yylex() is called, initialization will occur. */
+    yy_init_globals( yyscanner);
+
+    /* Destroy the main struct (reentrant only). */
+    _gmx_sel_yyfree ( yyscanner , yyscanner );
+    yyscanner = NULL;
+    return 0;
+}
+
+/*
+ * Internal utility routines.
+ */
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yyscanner)
+{
+       register int i;
+       for ( i = 0; i < n; ++i )
+               s1[i] = s2[i];
+}
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner)
+{
+       register int n;
+       for ( n = 0; s[n]; ++n )
+               ;
+
+       return n;
+}
+#endif
+
+void *_gmx_sel_yyalloc (yy_size_t  size , yyscan_t yyscanner)
+{
+       return (void *) malloc( size );
+}
+
+void *_gmx_sel_yyrealloc  (void * ptr, yy_size_t  size , yyscan_t yyscanner)
+{
+       /* The cast to (char *) in the following accommodates both
+        * implementations that use char* generic pointers, and those
+        * that use void* generic pointers.  It works with the latter
+        * because both ANSI C and C++ allow castless assignment from
+        * any pointer type to void*, and deal with argument conversions
+        * as though doing an assignment.
+        */
+       return (void *) realloc( (char *) ptr, size );
+}
+
+void _gmx_sel_yyfree (void * ptr , yyscan_t yyscanner)
+{
+       free( (char *) ptr );   /* see _gmx_sel_yyrealloc() for (char *) cast */
+}
+
+#define YYTABLES_NAME "yytables"
+
+#line 161 "scanner.l"
diff --git a/src/gromacs/selection/scanner.h b/src/gromacs/selection/scanner.h
new file mode 100644 (file)
index 0000000..6ab55e5
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * Parser/scanner interaction functions.
+ *
+ * This is an implementation header: there should be no need to use it outside
+ * this directory.
+ */
+#ifndef SELECTION_SCANNER_H
+#define SELECTION_SCANNER_H
+
+namespace gmx
+{
+class AbstractErrorReporter;
+}
+
+#include "parser.h"
+
+struct gmx_ana_indexgrps_t;
+struct gmx_ana_selcollection_t;
+
+#ifndef YY_TYPEDEF_YY_SCANNER_T
+#define YY_TYPEDEF_YY_SCANNER_T
+typedef void *yyscan_t;
+#endif
+
+/** Initializes the selection scanner. */
+int
+_gmx_sel_init_lexer(yyscan_t *scannerp, struct gmx_ana_selcollection_t *sc,
+                    gmx::AbstractErrorReporter *errors,
+                    bool bInteractive, int maxnr, bool bGroups,
+                    struct gmx_ana_indexgrps_t *grps);
+/** Frees memory allocated for the selection scanner. */
+void
+_gmx_sel_free_lexer(yyscan_t scanner);
+
+/** Returns TRUE if the scanner is interactive. */
+gmx_bool
+_gmx_sel_is_lexer_interactive(yyscan_t scanner);
+/** Returns the selection collection for the scanner. */
+struct gmx_ana_selcollection_t *
+_gmx_sel_lexer_selcollection(yyscan_t scanner);
+/** Returns the error reporter for the scanner. */
+gmx::AbstractErrorReporter *
+_gmx_sel_lexer_error_reporter(yyscan_t scanner);
+/** Returns true if the external index groups for the scanner are set. */
+bool
+_gmx_sel_lexer_has_groups_set(yyscan_t scanner);
+/** Returns the external index groups for the scanner. */
+struct gmx_ana_indexgrps_t *
+_gmx_sel_lexer_indexgrps(yyscan_t scanner);
+/** Returns the number of selections after which the parser should stop. */
+int
+_gmx_sel_lexer_exp_selcount(yyscan_t scanner);
+
+/** Returns a pretty string of the current selection.  */
+const char *
+_gmx_sel_lexer_pselstr(yyscan_t scanner);
+/** Clears the current selection string.  */
+void
+_gmx_sel_lexer_clear_pselstr(yyscan_t scanner);
+/** Clears the method stack in the scanner in error situations. */
+void
+_gmx_sel_lexer_clear_method_stack(yyscan_t scanner);
+/** Notifies the scanner that a complete method expression has been parsed. */
+void
+_gmx_sel_finish_method(yyscan_t scanner);
+/** Initializes the scanner to scan a file. */
+void
+_gmx_sel_set_lex_input_file(yyscan_t scanner, FILE *fp);
+/** Initializes the scanner to scan a string. */
+void
+_gmx_sel_set_lex_input_str(yyscan_t scanner, const char *str);
+
+/** A wrapper for the actual scanner, used by the Bison parser. */
+int
+_gmx_sel_yyblex(YYSTYPE *yylval, yyscan_t yyscanner);
+
+#endif
diff --git a/src/gromacs/selection/scanner.l b/src/gromacs/selection/scanner.l
new file mode 100644 (file)
index 0000000..1acebe1
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \cond \internal \file scanner.l
+ * \brief
+ * Tokenizer for the selection language.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_selection
+ * \endcond
+ */
+/*! \internal \file scanner.cpp
+ * \brief
+ * Generated (from scanner.l by Flex) tokenizer for the selection language.
+ *
+ * \ingroup module_selection
+ */
+%{
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string2.h>
+
+#include "parser.h"
+#include "scanner.h"
+#include "scanner_internal.h"
+
+/* This macro is here to make the actions a bit shorter, since nearly every
+ * action needs this call. */
+#define ADD_TOKEN _gmx_sel_lexer_add_token(yytext, yyleng, state)
+
+%}
+
+INTEGER    [[:digit:]]+
+DSEQ       ([[:digit:]]+)
+FRAC       (([[:digit:]]*"."{DSEQ})|{DSEQ}".")
+EXP        ([eE][+-]?{DSEQ})
+REAL       (({FRAC}{EXP}?)|({DSEQ}{EXP}))
+STRING     (\"([^\"\\\n]|(\\\"))*\")
+IDENTIFIER ([[:alpha:]][_[:alnum:]]*)
+CMPOP      (([<>]=?)|([!=]=))
+COMMENT    (#.*)
+
+%option nodefault
+%option noyywrap
+%option reentrant
+%option prefix="_gmx_sel_yy"
+%option header-file="scanner_flex.h"
+%option nounistd
+%option never-interactive
+
+%s matchof
+%s matchbool
+%s cmdstart
+%x help
+
+%%
+
+%{
+    gmx_sel_lexer_t *state = yyget_extra(yyscanner);
+    int              retval;
+    /* Return a token if one is pending */
+    retval = _gmx_sel_lexer_process_pending(yylval, state);
+    if (retval != 0)
+    {
+        return retval;
+    }
+    /* Handle the start conditions for 'of' matching */
+    if (state->bMatchOf)
+    {
+        BEGIN(matchof);
+        state->bMatchOf = FALSE;
+    }
+    else if (state->bMatchBool)
+    {
+        BEGIN(matchbool);
+        state->bMatchBool = FALSE;
+    }
+    else if (state->bCmdStart)
+    {
+        BEGIN(cmdstart);
+    }
+    else if (YYSTATE != help)
+    {
+        BEGIN(0);
+    }
+%}
+
+{COMMENT}
+{INTEGER}       { yylval->i   = strtol(yytext, NULL, 10);    ADD_TOKEN; return TOK_INT; }
+{REAL}          { yylval->r   = strtod(yytext, NULL);        ADD_TOKEN; return TOK_REAL; }
+{STRING}        { yylval->str = gmx_strndup(yytext+1, yyleng-2); ADD_TOKEN; return STR;  }
+
+\\\n            { _gmx_sel_lexer_add_token(" ", 1, state); }
+";"|\n          {
+                    if (yytext[0] == ';' || state->bInteractive)
+                    {
+                        rtrim(state->pselstr);
+                        return CMD_SEP;
+                    }
+                    else
+                    {
+                        _gmx_sel_lexer_add_token(" ", 1, state);
+                    }
+                }
+
+<cmdstart>help  { BEGIN(help); return HELP; }
+<help>{
+[[:blank:]]+
+{IDENTIFIER}    { yylval->str = gmx_strndup(yytext, yyleng); return HELP_TOPIC; }
+";"|\n          { return CMD_SEP; }
+.               { return INVALID; }
+}
+
+<matchbool>{
+yes|on          { ADD_TOKEN; yylval->i = 1; return TOK_INT; }
+no|off          { ADD_TOKEN; yylval->i = 0; return TOK_INT; }
+}
+group           { ADD_TOKEN; return GROUP; }
+to              { ADD_TOKEN; return TO; }
+<matchof>of     { ADD_TOKEN; BEGIN(0); return OF; }
+and|"&&"        { ADD_TOKEN; return AND; }
+or|"||"         { ADD_TOKEN; return OR; }
+xor             { ADD_TOKEN; return XOR; }
+not|"!"         { ADD_TOKEN; return NOT; }
+{CMPOP}         { yylval->str = gmx_strndup(yytext, yyleng); ADD_TOKEN; return CMP_OP; }
+
+{IDENTIFIER}    { return _gmx_sel_lexer_process_identifier(yylval, yytext, yyleng, state); }
+
+[[:blank:]]+    { _gmx_sel_lexer_add_token(" ", 1, state); }
+[_[:alnum:]]+   { yylval->str = gmx_strndup(yytext, yyleng); ADD_TOKEN; return STR; }
+.               { ADD_TOKEN; return yytext[0]; }
diff --git a/src/gromacs/selection/scanner_flex.h b/src/gromacs/selection/scanner_flex.h
new file mode 100644 (file)
index 0000000..abb400c
--- /dev/null
@@ -0,0 +1,350 @@
+#ifndef _gmx_sel_yyHEADER_H
+#define _gmx_sel_yyHEADER_H 1
+#define _gmx_sel_yyIN_HEADER 1
+
+#line 6 "scanner_flex.h"
+
+#line 8 "scanner_flex.h"
+
+#define  YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+#define YY_FLEX_SUBMINOR_VERSION 35
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+/* First, we deal with  platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types. 
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t; 
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN               (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN              (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN              (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX               (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX              (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX              (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX              (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX             (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX             (4294967295U)
+#endif
+
+#endif /* ! C99 */
+
+#endif /* ! FLEXINT_H */
+
+#ifdef __cplusplus
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else  /* ! __cplusplus */
+
+/* C99 requires __STDC__ to be defined as 1. */
+#if defined (__STDC__)
+
+#define YY_USE_CONST
+
+#endif /* defined (__STDC__) */
+#endif /* ! __cplusplus */
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+/* An opaque pointer. */
+#ifndef YY_TYPEDEF_YY_SCANNER_T
+#define YY_TYPEDEF_YY_SCANNER_T
+typedef void* yyscan_t;
+#endif
+
+/* For convenience, these vars (plus the bison vars far below)
+   are macros in the reentrant scanner. */
+#define yyin yyg->yyin_r
+#define yyout yyg->yyout_r
+#define yyextra yyg->yyextra_r
+#define yyleng yyg->yyleng_r
+#define yytext yyg->yytext_r
+#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno)
+#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column)
+#define yy_flex_debug yyg->yy_flex_debug_r
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#ifdef __ia64__
+/* On IA-64, the buffer size is 16k, not 8k.
+ * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case.
+ * Ditto for the __ia64__ case accordingly.
+ */
+#define YY_BUF_SIZE 32768
+#else
+#define YY_BUF_SIZE 16384
+#endif /* __ia64__ */
+#endif
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
+#endif
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+       {
+       FILE *yy_input_file;
+
+       char *yy_ch_buf;                /* input buffer */
+       char *yy_buf_pos;               /* current position in input buffer */
+
+       /* Size of input buffer in bytes, not including room for EOB
+        * characters.
+        */
+       yy_size_t yy_buf_size;
+
+       /* Number of characters read into yy_ch_buf, not including EOB
+        * characters.
+        */
+       int yy_n_chars;
+
+       /* Whether we "own" the buffer - i.e., we know we created it,
+        * and can realloc() it to grow it, and should free() it to
+        * delete it.
+        */
+       int yy_is_our_buffer;
+
+       /* Whether this is an "interactive" input source; if so, and
+        * if we're using stdio for input, then we want to use getc()
+        * instead of fread(), to make sure we stop fetching input after
+        * each newline.
+        */
+       int yy_is_interactive;
+
+       /* Whether we're considered to be at the beginning of a line.
+        * If so, '^' rules will be active on the next match, otherwise
+        * not.
+        */
+       int yy_at_bol;
+
+    int yy_bs_lineno; /**< The line count. */
+    int yy_bs_column; /**< The column count. */
+    
+       /* Whether to try to fill the input buffer when we reach the
+        * end of it.
+        */
+       int yy_fill_buffer;
+
+       int yy_buffer_status;
+
+       };
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+void _gmx_sel_yyrestart (FILE *input_file ,yyscan_t yyscanner );
+void _gmx_sel_yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner );
+YY_BUFFER_STATE _gmx_sel_yy_create_buffer (FILE *file,int size ,yyscan_t yyscanner );
+void _gmx_sel_yy_delete_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
+void _gmx_sel_yy_flush_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
+void _gmx_sel_yypush_buffer_state (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner );
+void _gmx_sel_yypop_buffer_state (yyscan_t yyscanner );
+
+YY_BUFFER_STATE _gmx_sel_yy_scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner );
+YY_BUFFER_STATE _gmx_sel_yy_scan_string (yyconst char *yy_str ,yyscan_t yyscanner );
+YY_BUFFER_STATE _gmx_sel_yy_scan_bytes (yyconst char *bytes,int len ,yyscan_t yyscanner );
+
+void *_gmx_sel_yyalloc (yy_size_t ,yyscan_t yyscanner );
+void *_gmx_sel_yyrealloc (void *,yy_size_t ,yyscan_t yyscanner );
+void _gmx_sel_yyfree (void * ,yyscan_t yyscanner );
+
+#define _gmx_sel_yywrap(n) 1
+#define YY_SKIP_YYWRAP
+
+#define yytext_ptr yytext_r
+
+#ifdef YY_HEADER_EXPORT_START_CONDITIONS
+#define INITIAL 0
+#define matchof 1
+#define matchbool 2
+#define cmdstart 3
+#define help 4
+
+#endif
+
+#ifndef YY_NO_UNISTD_H
+/* Special case for "unistd.h", since it is non-ANSI. We include it way
+ * down here because we want the user's section 1 to have been scanned first.
+ * The user has a chance to override it with an option.
+ */
+#include <unistd.h>
+#endif
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+int _gmx_sel_yylex_init (yyscan_t* scanner);
+
+int _gmx_sel_yylex_init_extra (YY_EXTRA_TYPE user_defined,yyscan_t* scanner);
+
+/* Accessor methods to globals.
+   These are made visible to non-reentrant scanners for convenience. */
+
+int _gmx_sel_yylex_destroy (yyscan_t yyscanner );
+
+int _gmx_sel_yyget_debug (yyscan_t yyscanner );
+
+void _gmx_sel_yyset_debug (int debug_flag ,yyscan_t yyscanner );
+
+YY_EXTRA_TYPE _gmx_sel_yyget_extra (yyscan_t yyscanner );
+
+void _gmx_sel_yyset_extra (YY_EXTRA_TYPE user_defined ,yyscan_t yyscanner );
+
+FILE *_gmx_sel_yyget_in (yyscan_t yyscanner );
+
+void _gmx_sel_yyset_in  (FILE * in_str ,yyscan_t yyscanner );
+
+FILE *_gmx_sel_yyget_out (yyscan_t yyscanner );
+
+void _gmx_sel_yyset_out  (FILE * out_str ,yyscan_t yyscanner );
+
+int _gmx_sel_yyget_leng (yyscan_t yyscanner );
+
+char *_gmx_sel_yyget_text (yyscan_t yyscanner );
+
+int _gmx_sel_yyget_lineno (yyscan_t yyscanner );
+
+void _gmx_sel_yyset_lineno (int line_number ,yyscan_t yyscanner );
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int _gmx_sel_yywrap (yyscan_t yyscanner );
+#else
+extern int _gmx_sel_yywrap (yyscan_t yyscanner );
+#endif
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char *,yyconst char *,int ,yyscan_t yyscanner);
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * ,yyscan_t yyscanner);
+#endif
+
+#ifndef YY_NO_INPUT
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#ifdef __ia64__
+/* On IA-64, the buffer size is 16k, not 8k */
+#define YY_READ_BUF_SIZE 16384
+#else
+#define YY_READ_BUF_SIZE 8192
+#endif /* __ia64__ */
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int _gmx_sel_yylex (yyscan_t yyscanner);
+
+#define YY_DECL int _gmx_sel_yylex (yyscan_t yyscanner)
+#endif /* !YY_DECL */
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+#undef YY_NEW_FILE
+#undef YY_FLUSH_BUFFER
+#undef yy_set_bol
+#undef yy_new_buffer
+#undef yy_set_interactive
+#undef YY_DO_BEFORE_ACTION
+
+#ifdef YY_DECL_IS_OURS
+#undef YY_DECL_IS_OURS
+#undef YY_DECL
+#endif
+
+#line 161 "scanner.l"
+
+#line 349 "scanner_flex.h"
+#undef _gmx_sel_yyIN_HEADER
+#endif /* _gmx_sel_yyHEADER_H */
diff --git a/src/gromacs/selection/scanner_internal.cpp b/src/gromacs/selection/scanner_internal.cpp
new file mode 100644 (file)
index 0000000..6753680
--- /dev/null
@@ -0,0 +1,616 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief Helper functions for the selection tokenizer.
+ *
+ * This file implements the functions in the headers scanner.h and
+ * scanner_internal.h.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_selection
+ */
+/*! \internal \file scanner_flex.h
+ * \brief Generated (from scanner.l) header file by Flex.
+ *
+ * This file contains definitions of functions that are needed in
+ * scanner_internal.cpp.
+ *
+ * \ingroup module_selection
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <typedefs.h>
+#include <smalloc.h>
+#include <string.h>
+
+#include "string2.h"
+
+#include "gromacs/fatalerror/fatalerror.h"
+
+#include "gromacs/selection/selmethod.h"
+
+#include "parsetree.h"
+#include "selectioncollection-impl.h"
+#include "selelem.h"
+#include "symrec.h"
+
+#include "parser.h"
+#include "scanner.h"
+#include "scanner_internal.h"
+
+//! Step in which the allocated memory for pretty-printed input is incremeted.
+#define STRSTORE_ALLOCSTEP 1000
+
+/* These are defined as macros in the generated scanner_flex.h.
+ * We undefine them here to have them as variable names in the subroutines.
+ * There are other ways of doing this, but this is probably the easiest. */
+#undef yylval
+#undef yytext
+#undef yyleng
+
+static gmx_bool
+read_stdin_line(gmx_sel_lexer_t *state)
+{
+    char *ptr     = state->inputstr;
+    int   max_len = state->nalloc_input;
+    int   totlen = 0;
+
+    if (feof(stdin))
+    {
+        return FALSE;
+    }
+    if (state->bInteractive)
+    {
+        fprintf(stderr, "> ");
+    }
+    /* For some reason (at least on my Linux), fgets() doesn't return until
+     * the user presses Ctrl-D _twice_ at the end of a non-empty line.
+     * This can be a bit confusing for users, but there's not much we can
+     * do, and the chances of a normal user noticing this are not very big. */
+    while (fgets(ptr, max_len, stdin) != NULL)
+    {
+        int len = strlen(ptr);
+
+        totlen += len;
+        if (len >= 2 && ptr[len - 1] == '\n' && ptr[len - 2] == '\\')
+        {
+            if (state->bInteractive)
+            {
+                fprintf(stderr, "... ");
+            }
+        }
+        else if ((len >= 1 && ptr[len - 1] == '\n') || len < max_len - 1)
+        {
+            break;
+        }
+        ptr     += len;
+        max_len -= len;
+        if (max_len <= 2)
+        {
+            max_len += state->nalloc_input;
+            state->nalloc_input *= 2;
+            len = ptr - state->inputstr;
+            srenew(state->inputstr, state->nalloc_input);
+            ptr = state->inputstr + len;
+        }
+    }
+    if (state->bInteractive && (totlen == 0 || ptr[totlen - 1] != '\n'))
+    {
+        fprintf(stderr, "\n");
+    }
+    if (ferror(stdin))
+    {
+        GMX_ERROR_NORET(gmx::eeInvalidInput, "Selection reading failed");
+    }
+    return totlen > 0;
+}
+
+int
+_gmx_sel_yyblex(YYSTYPE *yylval, yyscan_t yyscanner)
+{
+    gmx_sel_lexer_t *state = _gmx_sel_yyget_extra(yyscanner);
+    gmx_bool bCmdStart;
+    int token;
+
+    if (!state->bBuffer && !state->inputstr)
+    {
+        state->nalloc_input = 1024;
+        snew(state->inputstr, state->nalloc_input);
+        read_stdin_line(state);
+        _gmx_sel_set_lex_input_str(yyscanner, state->inputstr);
+    }
+    bCmdStart = state->bCmdStart;
+    token = _gmx_sel_yylex(yylval, yyscanner);
+    while (state->inputstr && token == 0 && read_stdin_line(state))
+    {
+        _gmx_sel_set_lex_input_str(yyscanner, state->inputstr);
+        token = _gmx_sel_yylex(yylval, yyscanner);
+    }
+    if (token == 0 && !bCmdStart)
+    {
+        token = CMD_SEP;
+        rtrim(state->pselstr);
+    }
+    state->bCmdStart = (token == CMD_SEP);
+    return token;
+}
+
+static int
+init_param_token(YYSTYPE *yylval, gmx_ana_selparam_t *param, gmx_bool bBoolNo)
+{
+    if (bBoolNo)
+    {
+        snew(yylval->str, strlen(param->name) + 3);
+        yylval->str[0] = 'n';
+        yylval->str[1] = 'o';
+        strcpy(yylval->str+2, param->name);
+    }
+    else
+    {
+        yylval->str = param->name ? strdup(param->name) : NULL;
+    }
+    return PARAM;
+}
+
+static int
+init_method_token(YYSTYPE *yylval, gmx_ana_selmethod_t *method, gmx_bool bPosMod,
+                  gmx_sel_lexer_t *state)
+{
+    /* If the previous token was not KEYWORD_POS, return EMPTY_POSMOD
+     * before the actual method to work around a limitation in Bison. */
+    if (!bPosMod && method->type != POS_VALUE)
+    {
+        state->nextmethod = method;
+        return EMPTY_POSMOD;
+    }
+    yylval->meth = method;
+    if (!(method->flags & SMETH_MODIFIER) && method->nparams == 0)
+    {
+        /* Keyword */
+        switch (method->type)
+        {
+            case INT_VALUE:   return KEYWORD_NUMERIC;
+            case REAL_VALUE:  return KEYWORD_NUMERIC;
+            case STR_VALUE:   return KEYWORD_STR;
+            case GROUP_VALUE: return KEYWORD_GROUP;
+            default:
+                GMX_ERROR_NORET(gmx::eeInternalError, "Unsupported keyword type");
+                return INVALID;
+        }
+    } else {
+        /* Method with parameters or a modifier */
+        if (method->flags & SMETH_MODIFIER)
+        {
+            /* Remove all methods from the stack */
+            state->msp = -1;
+            if (method->param[1].name == NULL)
+            {
+                state->nextparam = &method->param[1];
+            }
+        }
+        else
+        {
+            if (method->param[0].name == NULL)
+            {
+                state->nextparam = &method->param[0];
+            }
+        }
+        ++state->msp;
+        if (state->msp >= state->mstack_alloc)
+        {
+            state->mstack_alloc += 10;
+            srenew(state->mstack, state->mstack_alloc);
+        }
+        state->mstack[state->msp] = method;
+        if (method->flags & SMETH_MODIFIER)
+        {
+            return MODIFIER;
+        }
+        switch (method->type)
+        {
+            case INT_VALUE:   return METHOD_NUMERIC;
+            case REAL_VALUE:  return METHOD_NUMERIC;
+            case POS_VALUE:   return METHOD_POS;
+            case GROUP_VALUE: return METHOD_GROUP;
+            default:
+                --state->msp;
+                GMX_ERROR_NORET(gmx::eeInternalError, "Unsupported method type");
+                return INVALID;
+        }
+    }
+    return INVALID; /* Should not be reached */
+}
+
+int
+_gmx_sel_lexer_process_pending(YYSTYPE *yylval, gmx_sel_lexer_t *state)
+{
+    if (state->nextparam)
+    {
+        gmx_ana_selparam_t *param = state->nextparam;
+        gmx_bool                bBoolNo = state->bBoolNo;
+
+        if (state->neom > 0)
+        {
+            --state->neom;
+            return END_OF_METHOD;
+        }
+        state->nextparam = NULL;
+        state->bBoolNo   = FALSE;
+        _gmx_sel_lexer_add_token(param->name, -1, state);
+        return init_param_token(yylval, param, bBoolNo);
+    }
+    if (state->prev_pos_kw > 0)
+    {
+        --state->prev_pos_kw;
+    }
+    if (state->nextmethod)
+    {
+        gmx_ana_selmethod_t *method = state->nextmethod;
+
+        state->nextmethod = NULL;
+        return init_method_token(yylval, method, TRUE, state);
+    }
+    return 0;
+}
+
+int
+_gmx_sel_lexer_process_identifier(YYSTYPE *yylval, char *yytext, size_t yyleng,
+                                  gmx_sel_lexer_t *state)
+{
+    gmx_sel_symrec_t *symbol;
+    e_symbol_t        symtype;
+
+    /* Check if the identifier matches with a parameter name */
+    if (state->msp >= 0)
+    {
+        gmx_ana_selparam_t *param = NULL;
+        gmx_bool                bBoolNo = FALSE;
+        int                 sp = state->msp;
+        while (!param && sp >= 0)
+        {
+            int             i;
+            for (i = 0; i < state->mstack[sp]->nparams; ++i)
+            {
+                /* Skip NULL parameters and too long parameters */
+                if (state->mstack[sp]->param[i].name == NULL
+                    || strlen(state->mstack[sp]->param[i].name) > yyleng)
+                {
+                    continue;
+                }
+                if (!strncmp(state->mstack[sp]->param[i].name, yytext, yyleng))
+                {
+                    param = &state->mstack[sp]->param[i];
+                    break;
+                }
+                /* Check separately for a 'no' prefix on gmx_boolean parameters */
+                if (state->mstack[sp]->param[i].val.type == NO_VALUE
+                    && yyleng > 2 && yytext[0] == 'n' && yytext[1] == 'o'
+                    && !strncmp(state->mstack[sp]->param[i].name, yytext+2, yyleng-2))
+                {
+                    param = &state->mstack[sp]->param[i];
+                    bBoolNo = TRUE;
+                    break;
+                }
+            }
+            if (!param)
+            {
+                --sp;
+            }
+        }
+        if (param)
+        {
+            if (param->val.type == NO_VALUE && !bBoolNo)
+            {
+                state->bMatchBool = TRUE;
+            }
+            if (sp < state->msp)
+            {
+                state->neom = state->msp - sp - 1;
+                state->nextparam = param;
+                state->bBoolNo   = bBoolNo;
+                return END_OF_METHOD;
+            }
+            _gmx_sel_lexer_add_token(param->name, -1, state);
+            return init_param_token(yylval, param, bBoolNo);
+        }
+    }
+
+    /* Check if the identifier matches with a symbol */
+    symbol = _gmx_sel_find_symbol_len(state->sc->symtab, yytext, yyleng, FALSE);
+    /* If there is no match, return the token as a string */
+    if (!symbol)
+    {
+        yylval->str = gmx_strndup(yytext, yyleng);
+        _gmx_sel_lexer_add_token(yytext, yyleng, state);
+        return IDENTIFIER;
+    }
+    _gmx_sel_lexer_add_token(_gmx_sel_sym_name(symbol), -1, state);
+    symtype = _gmx_sel_sym_type(symbol);
+    /* Reserved symbols should have been caught earlier */
+    if (symtype == SYMBOL_RESERVED)
+    {
+        GMX_ERROR_NORET(gmx::eeInternalError,
+                        "Mismatch between tokenizer and reserved symbol table");
+        return INVALID;
+    }
+    /* For variable symbols, return the type of the variable value */
+    if (symtype == SYMBOL_VARIABLE)
+    {
+        t_selelem *var;
+
+        var = _gmx_sel_sym_value_var(symbol);
+        /* Return simple tokens for constant variables */
+        if (var->type == SEL_CONST)
+        {
+            switch (var->v.type)
+            {
+                case INT_VALUE:
+                    yylval->i = var->v.u.i[0];
+                    return TOK_INT;
+                case REAL_VALUE:
+                    yylval->r = var->v.u.r[0];
+                    return TOK_REAL;
+                case POS_VALUE:
+                    break;
+                default:
+                    GMX_ERROR_NORET(gmx::eeInternalError,
+                                    "Unsupported variable type");
+                    return INVALID;
+            }
+        }
+        yylval->sel = var;
+        switch (var->v.type)
+        {
+            case INT_VALUE:   return VARIABLE_NUMERIC;
+            case REAL_VALUE:  return VARIABLE_NUMERIC;
+            case POS_VALUE:   return VARIABLE_POS;
+            case GROUP_VALUE: return VARIABLE_GROUP;
+            default:
+                GMX_ERROR_NORET(gmx::eeInternalError,
+                                "Unsupported variable type");
+                return INVALID;
+        }
+        return INVALID; /* Should not be reached. */
+    }
+    /* For method symbols, return the correct type */
+    if (symtype == SYMBOL_METHOD)
+    {
+        gmx_ana_selmethod_t *method;
+
+        method = _gmx_sel_sym_value_method(symbol);
+        return init_method_token(yylval, method, state->prev_pos_kw > 0, state);
+    }
+    /* For position symbols, we need to return KEYWORD_POS, but we also need
+     * some additional handling. */
+    if (symtype == SYMBOL_POS)
+    {
+        state->bMatchOf = TRUE;
+        yylval->str = _gmx_sel_sym_name(symbol);
+        state->prev_pos_kw = 2;
+        return KEYWORD_POS;
+    }
+    /* Should not be reached */
+    return INVALID;
+}
+
+void
+_gmx_sel_lexer_add_token(const char *str, int len, gmx_sel_lexer_t *state)
+{
+    /* Do nothing if the string is empty, or if it is a space and there is
+     * no other text yet, or if there already is a space. */
+    if (!str || len == 0 || strlen(str) == 0
+        || (str[0] == ' ' && str[1] == 0
+            && (state->pslen == 0 || state->pselstr[state->pslen - 1] == ' ')))
+    {
+        return;
+    }
+    if (len < 0)
+    {
+        len = strlen(str);
+    }
+    /* Allocate more memory if necessary */
+    if (state->nalloc_psel - state->pslen < len)
+    {
+        int incr = STRSTORE_ALLOCSTEP < len ? len : STRSTORE_ALLOCSTEP;
+        state->nalloc_psel += incr;
+        srenew(state->pselstr, state->nalloc_psel);
+    }
+    /* Append the token to the stored string */
+    strncpy(state->pselstr + state->pslen, str, len);
+    state->pslen += len;
+    state->pselstr[state->pslen] = 0;
+}
+
+int
+_gmx_sel_init_lexer(yyscan_t *scannerp, struct gmx_ana_selcollection_t *sc,
+                    gmx::AbstractErrorReporter *errors,
+                    bool bInteractive, int maxnr, bool bGroups,
+                    struct gmx_ana_indexgrps_t *grps)
+{
+    gmx_sel_lexer_t *state;
+    int              rc;
+
+    rc = _gmx_sel_yylex_init(scannerp);
+    if (rc != 0)
+    {
+        return rc;
+    }
+
+    snew(state, 1);
+    state->sc        = sc;
+    state->errors    = errors;
+    state->bGroups   = bGroups;
+    state->grps      = grps;
+    state->nexpsel   = (maxnr > 0 ? sc->sel.size() + maxnr : -1);
+
+    state->bInteractive = bInteractive;
+    state->nalloc_input = 0;
+    state->inputstr     = NULL;
+
+    snew(state->pselstr, STRSTORE_ALLOCSTEP);
+    state->pselstr[0]   = 0;
+    state->pslen        = 0;
+    state->nalloc_psel  = STRSTORE_ALLOCSTEP;
+
+    snew(state->mstack, 20);
+    state->mstack_alloc = 20;
+    state->msp          = -1;
+    state->neom         = 0;
+    state->nextparam    = NULL;
+    state->nextmethod   = NULL;
+    state->prev_pos_kw  = 0;
+    state->bBoolNo      = FALSE;
+    state->bMatchOf     = FALSE;
+    state->bMatchBool   = FALSE;
+    state->bCmdStart    = TRUE;
+    state->bBuffer      = FALSE;
+
+    _gmx_sel_yyset_extra(state, *scannerp);
+    return 0;
+}
+
+void
+_gmx_sel_free_lexer(yyscan_t scanner)
+{
+    gmx_sel_lexer_t *state = _gmx_sel_yyget_extra(scanner);
+
+    sfree(state->inputstr);
+    sfree(state->pselstr);
+    sfree(state->mstack);
+    if (state->bBuffer)
+    {
+        _gmx_sel_yy_delete_buffer(state->buffer, scanner);
+    }
+    sfree(state);
+    _gmx_sel_yylex_destroy(scanner);
+}
+
+gmx_bool
+_gmx_sel_is_lexer_interactive(yyscan_t scanner)
+{
+    gmx_sel_lexer_t *state = _gmx_sel_yyget_extra(scanner);
+    return state->bInteractive;
+}
+
+struct gmx_ana_selcollection_t *
+_gmx_sel_lexer_selcollection(yyscan_t scanner)
+{
+    gmx_sel_lexer_t *state = _gmx_sel_yyget_extra(scanner);
+    return state->sc;
+}
+
+gmx::AbstractErrorReporter *
+_gmx_sel_lexer_error_reporter(yyscan_t scanner)
+{
+    gmx_sel_lexer_t *state = _gmx_sel_yyget_extra(scanner);
+    return state->errors;
+}
+
+bool
+_gmx_sel_lexer_has_groups_set(yyscan_t scanner)
+{
+    gmx_sel_lexer_t *state = _gmx_sel_yyget_extra(scanner);
+    return state->bGroups;
+}
+
+struct gmx_ana_indexgrps_t *
+_gmx_sel_lexer_indexgrps(yyscan_t scanner)
+{
+    gmx_sel_lexer_t *state = _gmx_sel_yyget_extra(scanner);
+    return state->grps;
+}
+
+int
+_gmx_sel_lexer_exp_selcount(yyscan_t scanner)
+{
+    gmx_sel_lexer_t *state = _gmx_sel_yyget_extra(scanner);
+    return state->nexpsel;
+}
+
+const char *
+_gmx_sel_lexer_pselstr(yyscan_t scanner)
+{
+    gmx_sel_lexer_t *state = _gmx_sel_yyget_extra(scanner);
+    return state->pselstr;
+}
+
+void
+_gmx_sel_lexer_clear_pselstr(yyscan_t scanner)
+{
+    gmx_sel_lexer_t *state = _gmx_sel_yyget_extra(scanner);
+    state->pselstr[0] = 0;
+    state->pslen      = 0;
+}
+
+void
+_gmx_sel_lexer_clear_method_stack(yyscan_t scanner)
+{
+    gmx_sel_lexer_t *state = _gmx_sel_yyget_extra(scanner);
+
+    state->msp = -1;
+}
+
+void
+_gmx_sel_finish_method(yyscan_t scanner)
+{
+    gmx_sel_lexer_t *state = _gmx_sel_yyget_extra(scanner);
+
+    if (state->msp >= 0)
+    {
+        --state->msp;
+    }
+}
+
+void
+_gmx_sel_set_lex_input_file(yyscan_t scanner, FILE *fp)
+{
+    gmx_sel_lexer_t *state = _gmx_sel_yyget_extra(scanner);
+
+    state->bBuffer = TRUE;
+    state->buffer  = _gmx_sel_yy_create_buffer(fp, YY_BUF_SIZE, scanner);
+    _gmx_sel_yy_switch_to_buffer(state->buffer, scanner);
+}
+
+void
+_gmx_sel_set_lex_input_str(yyscan_t scanner, const char *str)
+{
+    gmx_sel_lexer_t *state = _gmx_sel_yyget_extra(scanner);
+
+    if (state->bBuffer)
+    {
+        _gmx_sel_yy_delete_buffer(state->buffer, scanner);
+    }
+    state->bBuffer = TRUE;
+    state->buffer  = _gmx_sel_yy_scan_string(str, scanner);
+}
diff --git a/src/gromacs/selection/scanner_internal.h b/src/gromacs/selection/scanner_internal.h
new file mode 100644 (file)
index 0000000..4ab1084
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief Internal header file used by the selection tokenizer.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_selection
+ */
+#ifndef SELECTION_SCANNER_INTERNAL_H
+#define SELECTION_SCANNER_INTERNAL_H
+
+namespace gmx
+{
+class AbstractErrorReporter;
+}
+
+#include "parser.h"
+
+/** The scanning function generated by Flex. */
+#define YY_DECL int _gmx_sel_yylex(YYSTYPE *yylval, yyscan_t yyscanner)
+YY_DECL;
+
+/* These need to be defined before including scanner_flex.h, because it
+ * uses YY_EXTRA_TYPE. But we also need to include it before defining
+ * gmx_sel_lexer_t; hence the forward declaration. */
+struct gmx_sel_lexer_t;
+#define YY_EXTRA_TYPE struct gmx_sel_lexer_t *
+
+/* We cannot include scanner_flex.h from the scanner itself, because it
+ * seems to break everything. */
+/* And we need to define YY_NO_UNISTD_H here as well, otherwise unistd.h
+ * gets included in other files than scanner.cpp... */
+#ifndef FLEX_SCANNER
+#define YY_NO_UNISTD_H
+#include "scanner_flex.h"
+#endif
+
+/*! \internal \brief
+ * Internal data structure for the selection tokenizer state.
+ */
+typedef struct gmx_sel_lexer_t
+{
+    //! Selection collection to put parsed selections in.
+    struct gmx_ana_selcollection_t  *sc;
+    //! Error reporter object.
+    gmx::AbstractErrorReporter      *errors;
+    //! Whether external index groups have been set.
+    bool                             bGroups;
+    //! External index groups for resolving \c group keywords.
+    struct gmx_ana_indexgrps_t      *grps;
+    //! Number of selections at which the parser should stop.
+    int                              nexpsel;
+
+    //! Whether the parser is interactive.
+    gmx_bool                             bInteractive;
+    //! Current input string (line) for an interactive scanner.
+    char                            *inputstr;
+    //! Number of bytes allocated for \a inputstr.
+    int                              nalloc_input;
+
+    //! Pretty-printed version of the string parsed since last clear.
+    char                            *pselstr;
+    //! Length of the string in \a pselstr.
+    int                              pslen;
+    //! Number of bytes allocated for \a pselstr.
+    int                              nalloc_psel;
+
+    //! Stack of methods in which parameters should be looked up.
+    struct gmx_ana_selmethod_t     **mstack;
+    //! Index of the top of the stack in \a mstack.
+    int                              msp;
+    //! Number of elements allocated for \a mstack.
+    int                              mstack_alloc;
+
+    //! Number of END_OF_METHOD tokens to return before \a nextparam.
+    int                              neom;
+    //! Parameter symbol to return before resuming scanning.
+    struct gmx_ana_selparam_t       *nextparam;
+    //! Whether \a nextparam was a boolean parameter with a 'no' prefix.
+    gmx_bool                             bBoolNo;
+    /*! \brief
+     * Method symbol to return before resuming scanning
+     *
+     * Only used when \p nextparam is NULL.
+     */
+    struct gmx_ana_selmethod_t      *nextmethod;
+    //! Used to track whether the previous token was a position modifier.
+    int                              prev_pos_kw;
+
+    //! Whether the 'of' keyword is acceptable as the next token.
+    gmx_bool                             bMatchOf;
+    //! Whether boolean values (yes/no/on/off) are acceptable as the next token.
+    gmx_bool                             bMatchBool;
+    //! Whether the next token starts a new selection.
+    gmx_bool                             bCmdStart;
+
+    //! Whether an external buffer is set for the scanner.
+    gmx_bool                             bBuffer;
+    //! The current buffer for the scanner.
+    YY_BUFFER_STATE                  buffer;
+} gmx_sel_lexer_t;
+
+/* Because Flex defines yylval, yytext, and yyleng as macros,
+ * and this file is included from scanner.l,
+ * we cannot have them here as parameter names... */
+/** Internal function for cases where several tokens need to be returned. */
+int
+_gmx_sel_lexer_process_pending(YYSTYPE *, gmx_sel_lexer_t *state);
+/** Internal function that processes identifier tokens. */
+int
+_gmx_sel_lexer_process_identifier(YYSTYPE *, char *, size_t,
+                                  gmx_sel_lexer_t *state);
+/** Internal function to add a token to the pretty-printed selection text. */
+void
+_gmx_sel_lexer_add_token(const char *str, int len, gmx_sel_lexer_t *state);
+
+#endif
diff --git a/src/gromacs/selection/selection.cpp b/src/gromacs/selection/selection.cpp
new file mode 100644 (file)
index 0000000..7b7a137
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * Implements gmx::Selection.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_selection
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <smalloc.h>
+#include <statutil.h>
+#include <string2.h>
+#include <xvgr.h>
+
+#include "gromacs/selection/position.h"
+#include "gromacs/selection/selection.h"
+#include "gromacs/selection/selvalue.h"
+
+#include "selelem.h"
+
+namespace gmx
+{
+
+Selection::Selection(t_selelem *elem, const char *selstr)
+{
+    _sel.name = strdup(elem->name);
+    _sel.selstr = strdup(selstr);
+    gmx_ana_pos_clear(&_sel.p);
+
+    if (elem->child->type == SEL_CONST)
+    {
+        gmx_ana_pos_copy(&_sel.p, elem->child->v.u.p, TRUE);
+        _sel.bDynamic = FALSE;
+    }
+    else
+    {
+        t_selelem *child;
+
+        child = elem->child;
+        child->flags     &= ~SEL_ALLOCVAL;
+        _gmx_selvalue_setstore(&child->v, &_sel.p);
+        /* We should also skip any modifiers to determine the dynamic
+         * status. */
+        while (child->type == SEL_MODIFIER)
+        {
+            child = child->child;
+            if (child->type == SEL_SUBEXPRREF)
+            {
+                child = child->child;
+                /* Because most subexpression elements are created
+                 * during compilation, we need to check for them
+                 * explicitly here.
+                 */
+                if (child->type == SEL_SUBEXPR)
+                {
+                    child = child->child;
+                }
+            }
+        }
+        /* For variable references, we should skip the
+         * SEL_SUBEXPRREF and SEL_SUBEXPR elements. */
+        if (child->type == SEL_SUBEXPRREF)
+        {
+            child = child->child->child;
+        }
+        _sel.bDynamic = (child->child->flags & SEL_DYNAMIC);
+    }
+    /* The group will be set after compilation */
+    _sel.m        = NULL;
+    _sel.q        = NULL;
+    _sel.g        = NULL;
+    _sel.orgm     = NULL;
+    _sel.orgq     = NULL;
+    _sel.selelem  = elem;
+    initCoveredFraction(CFRAC_NONE);
+}
+
+
+Selection::~Selection()
+{
+    sfree(_sel.name);
+    sfree(_sel.selstr);
+    gmx_ana_pos_deinit(&_sel.p);
+    if (_sel.m != _sel.orgm)
+    {
+        sfree(_sel.m);
+    }
+    if (_sel.q != _sel.orgq)
+    {
+        sfree(_sel.q);
+    }
+    sfree(_sel.orgm);
+    sfree(_sel.orgq);
+}
+
+
+void
+Selection::printInfo() const
+{
+    fprintf(stderr, "\"%s\" (%d position%s, %d atom%s%s)", _sel.name,
+            _sel.p.nr,     _sel.p.nr     == 1 ? "" : "s",
+            _sel.g->isize, _sel.g->isize == 1 ? "" : "s",
+            _sel.bDynamic ? ", dynamic" : "");
+    fprintf(stderr, "\n");
+}
+
+
+bool
+Selection::initCoveredFraction(e_coverfrac_t type)
+{
+    gmx_ana_selection_t *sel = &_sel;
+
+    sel->cfractype = type;
+    if (type == CFRAC_NONE || !sel->selelem)
+    {
+        sel->bCFracDyn = FALSE;
+    }
+    else if (!_gmx_selelem_can_estimate_cover(sel->selelem))
+    {
+        sel->cfractype = CFRAC_NONE;
+        sel->bCFracDyn = FALSE;
+    }
+    else
+    {
+        sel->bCFracDyn = TRUE;
+    }
+    sel->cfrac     = sel->bCFracDyn ? 0.0 : 1.0;
+    sel->avecfrac  = sel->cfrac;
+    return type == CFRAC_NONE || sel->cfractype != CFRAC_NONE;
+}
+
+
+void
+Selection::printDebugInfo(int nmaxind) const
+{
+    fprintf(stderr, "  ");
+    printInfo();
+    fprintf(stderr, "    ");
+    gmx_ana_index_dump(_sel.g, -1, nmaxind);
+
+    fprintf(stderr, "    Block (size=%d):", _sel.p.m.mapb.nr);
+    if (!_sel.p.m.mapb.index)
+    {
+        fprintf(stderr, " (null)");
+    }
+    else
+    {
+        int n = _sel.p.m.mapb.nr;
+        if (nmaxind >= 0 && n > nmaxind)
+            n = nmaxind;
+        for (int i = 0; i <= n; ++i)
+            fprintf(stderr, " %d", _sel.p.m.mapb.index[i]);
+        if (n < _sel.p.m.mapb.nr)
+            fprintf(stderr, " ...");
+    }
+    fprintf(stderr, "\n");
+
+    int n = _sel.p.m.nr;
+    if (nmaxind >= 0 && n > nmaxind)
+        n = nmaxind;
+    fprintf(stderr, "    RefId:");
+    if (!_sel.p.m.refid)
+    {
+        fprintf(stderr, " (null)");
+    }
+    else
+    {
+        for (int i = 0; i < n; ++i)
+            fprintf(stderr, " %d", _sel.p.m.refid[i]);
+        if (n < _sel.p.m.nr)
+            fprintf(stderr, " ...");
+    }
+    fprintf(stderr, "\n");
+
+    fprintf(stderr, "    MapId:");
+    if (!_sel.p.m.mapid)
+    {
+        fprintf(stderr, " (null)");
+    }
+    else
+    {
+        for (int i = 0; i < n; ++i)
+            fprintf(stderr, " %d", _sel.p.m.mapid[i]);
+        if (n < _sel.p.m.nr)
+            fprintf(stderr, " ...");
+    }
+    fprintf(stderr, "\n");
+}
+
+} // namespace gmx
diff --git a/src/gromacs/selection/selection.h b/src/gromacs/selection/selection.h
new file mode 100644 (file)
index 0000000..c2d756c
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \file
+ * \brief
+ * Declares gmx::Selection.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \inpublicapi
+ * \ingroup module_selection
+ */
+#ifndef GMX_SELECTION_SELECTION_H
+#define GMX_SELECTION_SELECTION_H
+
+#include "position.h"
+#include "indexutil.h"
+#include "selectionenums.h"
+
+struct t_selelem;
+
+/*! \internal \brief
+ * Describes a single selection.
+ *
+ * \ingroup module_selection
+ */
+typedef struct gmx_ana_selection_t
+{
+    /** Name of the selection. */
+    char                   *name;
+    /** The actual selection string. */
+    char                   *selstr;
+    /** Selected positions. */
+    gmx_ana_pos_t           p;
+    /** Masses associated with the positions. */
+    real                   *m;
+    /** Charges associated with the positions. */
+    real                   *q;
+    /** Pointer to the index group that holds the selected atoms. */
+    struct gmx_ana_index_t *g;
+    /** TRUE if the value can change as a function of time. */
+    gmx_bool                    bDynamic;
+    /** Type of the covered fraction. */
+    e_coverfrac_t           cfractype;
+    /** TRUE if the covered fraction depends on the frame. */
+    gmx_bool                    bCFracDyn;
+    /** Covered fraction of the selection for the current frame. */
+    real                    cfrac;
+    /** The average covered fraction (over the trajectory). */
+    real                    avecfrac;
+
+    /*! \brief
+     * Pointer to the root of the selection element tree (internal use only).
+     *
+     * \internal
+     * This field is NULL if the selection has been loaded directly from an
+     * index file.
+     */
+    struct t_selelem       *selelem;
+    /** Original masses of all possible positions (internal use only). */
+    real                   *orgm;
+    /** Original charges of all possible positions (internal use only). */
+    real                   *orgq;
+} gmx_ana_selection_t;
+
+namespace gmx
+{
+
+class SelectionCollection;
+
+/*! \brief
+ * Provides access to a single selection.
+ *
+ * \inpublicapi
+ * \ingroup module_selection
+ */
+class Selection
+{
+    public:
+        /*! \brief
+         * Creates a new selection object.
+         *
+         * \param[in] elem   Root of the evaluation tree for this selection.
+         * \param[in] selstr String that was parsed to produce this selection.
+         */
+        Selection(t_selelem *elem, const char *selstr);
+
+        //! Returns the name of the selection.
+        const char *name() const  { return _sel.name; }
+        //! Returns the string that was parsed to produce this selection.
+        const char *selectionText() const { return _sel.selstr; }
+        //! Returns true if the size of the selection (posCount()) is dynamic.
+        bool isDynamic() const { return _sel.bDynamic; }
+        //! Returns the type of positions in the selection.
+        e_index_t type() const { return _sel.p.m.type; }
+        //! Number of positions in the selection.
+        int posCount() const { return _sel.p.nr; }
+        //! Returns the \p i'th position for the selection.
+        const rvec &x(int i) const { return _sel.p.x[i]; }
+        //! Returns the velocity for the \p i'th position.
+        const rvec &v(int i) const { return _sel.p.v[i]; }
+        //! Returns the force for the \p i'th position.
+        const rvec &f(int i) const { return _sel.p.f[i]; }
+        /*! \brief
+         * Returns the reference ID for the \p i'th position.
+         */
+        int refId(int i) const { return _sel.p.m.refid[i]; }
+        /*! \brief
+         * Returns the mapped ID for the \p i'th position.
+         */
+        int mapId(int i) const { return _sel.p.m.mapid[i]; }
+        //! Returns the mass for the \p i'th position.
+        real mass(int i) const { return _sel.m[i]; }
+        //! Returns the charge for the \p i'th position.
+        real charge(int i) const { return _sel.q[i]; }
+        //! Returns the number of atoms contributing to the \p i'th position.
+        int atomCount(int i) const
+            { return _sel.p.m.mapb.index[i+1] - _sel.p.m.mapb.index[i]; }
+        //! Returns the atom indices contributing to the \p i'th position.
+        const int *atomIndices(int i) const
+            { return _sel.g ? _sel.g->index + _sel.p.m.mapb.index[i] : NULL; }
+        //! Returns the covered fraction for the current frame.
+        real cfrac() const { return _sel.cfrac; }
+        //! Deprecated method for direct access to position data.
+        const gmx_ana_pos_t *positions() const { return &_sel.p; }
+        //! Deprecated method for direct access to atom index data.
+        gmx_ana_index_t *indexGroup() const { return _sel.g; }
+        //! Deprecated method for direct access to to mapped ID array.
+        int *mapIds() const { return _sel.p.m.mapid; }
+
+        //! Returns true if the given flag is set.
+        bool hasFlag(SelectionFlag flag) const { return _flags.test(flag); }
+        //! Sets the flags for this selection.
+        void setFlags(SelectionFlags flags) { _flags = flags; }
+        /*! \brief
+         * Sets the ID for the \p i'th position for use with mapId().
+         */
+        void setOriginalId(int i, int id) { _sel.p.m.orgid[i] = id; }
+        /*! \brief
+         * Initializes information about covered fractions.
+         *
+         * \param[in] type Type of covered fraction required.
+         * \returns   True if the covered fraction can be calculated for the
+         *      selection.
+         */
+        bool initCoveredFraction(e_coverfrac_t type);
+
+        //! Prints out one-line description of the selection.
+        void printInfo() const;
+        /*! \brief
+         * Prints out extended information about the selection for debugging.
+         *
+         * \param[in] nmaxind Maximum number of values to print in lists
+         *      (-1 = print all).
+         */
+        void printDebugInfo(int nmaxind) const;
+
+        gmx_ana_selection_t     _sel;
+
+    private:
+        ~Selection();
+
+        SelectionFlags          _flags;
+
+        friend class SelectionCollection;
+
+        // Disallow copy and assign.
+        Selection(const Selection &);
+        void operator =(const Selection &);
+};
+
+} // namespace gmx
+
+#endif
diff --git a/src/gromacs/selection/selectioncollection-impl.h b/src/gromacs/selection/selectioncollection-impl.h
new file mode 100644 (file)
index 0000000..35fba31
--- /dev/null
@@ -0,0 +1,213 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * Declares private implementation class for gmx::SelectionCollection.
+ *
+ * This header also defines ::gmx_ana_selcollection_t, which is used in the old
+ * C code for handling selection collections.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_selection
+ */
+#ifndef GMX_SELECTION_SELECTIONCOLLECTION_IMPL_H
+#define GMX_SELECTION_SELECTIONCOLLECTION_IMPL_H
+
+#include <string>
+#include <vector>
+
+#include <typedefs.h>
+
+#include "../options/options.h"
+#include "../utility/flags.h"
+#include "indexutil.h"
+#include "selectioncollection.h"
+
+namespace gmx
+{
+class Selection;
+}
+
+/*! \internal \brief
+ * Information for a collection of selections.
+ *
+ * \ingroup module_selection
+ */
+struct gmx_ana_selcollection_t
+{
+    /** Root of the selection element tree. */
+    struct t_selelem           *root;
+    /** Array of compiled selections. */
+    std::vector<gmx::Selection *>  sel;
+    /** Number of variables defined. */
+    int                            nvars;
+    /** Selection strings for variables. */
+    char                         **varstrs;
+
+    /** Topology for the collection. */
+    t_topology                    *top;
+    /** Index group that contains all the atoms. */
+    struct gmx_ana_index_t         gall;
+    /** Position calculation collection used for selection position evaluation. */
+    struct gmx_ana_poscalc_coll_t *pcc;
+    /** Memory pool used for selection evaluation. */
+    struct gmx_sel_mempool_t      *mempool;
+    /** Parser symbol table. */
+    struct gmx_sel_symtab_t     *symtab;
+};
+
+namespace gmx
+{
+
+class SelectionOptionStorage;
+
+/*! \internal \brief
+ * Private implemention class for SelectionCollection.
+ *
+ * \ingroup module_selection
+ */
+class SelectionCollection::Impl
+{
+    public:
+        struct SelectionRequest
+        {
+            SelectionRequest(const std::string &name, const std::string &descr,
+                             int count, SelectionOptionStorage *storage)
+                : name(name), descr(descr), count(count), storage(storage)
+            { }
+
+            std::string                 name;
+            std::string                 descr;
+            int                         count;
+            SelectionOptionStorage     *storage;
+        };
+
+        //! Shorthand for a list of selections stored internally.
+        typedef std::vector<Selection *> SelectionList;
+        //! Shorthand for a list of selection requests.
+        typedef std::vector<SelectionRequest> RequestList;
+
+        //! Possible flags for the selection collection.
+        enum Flag
+        {
+            efOwnPositionCollection = 1<<0,
+            efExternalGroupsSet     = 1<<1
+        };
+        //! Holds a collection of Flag values.
+        typedef FlagsTemplate<Flag> Flags;
+
+        //! Creates a new selection collection.
+        explicit Impl(gmx_ana_poscalc_coll_t *pcc);
+        ~Impl();
+
+        //! Returns true if the given flag has been set.
+        bool hasFlag(Flag flag) const { return _flags.test(flag); }
+        //! Clears the symbol table of the selection collection.
+        void clearSymbolTable();
+        //! Registers the default selection methods for the collection.
+        int registerDefaultMethods();
+        /*! \brief
+         * Helper function that runs the parser once the tokenizer has been
+         * initialized.
+         *
+         * \param[in,out] scanner Scanner data structure.
+         * \param[in]     maxnr   Maximum number of selections to parse
+         *      (if -1, parse as many as provided by the user).
+         * \param[out]    output  Vector to which parsed selections are
+         *      appended.
+         * \retval        0 on success.
+         * \retval        ::eeInvalidInput on error.
+         *
+         * Does not clear \p output.
+         */
+        int runParser(void *scanner, int maxnr,
+                      std::vector<Selection *> *output);
+        void requestSelections(const std::string &name,
+                               const std::string &descr,
+                               int count, SelectionOptionStorage *storage);
+        int resolveExternalGroups(struct t_selelem *root);
+
+        //! Internal data, used for interfacing with old C code.
+        gmx_ana_selcollection_t _sc;
+        //! Options object for setting global properties on the collection.
+        Options                 _options;
+        //! Default reference position type for selections.
+        std::string             _rpost;
+        //! Default output position type for selections.
+        std::string             _spost;
+        /*! \brief
+         * Debugging level for the collection.
+         *
+         * Possible values:
+         *  - 0: no debugging
+         *  - 1: print selection trees after parsing and compilation
+         *  - 2: like 1, also print intermediate compilation trees
+         *  - 3: like 1, also print the tree after evaluation
+         *  - 4: combine 2 and 3
+         */
+        int                     _debugLevel;
+        //! Flags for various properties of the collection.
+        Flags                   _flags;
+        //! External index groups (can be NULL).
+        gmx_ana_indexgrps_t    *_grps;
+        //! List of selections requested for later parsing.
+        RequestList             _requests;
+};
+
+} // namespace gmx
+
+/*! \addtogroup module_selection
+ * \{
+ */
+
+/* In compiler.cpp */
+/*! \internal \brief
+ * Prepares the selections for evaluation and performs some optimizations.
+ */
+int
+gmx_ana_selcollection_compile(gmx::SelectionCollection *coll);
+
+/* In evaluate.cpp */
+/*! \internal \brief
+ * Evaluates the selection.
+ */
+int
+gmx_ana_selcollection_evaluate(gmx_ana_selcollection_t *sc,
+                               t_trxframe *fr, t_pbc *pbc);
+/*! \internal \brief
+ * Evaluates the largest possible index groups from dynamic selections.
+ */
+int
+gmx_ana_selcollection_evaluate_fin(gmx_ana_selcollection_t *sc, int nframes);
+
+/*!\}*/
+
+#endif
diff --git a/src/gromacs/selection/selectioncollection.cpp b/src/gromacs/selection/selectioncollection.cpp
new file mode 100644 (file)
index 0000000..e17bc89
--- /dev/null
@@ -0,0 +1,678 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * Implements gmx::SelectionCollection.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_selection
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <cassert>
+#include <cstdio>
+
+#include <smalloc.h>
+#include <statutil.h>
+#include <string2.h>
+#include <xvgr.h>
+
+#include "poscalc.h"
+#include "selmethod.h"
+
+#include "gromacs/errorreporting/abstracterrorreporter.h"
+#include "gromacs/fatalerror/fatalerror.h"
+#include "gromacs/options/basicoptions.h"
+#include "gromacs/options/options.h"
+#include "gromacs/selection/selection.h"
+#include "gromacs/selection/selectioncollection.h"
+
+#include "mempool.h"
+#include "scanner.h"
+#include "selectioncollection-impl.h"
+#include "selectionoptionstorage.h"
+#include "selelem.h"
+#include "selmethod.h"
+#include "symrec.h"
+
+/* In parser.y */
+/*! \brief
+ * Parser function generated by Bison.
+ */
+int
+_gmx_sel_yybparse(void *scanner);
+
+namespace gmx
+{
+
+/********************************************************************
+ * SelectionCollection::Impl
+ */
+
+SelectionCollection::Impl::Impl(gmx_ana_poscalc_coll_t *pcc)
+    : _options("selection", "Common selection control"),
+      _debugLevel(0), _grps(NULL)
+{
+    _sc.root      = NULL;
+    _sc.nvars     = 0;
+    _sc.varstrs   = NULL;
+    _sc.top       = NULL;
+    gmx_ana_index_clear(&_sc.gall);
+    _sc.pcc       = pcc;
+    _sc.mempool   = NULL;
+    _sc.symtab    = NULL;
+}
+
+
+SelectionCollection::Impl::~Impl()
+{
+    _gmx_selelem_free_chain(_sc.root);
+    SelectionList::const_iterator isel;
+    for (isel = _sc.sel.begin(); isel != _sc.sel.end(); ++isel)
+    {
+        delete *isel;
+    }
+    for (int i = 0; i < _sc.nvars; ++i)
+    {
+        sfree(_sc.varstrs[i]);
+    }
+    sfree(_sc.varstrs);
+    gmx_ana_index_deinit(&_sc.gall);
+    if (_sc.mempool)
+    {
+        _gmx_sel_mempool_destroy(_sc.mempool);
+    }
+    if (hasFlag(efOwnPositionCollection))
+    {
+        gmx_ana_poscalc_coll_free(_sc.pcc);
+    }
+    clearSymbolTable();
+}
+
+
+void
+SelectionCollection::Impl::clearSymbolTable()
+{
+    if (_sc.symtab)
+    {
+        _gmx_sel_symtab_free(_sc.symtab);
+        _sc.symtab = NULL;
+    }
+}
+
+
+int
+SelectionCollection::Impl::runParser(yyscan_t scanner, int maxnr,
+                                     std::vector<Selection *> *output)
+{
+    gmx_ana_selcollection_t *sc = &_sc;
+    assert(sc == _gmx_sel_lexer_selcollection(scanner));
+
+    int oldCount = sc->sel.size();
+    int bOk = !_gmx_sel_yybparse(scanner);
+    _gmx_sel_free_lexer(scanner);
+    int nr = sc->sel.size() - oldCount;
+    if (maxnr > 0 && nr != maxnr)
+    {
+        return eeInvalidInput;
+    }
+
+    if (bOk)
+    {
+        SelectionList::const_iterator i;
+        for (i = _sc.sel.begin() + oldCount; i != _sc.sel.end(); ++i)
+        {
+            output->push_back(*i);
+        }
+    }
+
+    return bOk ? 0 : eeInvalidInput;
+}
+
+
+void SelectionCollection::Impl::requestSelections(
+        const std::string &name, const std::string &descr,
+        int count, SelectionOptionStorage *storage)
+{
+    _requests.push_back(SelectionRequest(name, descr, count, storage));
+}
+
+
+int SelectionCollection::Impl::resolveExternalGroups(t_selelem *root)
+{
+    int rc = 0;
+
+    if (root->type == SEL_GROUPREF)
+    {
+        if (root->u.gref.name != NULL)
+        {
+            char *name = root->u.gref.name;
+            if (!gmx_ana_indexgrps_find(&root->u.cgrp, _grps, name))
+            {
+                // TODO: Improve error messages
+                GMX_ERROR_NORET(eeInvalidInput,
+                                "Unknown group referenced in a selection");
+                rc = eeInvalidInput;
+            }
+            else
+            {
+                sfree(name);
+            }
+        }
+        else
+        {
+            if (!gmx_ana_indexgrps_extract(&root->u.cgrp, _grps,
+                                           root->u.gref.id))
+            {
+                // TODO: Improve error messages
+                GMX_ERROR_NORET(eeInvalidInput,
+                                "Unknown group referenced in a selection");
+                rc = eeInvalidInput;
+            }
+        }
+        if (rc == 0)
+        {
+            root->type = SEL_CONST;
+            root->name = root->u.cgrp.name;
+        }
+    }
+
+    t_selelem *child = root->child;
+    while (child != NULL)
+    {
+        int rc1 = resolveExternalGroups(child);
+        rc = (rc == 0 ? rc1 : rc);
+        child = child->next;
+    }
+    return rc;
+}
+
+
+/********************************************************************
+ * SelectionCollection
+ */
+
+SelectionCollection::SelectionCollection(gmx_ana_poscalc_coll_t *pcc)
+    : _impl(new Impl(pcc))
+{
+}
+
+
+SelectionCollection::~SelectionCollection()
+{
+    delete _impl;
+}
+
+
+int
+SelectionCollection::init()
+{
+    if (_impl->_sc.pcc == NULL)
+    {
+        int rc = gmx_ana_poscalc_coll_create(&_impl->_sc.pcc);
+        if (rc != 0)
+        {
+            return rc;
+        }
+        _impl->_flags.set(Impl::efOwnPositionCollection);
+    }
+    _gmx_sel_symtab_create(&_impl->_sc.symtab);
+    gmx_ana_selmethod_register_defaults(_impl->_sc.symtab);
+    return 0;
+}
+
+
+int
+SelectionCollection::create(SelectionCollection **scp,
+                            gmx_ana_poscalc_coll_t *pcc)
+{
+    SelectionCollection *sc = new SelectionCollection(pcc);
+
+    int rc = sc->init();
+    if (rc != 0)
+    {
+        *scp = NULL;
+        delete sc;
+        return rc;
+    }
+    *scp = sc;
+    return 0;
+}
+
+
+Options *
+SelectionCollection::initOptions()
+{
+    static const char * const debug_levels[]
+        = {"no", "basic", "compile", "eval", "full", NULL};
+    /*
+    static const char * const desc[] = {
+        "This program supports selections in addition to traditional",
+        "index files. Use [TT]-select help[tt] for additional information,",
+        "or type 'help' in the selection prompt.",
+        NULL,
+    };
+    options.setDescription(desc);
+    */
+
+    Options &options = _impl->_options;
+    const char **postypes = gmx_ana_poscalc_create_type_enum(TRUE);
+    if (postypes == NULL)
+    {
+        return NULL;
+    }
+    options.addOption(StringOption("selrpos").enumValue(postypes + 1)
+                          .store(&_impl->_rpost).defaultValue(postypes[1])
+                          .description("Selection reference positions"));
+    options.addOption(StringOption("seltype").enumValue(postypes + 1)
+                          .store(&_impl->_spost).defaultValue(postypes[1])
+                          .description("Default selection output positions"));
+    assert(_impl->_debugLevel >= 0 && _impl->_debugLevel <= 4);
+    options.addOption(StringOption("seldebug").hidden()
+                          .enumValue(debug_levels)
+                          .defaultValue(debug_levels[_impl->_debugLevel])
+                          .storeEnumIndex(&_impl->_debugLevel)
+                          .description("Print out selection trees for debugging"));
+    sfree(postypes);
+
+    return &_impl->_options;
+}
+
+
+void
+SelectionCollection::setReferencePosType(const char *type)
+{
+    assert(type != NULL);
+    _impl->_rpost = type;
+}
+
+
+void
+SelectionCollection::setOutputPosType(const char *type)
+{
+    assert(type != NULL);
+    _impl->_spost = type;
+}
+
+
+void
+SelectionCollection::setDebugLevel(int debuglevel)
+{
+    _impl->_debugLevel = debuglevel;
+}
+
+
+int
+SelectionCollection::setTopology(t_topology *top, int natoms)
+{
+    gmx_ana_selcollection_t *sc = &_impl->_sc;
+    gmx_ana_poscalc_coll_set_topology(sc->pcc, top);
+    sc->top = top;
+
+    /* Get the number of atoms from the topology if it is not given */
+    if (natoms <= 0)
+    {
+        if (sc->top == NULL)
+        {
+            GMX_ERROR(eeInvalidValue,
+                      "Selections need either the topology or the number of atoms");
+        }
+        natoms = sc->top->atoms.nr;
+    }
+    gmx_ana_index_init_simple(&sc->gall, natoms, NULL);
+    return 0;
+}
+
+
+int
+SelectionCollection::setIndexGroups(gmx_ana_indexgrps_t *grps)
+{
+    assert(grps == NULL || !_impl->hasFlag(Impl::efExternalGroupsSet));
+    _impl->_grps = grps;
+    _impl->_flags.set(Impl::efExternalGroupsSet);
+
+    int rc = 0;
+    t_selelem *root = _impl->_sc.root;
+    while (root != NULL)
+    {
+        int rc1 = _impl->resolveExternalGroups(root);
+        rc = (rc == 0 ? rc1 : rc);
+        root = root->next;
+    }
+    return rc;
+}
+
+
+bool
+SelectionCollection::requiresTopology() const
+{
+    t_selelem   *sel;
+    e_poscalc_t  type;
+    int          flags;
+    int          rc;
+
+    if (!_impl->_rpost.empty())
+    {
+        flags = 0;
+        rc = gmx_ana_poscalc_type_from_enum(_impl->_rpost.c_str(), &type, &flags);
+        if (rc == 0 && type != POS_ATOM)
+        {
+            return TRUE;
+        }
+    }
+    if (!_impl->_spost.empty())
+    {
+        flags = 0;
+        rc = gmx_ana_poscalc_type_from_enum(_impl->_spost.c_str(), &type, &flags);
+        if (rc == 0 && type != POS_ATOM)
+        {
+            return TRUE;
+        }
+    }
+
+    sel = _impl->_sc.root;
+    while (sel)
+    {
+        if (_gmx_selelem_requires_top(sel))
+        {
+            return TRUE;
+        }
+        sel = sel->next;
+    }
+    return FALSE;
+}
+
+
+int
+SelectionCollection::parseRequestedFromStdin(bool bInteractive,
+                                             AbstractErrorReporter *errors)
+{
+    int rc = 0;
+    Impl::RequestList::const_iterator i;
+    for (i = _impl->_requests.begin(); i != _impl->_requests.end(); ++i)
+    {
+        const Impl::SelectionRequest &request = *i;
+        if (bInteractive)
+        {
+            std::fprintf(stderr, "\nSpecify ");
+            if (request.count < 0)
+            {
+                std::fprintf(stderr, "any number of selections");
+            }
+            else if (request.count == 1)
+            {
+                std::fprintf(stderr, "a selection");
+            }
+            else
+            {
+                std::fprintf(stderr, "%d selections", request.count);
+            }
+            std::fprintf(stderr, " for option '%s' (%s):\n",
+                         request.name.c_str(), request.descr.c_str());
+            std::fprintf(stderr, "(one selection per line, 'help' for help%s)\n",
+                         request.count < 0 ? ", Ctrl-D to end" : "");
+        }
+        std::vector<Selection *> selections;
+        rc = parseFromStdin(request.count, bInteractive, errors, &selections);
+        if (rc != 0)
+        {
+            break;
+        }
+        rc = request.storage->addSelections(selections, true, errors);
+        if (rc != 0)
+        {
+            break;
+        }
+    }
+    _impl->_requests.clear();
+    return rc;
+}
+
+
+int
+SelectionCollection::parseRequestedFromString(const std::string &str,
+                                              AbstractErrorReporter *errors)
+{
+    std::vector<Selection *> selections;
+    int rc = parseFromString(str, errors, &selections);
+    if (rc != 0)
+    {
+        return rc;
+    }
+    std::vector<Selection *>::const_iterator first = selections.begin();
+    std::vector<Selection *>::const_iterator last = first;
+    Impl::RequestList::const_iterator i;
+    for (i = _impl->_requests.begin(); i != _impl->_requests.end(); ++i)
+    {
+        const Impl::SelectionRequest &request = *i;
+        if (request.count > 0)
+        {
+            if (selections.end() - first < request.count)
+            {
+                errors->error("Too few selections provided");
+                rc = eeInvalidInput;
+                break;
+            }
+            last = first + request.count;;
+        }
+        else
+        {
+            if (i != _impl->_requests.end() - 1)
+            {
+                GMX_ERROR_NORET(eeInvalidValue,
+                                "Request for all selections not the last option");
+                rc = eeInvalidValue;
+                break;
+            }
+            last = selections.end();
+        }
+        std::vector<Selection *> curr(first, last);
+        rc = request.storage->addSelections(curr, true, errors);
+        if (rc != 0)
+        {
+            break;
+        }
+        first = last;
+    }
+    _impl->_requests.clear();
+    if (last != selections.end())
+    {
+        errors->error("Too many selections provided");
+        rc = eeInvalidInput;
+    }
+    return rc;
+}
+
+
+int
+SelectionCollection::parseFromStdin(int nr, bool bInteractive,
+                                    AbstractErrorReporter *errors,
+                                    std::vector<Selection *> *output)
+{
+    yyscan_t scanner;
+    int      rc;
+
+    rc = _gmx_sel_init_lexer(&scanner, &_impl->_sc, errors, bInteractive, nr,
+                             _impl->hasFlag(Impl::efExternalGroupsSet),
+                             _impl->_grps);
+    if (rc != 0)
+    {
+        return rc;
+    }
+    /* We don't set the lexer input here, which causes it to use a special
+     * internal implementation for reading from stdin. */
+    return _impl->runParser(scanner, nr, output);
+}
+
+
+int
+SelectionCollection::parseFromFile(const std::string &filename,
+                                   AbstractErrorReporter *errors,
+                                   std::vector<Selection *> *output)
+{
+    yyscan_t scanner;
+    FILE *fp;
+    int   rc;
+
+    rc = _gmx_sel_init_lexer(&scanner, &_impl->_sc, errors, false, -1,
+                             _impl->hasFlag(Impl::efExternalGroupsSet),
+                             _impl->_grps);
+    if (rc != 0)
+    {
+        return rc;
+    }
+    fp = ffopen(filename.c_str(), "r");
+    _gmx_sel_set_lex_input_file(scanner, fp);
+    rc = _impl->runParser(scanner, -1, output);
+    ffclose(fp);
+    return rc;
+}
+
+
+int
+SelectionCollection::parseFromString(const std::string &str,
+                                     AbstractErrorReporter *errors,
+                                     std::vector<Selection *> *output)
+{
+    yyscan_t scanner;
+    int      rc;
+
+    rc = _gmx_sel_init_lexer(&scanner, &_impl->_sc, errors, false, -1,
+                             _impl->hasFlag(Impl::efExternalGroupsSet),
+                             _impl->_grps);
+    if (rc != 0)
+    {
+        return rc;
+    }
+    _gmx_sel_set_lex_input_str(scanner, str.c_str());
+    return _impl->runParser(scanner, -1, output);
+}
+
+
+int
+SelectionCollection::compile()
+{
+    if (!_impl->hasFlag(Impl::efExternalGroupsSet))
+    {
+        int rc = setIndexGroups(NULL);
+        if (rc != 0)
+        {
+            return rc;
+        }
+    }
+    if (_impl->_debugLevel >= 1)
+    {
+        printTree(stderr, false);
+    }
+    int rc = gmx_ana_selcollection_compile(this);
+    if (rc == 0 && _impl->hasFlag(Impl::efOwnPositionCollection))
+    {
+        if (_impl->_debugLevel >= 1)
+        {
+            std::fprintf(stderr, "\n");
+            printTree(stderr, false);
+            std::fprintf(stderr, "\n");
+            gmx_ana_poscalc_coll_print_tree(stderr, _impl->_sc.pcc);
+            std::fprintf(stderr, "\n");
+        }
+        gmx_ana_poscalc_init_eval(_impl->_sc.pcc);
+        if (_impl->_debugLevel >= 1)
+        {
+            gmx_ana_poscalc_coll_print_tree(stderr, _impl->_sc.pcc);
+            std::fprintf(stderr, "\n");
+        }
+    }
+    return rc;
+}
+
+
+int
+SelectionCollection::evaluate(t_trxframe *fr, t_pbc *pbc)
+{
+    if (_impl->hasFlag(Impl::efOwnPositionCollection))
+    {
+        gmx_ana_poscalc_init_frame(_impl->_sc.pcc);
+    }
+    int rc = gmx_ana_selcollection_evaluate(&_impl->_sc, fr, pbc);
+    if (rc == 0 && _impl->_debugLevel >= 3)
+    {
+        std::fprintf(stderr, "\n");
+        printTree(stderr, true);
+    }
+    return rc;
+}
+
+
+int
+SelectionCollection::evaluateFinal(int nframes)
+{
+    return gmx_ana_selcollection_evaluate_fin(&_impl->_sc, nframes);
+}
+
+
+void
+SelectionCollection::printTree(FILE *fp, bool bValues) const
+{
+    t_selelem *sel;
+
+    sel = _impl->_sc.root;
+    while (sel)
+    {
+        _gmx_selelem_print_tree(fp, sel, bValues, 0);
+        sel = sel->next;
+    }
+}
+
+
+void
+SelectionCollection::printXvgrInfo(FILE *out, output_env_t oenv) const
+{
+    int  i;
+
+    if (output_env_get_xvg_format(oenv) != exvgNONE)
+    {
+        gmx_ana_selcollection_t *sc = &_impl->_sc;
+        std::fprintf(out, "# Selections:\n");
+        for (i = 0; i < sc->nvars; ++i)
+        {
+            std::fprintf(out, "#   %s\n", sc->varstrs[i]);
+        }
+        for (i = 0; i < (int)sc->sel.size(); ++i)
+        {
+            std::fprintf(out, "#   %s\n", sc->sel[i]->_sel.selstr);
+        }
+        std::fprintf(out, "#\n");
+    }
+}
+
+} // namespace gmx
diff --git a/src/gromacs/selection/selectioncollection.h b/src/gromacs/selection/selectioncollection.h
new file mode 100644 (file)
index 0000000..d13c8c1
--- /dev/null
@@ -0,0 +1,347 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \libinternal \file
+ * \brief
+ * Declares gmx::SelectionCollection.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \inlibraryapi
+ * \ingroup module_selection
+ */
+#ifndef GMX_SELECTION_SELECTIONCOLLECTION_H
+#define GMX_SELECTION_SELECTIONCOLLECTION_H
+
+#include <string>
+#include <vector>
+
+#include <typedefs.h>
+
+struct gmx_ana_indexgrps_t;
+struct gmx_ana_poscalc_coll_t;
+
+namespace gmx
+{
+
+class AbstractErrorReporter;
+class Options;
+class Selection;
+class SelectionOptionStorage;
+
+/*! \libinternal \brief
+ * Collection of selections.
+ *
+ * Some default values must then be set with
+ * gmx_ana_selcollection_set_refpostype() and
+ * gmx_ana_selcollection_set_outpostype().
+ *
+ * After setting the default values, one or more selections can be parsed
+ * with one or more calls to parseFromStdin(), parseFromFile(), and/or
+ * parseFromString().  After all selections are parsed, the topology must be
+ * set with setTopology() unless requiresTopology() returns false (the topology
+ * can also be set earlier).  Once all selections are parsed, they must be
+ * compiled all at once using compile().
+ * After compilation, dynamic selections have the maximum number of atoms they
+ * can evaluate to, but positions have undefined values.  evaluate() can be
+ * used to update the selections for a new frame.
+ * evaluateFinal() can be called after all the frames have been processed to
+ * restore the selection values back to the ones they were after compile().
+ *
+ * At any point, requiresTopology() can be called to see whether the
+ * information provided so far requires loading the topology.
+ * printTree() can be used to print the internal representation of the
+ * selections (mostly useful for debugging).
+ *
+ * \inlibraryapi
+ * \ingroup module_selection
+ */
+class SelectionCollection
+{
+    public:
+        /*! \brief
+         * Creates an empty selection collection.
+         *
+         * \param[in] pcc  Position calculation collection to use for selection
+         *      evaluation.
+         *
+         * If \p pcc is NULL, an internal collection is created and managed by
+         * the object.
+         */
+        explicit SelectionCollection(gmx_ana_poscalc_coll_t *pcc);
+        ~SelectionCollection();
+
+        /*! \brief
+         * Initializes the object.
+         *
+         * \retval 0 on success.
+         *
+         * Should be called immediately after construction.
+         */
+        int init();
+        /*! \brief
+         * Initializes options for setting global properties on the collection.
+         *
+         * The return value should not be deleted by the caller.
+         */
+        Options *initOptions();
+
+        /*! \brief
+         * Convenience function that creates a new selection collection and
+         * calls init().
+         *
+         * \param[out] scp Pointer to a newly created selection collection.
+         * \param[in]  pcc Position calculation data structure to use for
+         *      selection evaluation.
+         * \returns    0 on success.
+         */
+        static int create(SelectionCollection **scp, gmx_ana_poscalc_coll_t *pcc);
+
+        /*! \brief
+         * Sets the default reference position handling for a selection
+         * collection.
+         *
+         * \param[in]     type      Default selection reference position type
+         *   (one of the strings acceptable for gmx_ana_poscalc_type_from_enum()).
+         *
+         * Should be called before calling the parser functions, unless
+         * initOptions() has been called.  In the latter case, can still be
+         * used to override the default value and/or the value provided through
+         * the Options object.
+         */
+        void setReferencePosType(const char *type);
+        /*! \brief
+         * Sets the default reference position handling for a selection
+         * collection.
+         *
+         * \param[in]     type      Default selection output position type
+         *   (one of the strings acceptable for gmx_ana_poscalc_type_from_enum()).
+         *
+         * Should be called before calling the parser functions, unless
+         * initOptions() has been called.  In the latter case, can still be
+         * used to override the default value and/or the value provided through
+         * the Options object.
+         */
+        void setOutputPosType(const char *type);
+        /*! \brief
+         * Sets the debugging level for the selection collection.
+         */
+        void setDebugLevel(int debuglevel);
+
+        /*! \brief
+         * Returns true if the collection requires topology information for
+         * evaluation.
+         *
+         * \returns true if any selection in the collection requires topology
+         *      information.
+         *
+         * Before the parser functions have been called, the return value is
+         * based just on the position types set.
+         * After parser functions have been called, the return value also takes
+         * into account the selection keywords used.
+         */
+        bool requiresTopology() const;
+        /*! \brief
+         * Sets the topology for the collection.
+         *
+         * \param[in]     top       Topology data.
+         * \param[in]     natoms    Number of atoms. If <=0, the number of
+         *      atoms in the topology is used.
+         * \retval  0 on success.
+         * \retval  ::eeInvalidValue if \p top is NULL and \p natoms <= 0.
+         *
+         * The topology is also set for the position calculation collection
+         * associated with the collection.
+         *
+         * \p natoms determines the largest atom index that can be selected by
+         * the selection: even if the topology contains more atoms, they will
+         * not be selected.
+         */
+        int setTopology(t_topology *top, int natoms);
+        /*! \brief
+         * Sets the external index groups to use for the selections.
+         *
+         * Can be called only once with non-NULL \p grps.
+         */
+        int setIndexGroups(gmx_ana_indexgrps_t *grps);
+        /*! \brief
+         * Parses selection(s) from standard input for options not yet
+         * provided.
+         *
+         * \param[in]  bInteractive Whether the parser should behave
+         *      interactively.
+         * \param[in]  errors       Error reporter object.
+         *
+         * This method cooperates with SelectionOption to allow interactive
+         * input of missing selections after all options have been processed.
+         * It should be called after the Options::finish() method has been
+         * called on all options that add selections to this collection.
+         */
+        int parseRequestedFromStdin(bool bInteractive,
+                                    AbstractErrorReporter *errors);
+        /*! \brief
+         * Parses selection(s) from a string for options not yet provided.
+         *
+         * \param[in]  str     String to parse.
+         * \param[in]  errors  Error reporter object.
+         *
+         * \see parseRequestedFromStdin()
+         */
+        int parseRequestedFromString(const std::string &str,
+                                     AbstractErrorReporter *errors);
+        /*! \brief
+         * Parses selection(s) from standard input.
+         *
+         * \param[in]  count    Number of selections to parse
+         *      (if -1, parse as many as provided by the user).
+         * \param[in]  bInteractive Whether the parser should behave
+         *      interactively.
+         * \param[in]  errors   Error reporter object.
+         * \param[out] output   Vector to which parsed selections are appended.
+         * \retval     0 on success.
+         * \retval     ::eeInvalidInput on syntax error (an interactive parser
+         *      only returns this if an incorrect number of selections is
+         *      provided).
+         *
+         * Parsed selections are appended to \p output without clearing it
+         * first.  If parsing fails, \p output is not modified.
+         *
+         * The objects returned in \p output remain valid for the lifetime of
+         * the selection collection, and should not be freed by the user.
+         * Some information about the selections only becomes available once
+         * compile() has been called.
+         */
+        int parseFromStdin(int count, bool bInteractive,
+                           AbstractErrorReporter *errors,
+                           std::vector<Selection *> *output);
+        /*! \brief
+         * Parses selection(s) from a file.
+         *
+         * \param[in]  filename Name of the file to parse selections from.
+         * \param[in]  errors   Error reporter object.
+         * \param[out] output   Vector to which parsed selections are appended.
+         * \retval     0 on success.
+         * \retval     ::eeInvalidInput on syntax error.
+         *
+         * Parsed selections are appended to \p output without clearing it
+         * first.  If parsing fails, \p output is not modified.
+         *
+         * The objects returned in \p output remain valid for the lifetime of
+         * the selection collection, and should not be freed by the user.
+         * Some information about the selections only becomes available once
+         * compile() has been called.
+         */
+        int parseFromFile(const std::string &filename,
+                          AbstractErrorReporter *errors,
+                          std::vector<Selection *> *output);
+        /*! \brief
+         * Parses selection(s) from a string.
+         *
+         * \param[in]  str      String to parse selections from.
+         * \param[in]  errors   Error reporter object.
+         * \param[out] output   Vector to which parsed selections are appended.
+         * \retval     0 on success.
+         * \retval     ::eeInvalidInput on syntax error.
+         *
+         * Parsed selections are appended to \p output without clearing it
+         * first.  If parsing fails, \p output is not modified.
+         *
+         * The objects returned in \p output remain valid for the lifetime of
+         * the selection collection, and should not be freed by the user.
+         * Some information about the selections only becomes available once
+         * compile() has been called.
+         */
+        int parseFromString(const std::string &str,
+                            AbstractErrorReporter *errors,
+                            std::vector<Selection *> *output);
+        /*! \brief
+         * Prepares the selections for evaluation and performs optimizations.
+         *
+         * \retval  0 on successful compilation, a non-zero error code on error.
+         *
+         * Before compilation, selections should have been added to the
+         * collection using the parseFrom*() functions.
+         * The compiled selection collection can be passed to evaluate() to
+         * evaluate the selection for a frame.
+         * If an error occurs, the collection is cleared.
+         *
+         * The covered fraction information is initialized to ::CFRAC_NONE for
+         * all selections.
+         */
+        int compile();
+        /*! \brief
+         * Evaluates selections in the collection.
+         *
+         * \param[in] fr  Frame for which the evaluation should be carried out.
+         * \param[in] pbc PBC data, or NULL if no PBC should be used.
+         * \returns   0 on successful evaluation, a non-zero error code on error.
+         */
+        int evaluate(t_trxframe *fr, t_pbc *pbc);
+        /*! \brief
+         * Evaluates the largest possible index groups from dynamic selections.
+         *
+         * \param[in] nframes Total number of frames.
+         * \returns   0 on successful evaluation, a non-zero error code on error.
+         */
+        int evaluateFinal(int nframes);
+
+        /*! \brief
+         * Prints a human-readable version of the internal selection element
+         * tree.
+         *
+         * \param[in] fp      File handle to receive the output.
+         * \param[in] bValues If true, the evaluated values of selection
+         *      elements are printed as well.
+         */
+        void printTree(FILE *fp, bool bValues) const;
+        /*! \brief
+         * Prints the selection strings into an XVGR file as comments.
+         *
+         * \param[in] fp   Output file.
+         * \param[in] oenv Output options structure.
+         */
+        void printXvgrInfo(FILE *fp, output_env_t oenv) const;
+
+        class Impl;
+        Impl                   *_impl;
+
+    private:
+        /*! \brief
+         * Needed for handling delayed selection parsing requests.
+         */
+        friend class SelectionOptionStorage;
+
+        // Disallow copy and assign.
+        SelectionCollection(const SelectionCollection &);
+        void operator =(const SelectionCollection &);
+};
+
+} // namespace gmx
+
+#endif
diff --git a/src/gromacs/selection/selectionenums.h b/src/gromacs/selection/selectionenums.h
new file mode 100644 (file)
index 0000000..cdbd201
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \file
+ * \brief
+ * Declares common types used in selections.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_selection
+ */
+#ifndef GMX_SELECTION_SELECTIONENUMS_H
+#define GMX_SELECTION_SELECTIONENUMS_H
+
+#include "../utility/flags.h"
+
+/*! \brief
+ * Defines the type of covered fraction.
+ *
+ * \inpublicapi
+ */
+typedef enum
+{
+    CFRAC_NONE,         /**< No covered fraction (everything covered). */
+    CFRAC_SOLIDANGLE    /**< Fraction of a solid (3D) angle covered. */
+} e_coverfrac_t;
+
+namespace gmx
+{
+
+/*! \brief
+ * Flags for options.
+ *
+ * These flags are not part of the public interface, even though they are in an
+ * installed header.  They are needed in the implementation of SelectionOption.
+ */
+enum SelectionFlag
+{
+    efOnlyStatic        = 1<<0,
+    efOnlyAtoms         = 1<<1,
+    //! Whether ::POS_MASKONLY should be used for output position evaluation.
+    efDynamicMask       = 1<<2,
+    efDynamicOnlyWhole  = 1<<3,
+    //! Whether velocities of output positions should be evaluated.
+    efEvaluateVelocities        = 1<<5,
+    //! Whether forces on output positions should be evaluated.
+    efEvaluateForces            = 1<<6,
+};
+
+//! Holds a collection of ::SelectionFlag values.
+typedef FlagsTemplate<SelectionFlag> SelectionFlags;
+
+}
+
+#endif
diff --git a/src/gromacs/selection/selectionoption.cpp b/src/gromacs/selection/selectionoption.cpp
new file mode 100644 (file)
index 0000000..831ed1d
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * Implements gmx::SelectionOption.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_selection
+ */
+#include "gromacs/selection/selectionoption.h"
+
+#include "selectionoptionstorage.h"
+
+namespace gmx
+{
+
+int SelectionOption::createDefaultStorage(Options *options,
+                                          AbstractOptionStorage **storage) const
+{
+    return createOptionStorage<SelectionOption, SelectionOptionStorage>(this, options, storage);
+}
+
+} // namespace gmx
diff --git a/src/gromacs/selection/selectionoption.h b/src/gromacs/selection/selectionoption.h
new file mode 100644 (file)
index 0000000..0feb77d
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \file
+ * \brief
+ * Declares gmx::SelectionOption.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \inpublicapi
+ * \ingroup module_selection
+ */
+#ifndef GMX_SELECTION_SELECTIONOPTION_H
+#define GMX_SELECTION_SELECTIONOPTION_H
+
+#include "../options/abstractoption.h"
+#include "selectionenums.h"
+
+namespace gmx
+{
+
+class Selection;
+class SelectionOptionStorage;
+
+/*! \brief
+ * Specifies an option that provides selection(s).
+ *
+ * \inpublicapi
+ * \ingroup module_selection
+ */
+class SelectionOption : public OptionTemplate<Selection *, SelectionOption>
+{
+    public:
+        //! Initializes an option with the given name.
+        explicit SelectionOption(const char *name) : MyBase(name)
+        { }
+
+        /*! \brief
+         * Request velocity evaluation for output positions.
+         */
+        MyClass &evaluateVelocities()
+        { _selectionFlags.set(efEvaluateVelocities); return me(); }
+        /*! \brief
+         * Request force evaluation for output positions.
+         */
+        MyClass &evaluateForces()
+        { _selectionFlags.set(efEvaluateForces); return me(); }
+        /*! \brief
+         * Only accept selections that evaluate to atom positions.
+         *
+         * TODO: This option is not yet implemented.
+         */
+        MyClass &onlyAtoms()
+        { _selectionFlags.set(efOnlyAtoms); return me(); }
+        /*! \brief
+         * Only accept static selections for this option.
+         */
+        MyClass &onlyStatic()
+        { _selectionFlags.set(efOnlyStatic); return me(); }
+        /*! \brief
+         * Handle dynamic selections for this option with position masks.
+         *
+         * Sets ::POS_MASKONLY on the positions for this selection.
+         */
+        MyClass &dynamicMask()
+        { _selectionFlags.set(efDynamicMask); return me(); }
+        /*! \brief
+         * Disallow using atom coordinates as the reference positions.
+         *
+         * TODO: This option is not yet implemented.
+         */
+        MyClass &dynamicOnlyWhole()
+        { _selectionFlags.set(efDynamicOnlyWhole); return me(); }
+
+    private:
+        // Disable default value because it is impossible to provide a
+        // Selection object.
+        using MyBase::defaultValue;
+
+        virtual int createDefaultStorage(Options *options,
+                                         AbstractOptionStorage **storage) const;
+
+        SelectionFlags          _selectionFlags;
+
+        /*! \brief
+         * Needed to initialize SelectionOptionStorage from this class without
+         * otherwise unnecessary accessors.
+         */
+        friend class SelectionOptionStorage;
+};
+
+} // namespace gmx
+
+#endif
diff --git a/src/gromacs/selection/selectionoptionstorage.cpp b/src/gromacs/selection/selectionoptionstorage.cpp
new file mode 100644 (file)
index 0000000..5898857
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * Implements gmx::SelectionOptionStorage.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_selection
+ */
+#include "selectionoptionstorage.h"
+
+#include <cassert>
+
+#include <string>
+#include <vector>
+
+#include "gromacs/errorreporting/abstracterrorreporter.h"
+#include "gromacs/fatalerror/fatalerror.h"
+#include "gromacs/options/globalproperties.h"
+#include "gromacs/options/options.h"
+#include "gromacs/selection/selection.h"
+#include "gromacs/selection/selectioncollection.h"
+#include "gromacs/selection/selectionoption.h"
+
+#include "selectioncollection-impl.h"
+
+namespace gmx
+{
+
+/********************************************************************
+ * SelectionOptionStorage
+ */
+
+SelectionOptionStorage::SelectionOptionStorage()
+{
+    MyBase::setFlag(efNoDefaultValue);
+    MyBase::setFlag(efConversionMayNotAddValues);
+    MyBase::setFlag(efDontCheckMinimumCount);
+}
+
+
+int SelectionOptionStorage::init(const SelectionOption &settings,
+                                 Options *options)
+{
+    _selectionFlags = settings._selectionFlags;
+    options->globalProperties().request(eogpSelectionCollection);
+    return MyBase::init(settings, options);
+}
+
+
+std::string SelectionOptionStorage::formatValue(int i) const
+{
+    Selection *sel = values().at(i);
+    return (sel != NULL ? sel->selectionText() : "");
+}
+
+
+int SelectionOptionStorage::addSelections(
+        const std::vector<Selection *> &selections,
+        bool bFullValue, AbstractErrorReporter *errors)
+{
+    if (bFullValue && selections.size() < static_cast<size_t>(minValueCount()))
+    {
+        errors->error("Too few selections provided");
+        return eeInvalidInput;
+    }
+    std::vector<Selection *>::const_iterator i;
+    for (i = selections.begin(); i != selections.end(); ++i)
+    {
+        // TODO: Having this check in the parser would make interactive input
+        // behave better.
+        if (_selectionFlags.test(efOnlyStatic) && (*i)->isDynamic())
+        {
+            errors->error("Dynamic selections not supported");
+            return eeInvalidInput;
+        }
+        (*i)->setFlags(_selectionFlags);
+        int rc = addValue(*i);
+        if (rc != 0)
+        {
+            return rc;
+        }
+    }
+    if (bFullValue)
+    {
+        processValues(selections.size(), true);
+    }
+    return 0;
+}
+
+
+int SelectionOptionStorage::convertValue(const std::string &value,
+                                         AbstractErrorReporter *errors)
+{
+    SelectionCollection *sc =
+        hostOptions().globalProperties().selectionCollection();
+    assert(sc != NULL);
+
+    std::vector<Selection *> selections;
+    // TODO: Implement reading from a file.
+    int rc = sc->parseFromString(value, errors, &selections);
+    if (rc == 0)
+    {
+        rc = addSelections(selections, false, errors);
+    }
+    return rc;
+}
+
+int SelectionOptionStorage::processSet(int nvalues,
+                                       AbstractErrorReporter *errors)
+{
+    if (nvalues > 0 && nvalues < minValueCount())
+    {
+        // TODO: Remove the invalid values
+        errors->error("Too few (valid) values provided");
+        return eeInvalidInput;
+    }
+    return MyBase::processSet(nvalues, errors);
+}
+
+int SelectionOptionStorage::processAll(AbstractErrorReporter *errors)
+{
+    if ((hasFlag(efRequired) || hasFlag(efSet)) && valueCount() == 0)
+    {
+        SelectionCollection *sc =
+            hostOptions().globalProperties().selectionCollection();
+        assert(sc != NULL);
+
+        sc->_impl->requestSelections(name(), description(),
+                                     maxValueCount(), this);
+        setFlag(efSet);
+    }
+    return MyBase::processAll(errors);
+}
+
+} // namespace gmx
diff --git a/src/gromacs/selection/selectionoptionstorage.h b/src/gromacs/selection/selectionoptionstorage.h
new file mode 100644 (file)
index 0000000..abc1435
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * Declares gmx::SelectionOptionStorage.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_selection
+ */
+#ifndef GMX_SELECTION_SELECTIONOPTIONSTORAGE_H
+#define GMX_SELECTION_SELECTIONOPTIONSTORAGE_H
+
+#include "../options/optionstoragetemplate.h"
+#include "selectionenums.h"
+
+namespace gmx
+{
+
+class Selection;
+class SelectionOption;
+
+/*! \internal \brief
+ * Converts, validates, and stores selection values.
+ *
+ * \ingroup module_selection
+ */
+class SelectionOptionStorage : public OptionStorageTemplate<Selection *>
+{
+    public:
+        SelectionOptionStorage();
+
+        /*! \brief
+         * Initializes the storage from option settings.
+         *
+         * \param[in] settings   Storage settings.
+         * \param[in] options    Options object.
+         * \retval 0 on success.
+         */
+        int init(const SelectionOption &settings, Options *options);
+
+        virtual const char *typeString() const { return "sel"; }
+        virtual std::string formatValue(int i) const;
+
+        /*! \brief
+         * Adds selections to the storage.
+         *
+         * \param[in] selections  List of selections to add.
+         * \param[in] bFullValue  If true, the provided selections are the full
+         *      value of the option, and additional checks are performed.
+         * \param[in] errors      Error reporter object.
+         *
+         * This function is used to implement the methods
+         * SelectionCollection::parseRequestedFromStdin() and
+         * SelectionCollection::parseRequestedFromString() (called with
+         * \p bFullValue set to true), as well as internally by the storage
+         * class (called with \p bFullValue set to false).
+         */
+        int addSelections(const std::vector<Selection *> &selections,
+                          bool bFullValue, AbstractErrorReporter *errors);
+
+    private:
+        virtual int convertValue(const std::string &value,
+                                 AbstractErrorReporter *errors);
+        virtual int processSet(int nvalues, AbstractErrorReporter *errors);
+        virtual int processAll(AbstractErrorReporter *errors);
+
+        SelectionFlags          _selectionFlags;
+};
+
+} // namespace gmx
+
+#endif
diff --git a/src/gromacs/selection/selelem.cpp b/src/gromacs/selection/selelem.cpp
new file mode 100644 (file)
index 0000000..6393937
--- /dev/null
@@ -0,0 +1,694 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * Implements functions in selelem.h.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_selection
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <smalloc.h>
+#include <gmx_fatal.h>
+
+#include "gromacs/selection/indexutil.h"
+#include "gromacs/selection/poscalc.h"
+#include "gromacs/selection/position.h"
+#include "gromacs/selection/selmethod.h"
+
+#include "keywords.h"
+#include "mempool.h"
+#include "selelem.h"
+
+/*!
+ * \param[in] sel Selection for which the string is requested
+ * \returns   Pointer to a string that corresponds to \p sel->type.
+ *
+ * The return value points to a string constant and should not be \p free'd.
+ * 
+ * The function returns NULL if \p sel->type is not one of the valid values.
+ */
+const char *
+_gmx_selelem_type_str(t_selelem *sel)
+{
+    switch (sel->type)
+    {
+        case SEL_CONST:      return "CONST";
+        case SEL_EXPRESSION: return "EXPR";
+        case SEL_BOOLEAN:    return "BOOL";
+        case SEL_ARITHMETIC: return "ARITH";
+        case SEL_ROOT:       return "ROOT";
+        case SEL_SUBEXPR:    return "SUBEXPR";
+        case SEL_SUBEXPRREF: return "REF";
+        case SEL_GROUPREF:   return "GROUPREF";
+        case SEL_MODIFIER:   return "MODIFIER";
+    }
+    return NULL;
+}
+
+/*!
+ * \param[in] val Value structore for which the string is requested.
+ * \returns   Pointer to a string that corresponds to \p val->type,
+ *   NULL if the type value is invalid.
+ *
+ * The return value points to a string constant and should not be \p free'd.
+ */
+const char *
+_gmx_sel_value_type_str(gmx_ana_selvalue_t *val)
+{
+    switch (val->type)
+    {
+        case NO_VALUE:       return "NONE";
+        case INT_VALUE:      return "INT";
+        case REAL_VALUE:     return "REAL";
+        case STR_VALUE:      return "STR";
+        case POS_VALUE:      return "VEC";
+        case GROUP_VALUE:    return "GROUP";
+    }
+    return NULL;
+}
+
+/*! \copydoc _gmx_selelem_type_str() */
+const char *
+_gmx_selelem_gmx_boolean_type_str(t_selelem *sel)
+{
+    switch (sel->u.boolt)
+    {
+        case BOOL_NOT:  return "NOT"; break;
+        case BOOL_AND:  return "AND"; break;
+        case BOOL_OR:   return "OR";  break;
+        case BOOL_XOR:  return "XOR"; break;
+    }
+    return NULL;
+}
+
+/*!
+ * \param[in] type Type of selection element to allocate.
+ * \returns   Pointer to the newly allocated and initialized element.
+ *
+ * \c t_selelem::type is set to \p type,
+ * \c t_selelem::v::type is set to \ref GROUP_VALUE for gmx_boolean and comparison
+ * expressions and \ref NO_VALUE for others,
+ * \ref SEL_ALLOCVAL is set for non-root elements (\ref SEL_ALLOCDATA is also
+ * set for \ref SEL_BOOLEAN elements),
+ * and \c t_selelem::refcount is set to one.
+ * All the pointers are set to NULL.
+ */
+t_selelem *
+_gmx_selelem_create(e_selelem_t type)
+{
+    t_selelem *sel;
+
+    snew(sel, 1);
+    sel->name       = NULL;
+    sel->type       = type;
+    sel->flags      = (type != SEL_ROOT) ? SEL_ALLOCVAL : 0;
+    if (type == SEL_BOOLEAN)
+    {
+        sel->v.type = GROUP_VALUE;
+        sel->flags |= SEL_ALLOCDATA;
+    }
+    else
+    {
+        sel->v.type = NO_VALUE;
+    }
+    _gmx_selvalue_clear(&sel->v);
+    sel->evaluate   = NULL;
+    sel->mempool    = NULL;
+    sel->child      = NULL;
+    sel->next       = NULL;
+    sel->refcount   = 1;
+
+    return sel;
+}
+
+/*!
+ * \param[in,out] sel   Selection element to set the type for.
+ * \param[in]     vtype Value type for the selection element.
+ * \returns       0 on success, EINVAL if the value type is invalid.
+ *
+ * If the new type is \ref GROUP_VALUE or \ref POS_VALUE, the
+ * \ref SEL_ALLOCDATA flag is also set.
+ *
+ * This function should only be called at most once for each element,
+ * preferably right after calling _gmx_selelem_create().
+ */
+int
+_gmx_selelem_set_vtype(t_selelem *sel, e_selvalue_t vtype)
+{
+    if (sel->type == SEL_BOOLEAN && vtype != GROUP_VALUE)
+    {
+        gmx_bug("internal error");
+        return EINVAL;
+    }
+    if (sel->v.type != NO_VALUE && vtype != sel->v.type)
+    {
+        gmx_call("_gmx_selelem_set_vtype() called more than once");
+        return EINVAL;
+    }
+    sel->v.type = vtype;
+    if (vtype == GROUP_VALUE || vtype == POS_VALUE)
+    {
+        sel->flags |= SEL_ALLOCDATA;
+    }
+    return 0;
+}
+
+/*!
+ * \param[in,out] sel   Selection element to reserve.
+ * \param[in]     count Number of values to reserve memory for.
+ * \returns       0 on success or if no memory pool, non-zero on error.
+ *
+ * Reserves memory for the values of \p sel from the \p sel->mempool
+ * memory pool. If no memory pool is set, nothing is done.
+ */
+int
+_gmx_selelem_mempool_reserve(t_selelem *sel, int count)
+{
+    int rc = 0;
+
+    if (!sel->mempool)
+    {
+        return 0;
+    }
+    switch (sel->v.type)
+    {
+        case INT_VALUE:
+            rc = _gmx_sel_mempool_alloc(sel->mempool, (void **)&sel->v.u.i,
+                                        sizeof(*sel->v.u.i)*count);
+            break;
+
+        case REAL_VALUE:
+            rc = _gmx_sel_mempool_alloc(sel->mempool, (void **)&sel->v.u.r,
+                                        sizeof(*sel->v.u.r)*count);
+            break;
+
+        case GROUP_VALUE:
+            rc = _gmx_sel_mempool_alloc_group(sel->mempool, sel->v.u.g, count);
+            break;
+
+        default:
+            gmx_incons("mem pooling not implemented for requested type");
+            return -1;
+    }
+    return rc;
+}
+
+/*!
+ * \param[in,out] sel   Selection element to release.
+ *
+ * Releases the memory allocated for the values of \p sel from the
+ * \p sel->mempool memory pool. If no memory pool is set, nothing is done.
+ */
+void
+_gmx_selelem_mempool_release(t_selelem *sel)
+{
+    if (!sel->mempool)
+    {
+        return;
+    }
+    switch (sel->v.type)
+    {
+        case INT_VALUE:
+        case REAL_VALUE:
+            _gmx_sel_mempool_free(sel->mempool, sel->v.u.ptr);
+            _gmx_selvalue_setstore(&sel->v, NULL);
+            break;
+
+        case GROUP_VALUE:
+            if (sel->v.u.g)
+            {
+                _gmx_sel_mempool_free_group(sel->mempool, sel->v.u.g);
+            }
+            break;
+
+        default:
+            gmx_incons("mem pooling not implemented for requested type");
+            break;
+    }
+}
+
+/*!
+ * \param[in] sel Selection to free.
+ */
+void
+_gmx_selelem_free_values(t_selelem *sel)
+{
+    int   i, n;
+
+    _gmx_selelem_mempool_release(sel);
+    if ((sel->flags & SEL_ALLOCDATA) && sel->v.u.ptr)
+    {
+        /* The number of position/group structures is constant, so the
+         * backup of using sel->v.nr should work for them.
+         * For strings, we report an error if we don't know the allocation
+         * size here. */
+        n = (sel->v.nalloc > 0) ? sel->v.nalloc : sel->v.nr;
+        switch (sel->v.type)
+        {
+            case STR_VALUE:
+                if (sel->v.nalloc == 0)
+                {
+                    gmx_bug("SEL_ALLOCDATA should only be set for allocated STR_VALUE values");
+                    break;
+                }
+                for (i = 0; i < n; ++i)
+                {
+                    sfree(sel->v.u.s[i]);
+                }
+                break;
+            case POS_VALUE:
+                for (i = 0; i < n; ++i)
+                {
+                    gmx_ana_pos_deinit(&sel->v.u.p[i]);
+                }
+                break;
+            case GROUP_VALUE:
+                for (i = 0; i < n; ++i)
+                {
+                    gmx_ana_index_deinit(&sel->v.u.g[i]);
+                }
+                break;
+            default: /* No special handling for other types */
+                break;
+        }
+    }
+    if (sel->flags & SEL_ALLOCVAL)
+    {
+        sfree(sel->v.u.ptr);
+    }
+    _gmx_selvalue_setstore(&sel->v, NULL);
+    if (sel->type == SEL_SUBEXPRREF && sel->u.param)
+    {
+        sel->u.param->val.u.ptr = NULL;
+    }
+}
+
+/*!
+ * \param[in] method Method to free.
+ * \param[in] mdata  Method data to free.
+ */
+void
+_gmx_selelem_free_method(gmx_ana_selmethod_t *method, void *mdata)
+{
+    sel_freefunc free_func = NULL;
+
+    /* Save the pointer to the free function. */
+    if (method && method->free)
+    {
+        free_func = method->free;
+    }
+
+    /* Free the method itself.
+     * Has to be done before freeing the method data, because parameter
+     * values are typically stored in the method data, and here we may
+     * access them. */
+    if (method)
+    {
+        int  i, j;
+
+        /* Free the memory allocated for the parameters that are not managed
+         * by the selection method itself. */
+        for (i = 0; i < method->nparams; ++i)
+        {
+            gmx_ana_selparam_t *param = &method->param[i];
+
+            if (param->val.u.ptr)
+            {
+                if (param->val.type == GROUP_VALUE)
+                {
+                    for (j = 0; j < param->val.nr; ++j)
+                    {
+                        gmx_ana_index_deinit(&param->val.u.g[j]);
+                    }
+                }
+                else if (param->val.type == POS_VALUE)
+                {
+                    for (j = 0; j < param->val.nr; ++j)
+                    {
+                        gmx_ana_pos_deinit(&param->val.u.p[j]);
+                    }
+                }
+
+                if (param->val.nalloc > 0)
+                {
+                    sfree(param->val.u.ptr);
+                }
+            }
+        }
+        sfree(method->param);
+        sfree(method);
+    }
+    /* Free method data. */
+    if (mdata)
+    {
+        if (free_func)
+        {
+            free_func(mdata);
+        }
+        sfree(mdata);
+    }
+}
+
+/*!
+ * \param[in] sel Selection to free.
+ */
+void
+_gmx_selelem_free_exprdata(t_selelem *sel)
+{
+    if (sel->type == SEL_EXPRESSION || sel->type == SEL_MODIFIER)
+    {
+        _gmx_selelem_free_method(sel->u.expr.method, sel->u.expr.mdata);
+        sel->u.expr.mdata = NULL;
+        sel->u.expr.method = NULL;
+        /* Free position data */
+        if (sel->u.expr.pos)
+        {
+            gmx_ana_pos_free(sel->u.expr.pos);
+            sel->u.expr.pos = NULL;
+        }
+        /* Free position calculation data */
+        if (sel->u.expr.pc)
+        {
+            gmx_ana_poscalc_free(sel->u.expr.pc);
+            sel->u.expr.pc = NULL;
+        }
+    }
+    if (sel->type == SEL_ARITHMETIC)
+    {
+        sfree(sel->u.arith.opstr);
+        sel->u.arith.opstr = NULL;
+    }
+    if (sel->type == SEL_SUBEXPR || sel->type == SEL_ROOT
+        || (sel->type == SEL_CONST && sel->v.type == GROUP_VALUE))
+    {
+        gmx_ana_index_deinit(&sel->u.cgrp);
+    }
+    if (sel->type == SEL_GROUPREF)
+    {
+        sfree(sel->u.gref.name);
+    }
+}
+
+/*!
+ * \param[in] sel Selection to free.
+ *
+ * Decrements \ref t_selelem::refcount "sel->refcount" and frees the
+ * memory allocated for \p sel and all its children if the reference count
+ * reaches zero.
+ */
+void
+_gmx_selelem_free(t_selelem *sel)
+{
+    /* Decrement the reference counter and do nothing if references remain */
+    sel->refcount--;
+    if (sel->refcount > 0)
+    {
+        return;
+    }
+
+    /* Free the children.
+     * Must be done before freeing other data, because the children may hold
+     * references to data in this element. */
+    _gmx_selelem_free_chain(sel->child);
+
+    /* Free value storage */
+    _gmx_selelem_free_values(sel);
+
+    /* Free other storage */
+    _gmx_selelem_free_exprdata(sel);
+
+    /* Free temporary compiler data if present */
+    _gmx_selelem_free_compiler_data(sel);
+
+    sfree(sel);
+}
+
+/*!
+ * \param[in] first First selection to free.
+ *
+ * Frees \p first and all selections accessible through the
+ * \ref t_selelem::next "first->next" pointer.
+ */
+void
+_gmx_selelem_free_chain(t_selelem *first)
+{
+    t_selelem *child, *prev;
+
+    child = first;
+    while (child)
+    {
+        prev = child;
+        child = child->next;
+        _gmx_selelem_free(prev);
+    }
+}
+
+/*!
+ * \param[in] fp      File handle to receive the output.
+ * \param[in] sel     Root of the selection subtree to print.
+ * \param[in] bValues If TRUE, the evaluated values of selection elements
+ *   are printed as well.
+ * \param[in] level   Indentation level, starting from zero.
+ */
+void
+_gmx_selelem_print_tree(FILE *fp, t_selelem *sel, gmx_bool bValues, int level)
+{
+    t_selelem *child;
+    int          i;
+
+    fprintf(fp, "%*c %s %s", level*2+1, '*',
+            _gmx_selelem_type_str(sel), _gmx_sel_value_type_str(&sel->v));
+    if (sel->name)
+    {
+        fprintf(fp, " \"%s\"", sel->name);
+    }
+    fprintf(fp, " flg=");
+    if (sel->flags & SEL_FLAGSSET)
+    {
+        fprintf(fp, "s");
+    }
+    if (sel->flags & SEL_SINGLEVAL)
+    {
+        fprintf(fp, "S");
+    }
+    if (sel->flags & SEL_ATOMVAL)
+    {
+        fprintf(fp, "A");
+    }
+    if (sel->flags & SEL_VARNUMVAL)
+    {
+        fprintf(fp, "V");
+    }
+    if (sel->flags & SEL_DYNAMIC)
+    {
+        fprintf(fp, "D");
+    }
+    if (!(sel->flags & SEL_VALFLAGMASK))
+    {
+        fprintf(fp, "0");
+    }
+    if (sel->mempool)
+    {
+        fprintf(fp, "P");
+    }
+    if (sel->type == SEL_CONST)
+    {
+        if (sel->v.type == INT_VALUE)
+        {
+            fprintf(fp, " %d", sel->v.u.i[0]);
+        }
+        else if (sel->v.type == REAL_VALUE)
+        {
+            fprintf(fp, " %f", sel->v.u.r[0]);
+        }
+        else if (sel->v.type == GROUP_VALUE)
+        {
+            gmx_ana_index_t *g = sel->v.u.g;
+            if (!g || g->isize == 0)
+                g = &sel->u.cgrp;
+            fprintf(fp, " (%d atoms)", g->isize);
+        }
+    }
+    else if (sel->type == SEL_BOOLEAN)
+    {
+        fprintf(fp, " %s", _gmx_selelem_gmx_boolean_type_str(sel));
+    }
+    else if (sel->type == SEL_EXPRESSION
+             && sel->u.expr.method->name == sm_compare.name)
+    {
+        _gmx_selelem_print_compare_info(fp, sel->u.expr.mdata);
+    }
+    if (sel->evaluate)
+    {
+        fprintf(fp, " eval=");
+        _gmx_sel_print_evalfunc_name(fp, sel->evaluate);
+    }
+    if (sel->refcount > 1)
+    {
+        fprintf(fp, " refc=%d", sel->refcount);
+    }
+    if (!(sel->flags & SEL_ALLOCVAL))
+    {
+        fprintf(fp, " (ext. output)");
+    }
+    fprintf(fp, "\n");
+
+    if ((sel->type == SEL_CONST && sel->v.type == GROUP_VALUE) || sel->type == SEL_ROOT)
+    {
+        gmx_ana_index_t *g = sel->v.u.g;
+        if (!g || g->isize == 0 || sel->evaluate != NULL)
+        {
+            g = &sel->u.cgrp;
+        }
+        if (g->isize < 0)
+        {
+            fprintf(fp, "%*c group: (null)\n", level*2+1, ' ');
+        }
+        else if (g->isize > 0)
+        {
+            fprintf(fp, "%*c group:", level*2+1, ' ');
+            if (g->isize <= 20)
+            {
+                for (i = 0; i < g->isize; ++i)
+                {
+                    fprintf(fp, " %d", g->index[i] + 1);
+                }
+            }
+            else
+            {
+                fprintf(fp, " %d atoms", g->isize);
+            }
+            fprintf(fp, "\n");
+        }
+    }
+    else if (sel->type == SEL_EXPRESSION)
+    {
+        if (sel->u.expr.pc)
+        {
+            fprintf(fp, "%*c COM", level*2+3, '*');
+            fprintf(fp, "\n");
+        }
+    }
+
+    if (sel->cdata)
+    {
+        _gmx_selelem_print_compiler_info(fp, sel, level);
+    }
+
+    if (bValues && sel->type != SEL_CONST && sel->type != SEL_ROOT && sel->v.u.ptr)
+    {
+        fprintf(fp, "%*c value: ", level*2+1, ' ');
+        switch (sel->v.type)
+        {
+            case POS_VALUE:
+                /* In normal use, the pointer should never be NULL, but it's
+                 * useful to have the check for debugging to avoid accidental
+                 * segfaults when printing the selection tree. */
+                if (sel->v.u.p->x)
+                {
+                    fprintf(fp, "(%f, %f, %f)",
+                            sel->v.u.p->x[0][XX], sel->v.u.p->x[0][YY],
+                            sel->v.u.p->x[0][ZZ]);
+                }
+                else
+                {
+                    fprintf(fp, "(null)");
+                }
+                break;
+            case GROUP_VALUE:
+                fprintf(fp, "%d atoms", sel->v.u.g->isize);
+                if (sel->v.u.g->isize < 20)
+                {
+                    if (sel->v.u.g->isize > 0)
+                    {
+                        fprintf(fp, ":");
+                    }
+                    for (i = 0; i < sel->v.u.g->isize; ++i)
+                    {
+                        fprintf(fp, " %d", sel->v.u.g->index[i] + 1);
+                    }
+                }
+                break;
+            default:
+                fprintf(fp, "???");
+                break;
+        }
+        fprintf(fp, "\n");
+    }
+
+    /* Print the subexpressions with one more level of indentation */
+    child = sel->child;
+    while (child)
+    {
+        if (!(sel->type == SEL_SUBEXPRREF && child->type == SEL_SUBEXPR))
+        {
+            _gmx_selelem_print_tree(fp, child, bValues, level+1);
+        }
+        child = child->next;
+    }
+}
+
+/*!
+ * \param[in] root Root of the subtree to query.
+ * \returns TRUE if \p root or any any of its elements require topology
+ *   information, FALSE otherwise.
+ */
+gmx_bool
+_gmx_selelem_requires_top(t_selelem *root)
+{
+    t_selelem *child;
+
+    if (root->type == SEL_EXPRESSION || root->type == SEL_MODIFIER)
+    {
+        if (root->u.expr.method && (root->u.expr.method->flags & SMETH_REQTOP))
+        {
+            return TRUE;
+        }
+        if (root->u.expr.pc && gmx_ana_poscalc_requires_top(root->u.expr.pc))
+        {
+            return TRUE;
+        }
+    }
+    child = root->child;
+    while (child)
+    {
+        if (_gmx_selelem_requires_top(child))
+        {
+            return TRUE;
+        }
+        child = child->next;
+    }
+    return FALSE;
+}
diff --git a/src/gromacs/selection/selelem.h b/src/gromacs/selection/selelem.h
new file mode 100644 (file)
index 0000000..9740aa8
--- /dev/null
@@ -0,0 +1,384 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * Declares ::t_selelem and related things.
+ *
+ * The selection element trees constructed by the parser and the compiler
+ * are described on the respective pages:
+ * \ref page_module_selection_parser and \ref page_module_selection_compiler.
+ *
+ * This is an implementation header: there should be no need to use it outside
+ * this directory.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_selection
+ */
+#ifndef SELECTION_ELEMENT_H
+#define SELECTION_ELEMENT_H
+
+#include <types/simple.h>
+
+#include "gromacs/selection/indexutil.h"
+#include "gromacs/selection/selvalue.h"
+
+struct gmx_ana_poscalc_t;
+struct gmx_ana_selparam_t;
+struct gmx_ana_selmethod_t;
+
+struct gmx_sel_evaluate_t;
+struct gmx_sel_mempool_t;
+struct t_selelem;
+
+/********************************************************************/
+/*! \name Enumerations for expression types
+ ********************************************************************/
+/*@{*/
+
+/** Defines the type of a \c t_selelem object. */
+typedef enum
+{
+    /** Constant-valued expression. */
+    SEL_CONST,
+    /** Method expression that requires evaluation. */
+    SEL_EXPRESSION,
+    /** Boolean expression. */
+    SEL_BOOLEAN,
+    /** Arithmetic expression. */
+    SEL_ARITHMETIC,
+    /** Root node of the evaluation tree. */
+    SEL_ROOT,
+    /** Subexpression that may be referenced several times. */
+    SEL_SUBEXPR,
+    /** Reference to a subexpression. */
+    SEL_SUBEXPRREF,
+    /** Unresolved reference to an external group. */
+    SEL_GROUPREF,
+    /** Post-processing of selection value. */
+    SEL_MODIFIER
+} e_selelem_t;
+
+/** Defines the gmx_boolean operation of \c t_selelem objects with type \ref SEL_BOOLEAN. */
+typedef enum
+{
+    BOOL_NOT,           /**< Not */
+    BOOL_AND,           /**< And */
+    BOOL_OR,            /**< Or */
+    BOOL_XOR            /**< Xor (not implemented). */
+} e_boolean_t;
+
+/** Defines the arithmetic operation of \c t_selelem objects with type \ref SEL_ARITHMETIC. */
+typedef enum
+{
+    ARITH_PLUS,         /**< + */
+    ARITH_MINUS,        /**< - */
+    ARITH_NEG,          /**< Unary - */
+    ARITH_MULT,         /**< * */
+    ARITH_DIV,          /**< / */
+    ARITH_EXP           /**< ^ (to power) */
+} e_arithmetic_t;
+
+/** Returns a string representation of the type of a \c t_selelem. */
+extern const char *
+_gmx_selelem_type_str(struct t_selelem *sel);
+/** Returns a string representation of the gmx_boolean type of a \ref SEL_BOOLEAN \c t_selelem. */
+extern const char *
+_gmx_selelem_gmx_boolean_type_str(struct t_selelem *sel);
+/** Returns a string representation of the type of a \c gmx_ana_selvalue_t. */
+extern const char *
+_gmx_sel_value_type_str(gmx_ana_selvalue_t *val);
+
+/*@}*/
+
+
+/********************************************************************/
+/*! \name Selection expression flags
+ * \anchor selelem_flags
+ ********************************************************************/
+/*@{*/
+/*! \brief
+ * Selection value flags are set.
+ *
+ * If this flag is set, the flags covered by \ref SEL_VALFLAGMASK
+ * have been set properly for the element.
+ */
+#define SEL_FLAGSSET    1
+/*! \brief
+ * The element evaluates to a single value.
+ *
+ * This flag is always set for \ref GROUP_VALUE elements.
+ */
+#define SEL_SINGLEVAL   2
+/*! \brief
+ * The element evaluates to one value for each input atom.
+ */
+#define SEL_ATOMVAL     4
+/*! \brief
+ * The element evaluates to an arbitrary number of values.
+ */
+#define SEL_VARNUMVAL   8
+/*! \brief
+ * The element (or one of its children) is dynamic.
+ */
+#define SEL_DYNAMIC     16
+/*! \brief
+ * Mask that covers the flags that describe the number of values.
+ */
+#define SEL_VALTYPEMASK (SEL_SINGLEVAL | SEL_ATOMVAL | SEL_VARNUMVAL)
+/*! \brief
+ * Mask that covers the flags that describe the value type.
+ */
+#define SEL_VALFLAGMASK (SEL_FLAGSSET | SEL_VALTYPEMASK | SEL_DYNAMIC)
+/*! \brief
+ * Data has been allocated for the \p v.u union.
+ *
+ * If not set, the \p v.u.ptr points to data allocated externally.
+ * This is the case if the value of the element is used as a parameter
+ * for a selection method or if the element evaluates the final value of
+ * a selection.
+ *
+ * Even if the flag is set, \p v.u.ptr can be NULL during initialization.
+ *
+ * \todo
+ * This flag overlaps with the function of \p v.nalloc field, and could
+ * probably be removed, making memory management simpler. Currently, the
+ * \p v.nalloc field is not kept up-to-date in all cases when this flag
+ * is changed and is used in places where this flag is not, so this would
+ * require a careful investigation of the selection code.
+ */
+#define SEL_ALLOCVAL    (1<<8)
+/*! \brief
+ * Data has been allocated for the group/position structure.
+ *
+ * If not set, the memory allocated for fields in \p v.u.g or \p v.u.p is
+ * managed externally.
+ *
+ * This field has no effect if the value type is not \ref GROUP_VALUE or
+ * \ref POS_VALUE, but should not be set.
+ */
+#define SEL_ALLOCDATA   (1<<9)
+/*! \brief
+ * \p method->init_frame should be called for the frame.
+ */
+#define SEL_INITFRAME   (1<<10)
+/*! \brief
+ * Parameter has been evaluated for the current frame.
+ *
+ * This flag is set for children of \ref SEL_EXPRESSION elements (which
+ * describe method parameters) after the element has been evaluated for the
+ * current frame.
+ * It is not set for \ref SEL_ATOMVAL elements, because they may need to
+ * be evaluated multiple times.
+ */
+#define SEL_EVALFRAME   (1<<11)
+/*! \brief
+ * \p method->init has been called.
+ */
+#define SEL_METHODINIT  (1<<12)
+/*! \brief
+ * \p method->outinit has been called.
+ *
+ * This flag is also used for \ref SEL_SUBEXPRREF elements.
+ */
+#define SEL_OUTINIT     (1<<13)
+/*@}*/
+
+
+/********************************************************************/
+/*! \name Selection expression data structures and functions
+ ********************************************************************/
+/*@{*/
+
+struct t_selelem;
+
+/*! \brief
+ * Function pointer for evaluating a \c t_selelem.
+ */
+typedef int (*sel_evalfunc)(struct gmx_sel_evaluate_t *data,
+                            struct t_selelem *sel, gmx_ana_index_t *g);
+
+/*! \internal \brief
+ * Represents an element of a selection expression.
+ */
+typedef struct t_selelem
+{
+    /*! \brief Name of the element.
+     *
+     * This field is only used for informative purposes.
+     * It is always either NULL or a pointer to a string.
+     * Memory is never allocated for it directly.
+     */
+    const char                         *name;
+    /** Type of the element. */
+    e_selelem_t                         type;
+    /*! \brief
+     * Value storage of the element.
+     *
+     * This field contains the evaluated value of the element, as well as
+     * the output value type.
+     */
+    gmx_ana_selvalue_t                  v;
+    /*! \brief
+     * Evaluation function for the element.
+     *
+     * Can be either NULL (if the expression is a constant and does not require
+     * evaluation) or point to one of the functions defined in evaluate.h.
+     */
+    sel_evalfunc                        evaluate;
+    /*! \brief
+     * Information flags about the element.
+     *
+     * Allowed flags are listed here:
+     * \ref selelem_flags "flags for \c t_selelem".
+     */
+    int                                 flags;
+    /** Data required by the evaluation function. */
+    union {
+        /*! \brief Index group data for several element types.
+         *
+         *  - \ref SEL_CONST : if the value type is \ref GROUP_VALUE,
+         *    this field holds the unprocessed group value.
+         *  - \ref SEL_ROOT : holds the group value for which the
+         *    selection subtree should be evaluated.
+         *  - \ref SEL_SUBEXPR : holds the group for which the subexpression
+         *    has been evaluated.
+         */
+        gmx_ana_index_t                 cgrp;
+        /** Data for \ref SEL_EXPRESSION and \ref SEL_MODIFIER elements. */
+        struct {
+            /** Pointer the the method used in this expression. */
+            struct gmx_ana_selmethod_t *method;
+            /** Pointer to the data allocated by the method's \p init_data (see sel_datafunc()). */
+            void                       *mdata;
+            /** Pointer to the position data passed to the method. */
+            struct gmx_ana_pos_t       *pos;
+            /** Pointer to the evaluation data for \p pos. */
+            struct gmx_ana_poscalc_t   *pc;
+        }                               expr;
+        /** Operation type for \ref SEL_BOOLEAN elements. */
+        e_boolean_t                     boolt;
+        /** Operation type for \ref SEL_ARITHMETIC elements. */
+        struct {
+            /** Operation type. */
+            e_arithmetic_t              type;
+            /** String representation. */
+            char                       *opstr;
+        }                               arith;
+        /** Associated selection parameter for \ref SEL_SUBEXPRREF elements. */
+        struct gmx_ana_selparam_t      *param;
+        /** The string/number used to reference the group. */
+        struct {
+            /** Name of the referenced external group. */
+            char                       *name;
+            /** If \a name is NULL, the index number of the referenced group. */
+            int                         id;
+        }                               gref;
+    }                                   u;
+    /** Memory pool to use for values, or NULL if standard memory handling. */
+    struct gmx_sel_mempool_t           *mempool;
+    /** Internal data for the selection compiler. */
+    struct t_compiler_data             *cdata;
+    
+    /*! \brief The first child element.
+     *
+     * Other children can be accessed through the \p next field of \p child.
+     */
+    struct t_selelem                    *child;
+    /** The next sibling element. */
+    struct t_selelem                    *next;
+    /*! \brief Number of references to this element.
+     *
+     * Should be larger than one only for \ref SEL_SUBEXPR elements.
+     */
+    int                                  refcount;
+} t_selelem;
+
+/* In evaluate.c */
+/** Writes out a human-readable name for an evaluation function. */
+extern void
+_gmx_sel_print_evalfunc_name(FILE *fp, sel_evalfunc evalfunc);
+
+/** Allocates memory and performs some common initialization for a \c t_selelem. */
+extern t_selelem *
+_gmx_selelem_create(e_selelem_t type);
+/** Sets the value type of a \c t_selelem. */
+extern int
+_gmx_selelem_set_vtype(t_selelem *sel, e_selvalue_t vtype);
+/** Reserves memory for value of a \c t_selelem from a memory pool. */
+extern int
+_gmx_selelem_mempool_reserve(t_selelem *sel, int count);
+/** Releases memory pool used for value of a \c t_selelem. */
+extern void
+_gmx_selelem_mempool_release(t_selelem *sel);
+/** Frees the memory allocated for a \c t_selelem structure and all its children. */
+extern void
+_gmx_selelem_free(t_selelem *sel);
+/** Frees the memory allocated for a \c t_selelem structure, all its children, and also all structures referenced through t_selelem::next fields. */
+extern void
+_gmx_selelem_free_chain(t_selelem *first);
+
+/** Frees the memory allocated for the \c t_selelem::d union. */
+extern void
+_gmx_selelem_free_values(t_selelem *sel);
+/** Frees the memory allocated for a selection method. */
+extern void
+_gmx_selelem_free_method(struct gmx_ana_selmethod_t *method, void *mdata);
+/** Frees the memory allocated for the \c t_selelem::u field. */
+extern void
+_gmx_selelem_free_exprdata(t_selelem *sel);
+/* In compiler.c */
+/** Frees the memory allocated for the selection compiler. */
+extern void
+_gmx_selelem_free_compiler_data(t_selelem *sel);
+
+/** Prints a human-readable version of a selection element subtree. */
+extern void
+_gmx_selelem_print_tree(FILE *fp, t_selelem *root, gmx_bool bValues, int level);
+/* In compile.c */
+/** Prints a human-readable version of the internal compiler data structure. */
+extern void
+_gmx_selelem_print_compiler_info(FILE *fp, t_selelem *sel, int level);
+
+/** Returns TRUE if the selection element subtree requires topology information for evaluation. */
+extern gmx_bool
+_gmx_selelem_requires_top(t_selelem *root);
+
+/* In sm_insolidangle.c */
+/** Returns TRUE if the covered fraction of the selection can be calculated. */
+extern gmx_bool
+_gmx_selelem_can_estimate_cover(t_selelem *sel);
+/** Returns the covered fraction of the selection for the current frame. */
+extern real
+_gmx_selelem_estimate_coverfrac(t_selelem *sel);
+
+/*@}*/
+
+#endif
diff --git a/src/gromacs/selection/selhelp.cpp b/src/gromacs/selection/selhelp.cpp
new file mode 100644 (file)
index 0000000..d7e7a69
--- /dev/null
@@ -0,0 +1,487 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * Implements functions in selhelp.h.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_selection
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <macros.h>
+#include <string2.h>
+#include <wman.h>
+
+#include "gromacs/selection/selmethod.h"
+
+#include "selhelp.h"
+#include "symrec.h"
+
+/*! \internal \brief
+ * Describes a selection help section.
+ */
+typedef struct {
+    //! Topic keyword that produces this help.
+    const char  *topic;
+    //! Number of items in the \a text array.
+    int          nl;
+    //! Help text as a list of strings that will be concatenated.
+    const char **text;
+} t_selection_help_item;
+
+static const char *help_common[] = {
+    "SELECTION HELP[PAR]",
+
+    "This program supports selections in addition to traditional index files.",
+    "Please read the subtopic pages (available through \"help topic\") for",
+    "more information.",
+    "Explanation of command-line arguments for specifying selections can be",
+    "found under the \"cmdline\" subtopic, and general selection syntax is",
+    "described under \"syntax\". Available keywords can be found under",
+    "\"keywords\", and concrete examples under \"examples\".",
+    "Other subtopics give more details on certain aspects.",
+    "\"help all\" prints the help for all subtopics.",
+};
+
+static const char *help_arithmetic[] = {
+    "ARITHMETIC EXPRESSIONS IN SELECTIONS[PAR]",
+
+    "Basic arithmetic evaluation is supported for numeric expressions.",
+    "Supported operations are addition, subtraction, negation, multiplication,",
+    "division, and exponentiation (using ^).",
+    "Result of a division by zero or other illegal operations is undefined.",
+};
+
+static const char *help_cmdline[] = {
+    "SELECTION COMMAND-LINE ARGUMENTS[PAR]",
+
+    "There are two alternative command-line arguments for specifying",
+    "selections:[BR]",
+    "1. [TT]-select[tt] can be used to specify the complete selection as a",
+    "string on the command line.[BR]",
+    "2. [TT]-sf[tt] can be used to specify a file name from which the",
+    "selection is read.[BR]",
+    "If both options are specified, [TT]-select[tt] takes precedence.",
+    "If neither of the above is present, the user is prompted to type the",
+    "selection on the standard input (a pipe can also be used to provide",
+    "the selections in this case).",
+    "This is also done if an empty string is passed to [TT]-select[tt].[PAR]",
+
+    "Option [TT]-n[tt] can be used to provide an index file.",
+    "If no index file is provided, default groups are generated.",
+    "In both cases, the user can also select an index group instead of",
+    "writing a full selection.",
+    "The default groups are generated by reading selections from a file",
+    "[TT]defselection.dat[tt]. If such a file is found in the current",
+    "directory, it is used instead of the one provided by default.[PAR]",
+
+    "Depending on the tool, two additional command-line arguments may be",
+    "available to control the behavior:[BR]",
+    "1. [TT]-seltype[tt] can be used to specify the default type of",
+    "positions to calculate for each selection.[BR]",
+    "2. [TT]-selrpos[tt] can be used to specify the default type of",
+    "positions used in selecting atoms by coordinates.[BR]",
+    "See \"help positions\" for more information on these options.",
+};
+
+static const char *help_eval[] = {
+    "SELECTION EVALUATION AND OPTIMIZATION[PAR]",
+
+    "Boolean evaluation proceeds from left to right and is short-circuiting",
+    "i.e., as soon as it is known whether an atom will be selected, the",
+    "remaining expressions are not evaluated at all.",
+    "This can be used to optimize the selections: you should write the",
+    "most restrictive and/or the most inexpensive expressions first in",
+    "boolean expressions.",
+    "The relative ordering between dynamic and static expressions does not",
+    "matter: all static expressions are evaluated only once, before the first",
+    "frame, and the result becomes the leftmost expression.[PAR]",
+
+    "Another point for optimization is in common subexpressions: they are not",
+    "automatically recognized, but can be manually optimized by the use of",
+    "variables. This can have a big impact on the performance of complex",
+    "selections, in particular if you define several index groups like this:",
+    "  [TT]rdist = distance from com of resnr 1 to 5;[tt][BR]",
+    "  [TT]resname RES and rdist < 2;[tt][BR]",
+    "  [TT]resname RES and rdist < 4;[tt][BR]",
+    "  [TT]resname RES and rdist < 6;[tt][BR]",
+    "Without the variable assignment, the distances would be evaluated three",
+    "times, although they are exactly the same within each selection.",
+    "Anything assigned into a variable becomes a common subexpression that",
+    "is evaluated only once during a frame.",
+    "Currently, in some cases the use of variables can actually lead to a small",
+    "performance loss because of the checks necessary to determine for which",
+    "atoms the expression has already been evaluated, but this should not be",
+    "a major problem.",
+};
+
+static const char *help_examples[] = {
+    "SELECTION EXAMPLES[PAR]",
+
+    "Below, examples of increasingly complex selections are given.[PAR]",
+
+    "Selection of all water oxygens:[BR]",
+    "  resname SOL and name OW",
+    "[PAR]",
+
+    "Centers of mass of residues 1 to 5 and 10:[BR]",
+    "  res_com of resnr 1 to 5 10",
+    "[PAR]",
+
+    "All atoms farther than 1 nm of a fixed position:[BR]",
+    "  not within 1 of (1.2, 3.1, 2.4)",
+    "[PAR]",
+
+    "All atoms of a residue LIG within 0.5 nm of a protein (with a custom name):[BR]",
+    "  \"Close to protein\" resname LIG and within 0.5 of group \"Protein\"",
+    "[PAR]",
+
+    "All protein residues that have at least one atom within 0.5 nm of a residue LIG:[BR]",
+    "  group \"Protein\" and same residue as within 0.5 of resname LIG",
+    "[PAR]",
+
+    "All RES residues whose COM is between 2 and 4 nm from the COM of all of them:[BR]",
+    "  rdist = res_com distance from com of resname RES[BR]",
+    "  resname RES and rdist >= 2 and rdist <= 4",
+    "[PAR]",
+
+    "Selection like C1 C2 C2 C3 C3 C4 ... C8 C9 (e.g., for g_bond):[BR]",
+    "  name \"C[1-8]\" merge name \"C[2-9]\"",
+};
+
+static const char *help_keywords[] = {
+    "SELECTION KEYWORDS[PAR]",
+
+    "The following selection keywords are currently available.",
+    "For keywords marked with a star, additional help is available through",
+    "\"help KEYWORD\", where KEYWORD is the name of the keyword.",
+};
+
+static const char *help_limits[] = {
+    "SELECTION LIMITATIONS[PAR]",
+
+    "Some analysis programs may require a special structure for the input",
+    "selections (e.g., [TT]g_angle[tt] requires the index group to be made",
+    "of groups of three or four atoms).",
+    "For such programs, it is up to the user to provide a proper selection",
+    "expression that always returns such positions.",
+    "[PAR]",
+
+    "Due to technical reasons, having a negative value as the first value in",
+    "expressions like[BR]",
+    "[TT]charge -1 to -0.7[tt][BR]",
+    "result in a syntax error. A workaround is to write[BR]",
+    "[TT]charge {-1 to -0.7}[tt][BR]",
+    "instead.",
+};
+
+static const char *help_positions[] = {
+    "SPECIFYING POSITIONS[PAR]",
+
+    "Possible ways of specifying positions in selections are:[PAR]",
+
+    "1. A constant position can be defined as [TT][XX, YY, ZZ][tt], where",
+    "[TT]XX[tt], [TT]YY[tt] and [TT]ZZ[tt] are real numbers.[PAR]",
+
+    "2. [TT]com of ATOM_EXPR [pbc][tt] or [TT]cog of ATOM_EXPR [pbc][tt]",
+    "calculate the center of mass/geometry of [TT]ATOM_EXPR[tt]. If",
+    "[TT]pbc[tt] is specified, the center is calculated iteratively to try",
+    "to deal with cases where [TT]ATOM_EXPR[tt] wraps around periodic",
+    "boundary conditions.[PAR]",
+
+    "3. [TT]POSTYPE of ATOM_EXPR[tt] calculates the specified positions for",
+    "the atoms in [TT]ATOM_EXPR[tt].",
+    "[TT]POSTYPE[tt] can be [TT]atom[tt], [TT]res_com[tt], [TT]res_cog[tt],",
+    "[TT]mol_com[tt] or [TT]mol_cog[tt], with an optional prefix [TT]whole_[tt]",
+    "[TT]part_[tt] or [TT]dyn_[tt].",
+    "[TT]whole_[tt] calculates the centers for the whole residue/molecule,",
+    "even if only part of it is selected.",
+    "[TT]part_[tt] prefix calculates the centers for the selected atoms, but",
+    "uses always the same atoms for the same residue/molecule. The used atoms",
+    "are determined from the the largest group allowed by the selection.",
+    "[TT]dyn_[tt] calculates the centers strictly only for the selected atoms.",
+    "If no prefix is specified, whole selections default to [TT]part_[tt] and",
+    "other places default to [TT]whole_[tt].",
+    "The latter is often desirable to select the same molecules in different",
+    "tools, while the first is a compromise between speed ([TT]dyn_[tt]",
+    "positions can be slower to evaluate than [TT]part_[tt]) and intuitive",
+    "behavior.[PAR]",
+
+    "4. [TT]ATOM_EXPR[tt], when given for whole selections, is handled as 3.",
+    "above, using the position type from the command-line argument",
+    "[TT]-seltype[tt].[PAR]",
+
+    "Selection keywords that select atoms based on their positions, such as",
+    "[TT]dist from[tt], use by default the positions defined by the",
+    "[TT]-selrpos[tt] command-line option.",
+    "This can be overridden by prepending a [TT]POSTYPE[tt] specifier to the",
+    "keyword. For example, [TT]res_com dist from POS[tt] evaluates the",
+    "residue center of mass distances. In the example, all atoms of a residue",
+    "are either selected or not, based on the single distance calculated.",
+};
+
+static const char *help_syntax[] = {
+    "SELECTION SYNTAX[PAR]",
+
+    "A set of selections consists of one or more selections, separated by",
+    "semicolons. Each selection defines a set of positions for the analysis.",
+    "Each selection can also be preceded by a string that gives a name for",
+    "the selection for use in, e.g., graph legends.",
+    "If no name is provided, the string used for the selection is used",
+    "automatically as the name.[PAR]",
+
+    "For interactive input, the syntax is slightly altered: line breaks can",
+    "also be used to separate selections. \\ followed by a line break can",
+    "be used to continue a line if necessary.",
+    "Notice that the above only applies to real interactive input,",
+    "not if you provide the selections, e.g., from a pipe.[PAR]",
+
+    "It is possible to use variables to store selection expressions.",
+    "A variable is defined with the following syntax:[BR]",
+    "[TT]VARNAME = EXPR ;[tt][BR]",
+    "where [TT]EXPR[tt] is any valid selection expression.",
+    "After this, [TT]VARNAME[tt] can be used anywhere where [TT]EXPR[tt]",
+    "would be valid.[PAR]",
+
+    "Selections are composed of three main types of expressions, those that",
+    "define atoms ([TT]ATOM_EXPR[tt]s), those that define positions",
+    "([TT]POS_EXPR[tt]s), and those that evaluate to numeric values",
+    "([TT]NUM_EXPR[tt]s). Each selection should be a [TT]POS_EXPR[tt]",
+    "or a [TT]ATOM_EXPR[tt] (the latter is automatically converted to",
+    "positions). The basic rules are as follows:[BR]",
+    "1. An expression like [TT]NUM_EXPR1 < NUM_EXPR2[tt] evaluates to an",
+    "[TT]ATOM_EXPR[tt] that selects all the atoms for which the comparison",
+    "is true.[BR]",
+    "2. Atom expressions can be combined with gmx_boolean operations such as",
+    "[TT]not ATOM_EXPR[tt], [TT]ATOM_EXPR and ATOM_EXPR[tt], or",
+    "[TT]ATOM_EXPR or ATOM_EXPR[tt]. Parentheses can be used to alter the",
+    "evaluation order.[BR]",
+    "3. [TT]ATOM_EXPR[tt] expressions can be converted into [TT]POS_EXPR[tt]",
+    "expressions in various ways, see \"help positions\" for more details.[PAR]",
+
+    "Some keywords select atoms based on string values such as the atom name.",
+    "For these keywords, it is possible to use wildcards ([TT]name \"C*\"[tt])",
+    "or regular expressions (e.g., [TT]resname \"R[AB]\"[tt]).",
+    "The match type is automatically guessed from the string: if it contains",
+    "other characters than letters, numbers, '*', or '?', it is interpreted",
+    "as a regular expression.",
+    "Strings that contain non-alphanumeric characters should be enclosed in",
+    "double quotes as in the examples. For other strings, the quotes are",
+    "optional, but if the value conflicts with a reserved keyword, a syntax",
+    "error will occur. If your strings contain uppercase letters, this should",
+    "not happen.[PAR]",
+
+    "Index groups provided with the [TT]-n[tt] command-line option or",
+    "generated by default can be accessed with [TT]group NR[tt] or",
+    "[TT]group NAME[tt], where [TT]NR[tt] is a zero-based index of the group",
+    "and [TT]NAME[tt] is part of the name of the desired group.",
+    "The keyword [TT]group[tt] is optional if the whole selection is",
+    "provided from an index group.",
+    "To see a list of available groups in the interactive mode, press enter",
+    "in the beginning of a line.",
+};
+
+static const t_selection_help_item helpitems[] = {
+    {NULL,          asize(help_common),     help_common},
+    {"cmdline",     asize(help_cmdline),    help_cmdline},
+    {"syntax",      asize(help_syntax),     help_syntax},
+    {"positions",   asize(help_positions),  help_positions},
+    {"arithmetic",  asize(help_arithmetic), help_arithmetic},
+    {"keywords",    asize(help_keywords),   help_keywords},
+    {"evaluation",  asize(help_eval),       help_eval},
+    {"limitations", asize(help_limits),     help_limits},
+    {"examples",    asize(help_examples),   help_examples},
+};
+
+/*! \brief
+ * Prints a brief list of keywords (selection methods) available.
+ *
+ * \param[in] symtab  Symbol table to use to find available keywords.
+ * \param[in] type  Only methods that return this type are printed.
+ * \param[in] bMod  If FALSE, \ref SMETH_MODIFIER methods are excluded, otherwise
+ *     only them are printed.
+ */
+static void
+print_keyword_list(gmx_sel_symtab_t *symtab, e_selvalue_t type,
+                   gmx_bool bMod)
+{
+    gmx_sel_symrec_t *symbol;
+
+    symbol = _gmx_sel_first_symbol(symtab, SYMBOL_METHOD);
+    while (symbol)
+    {
+        gmx_ana_selmethod_t *method = _gmx_sel_sym_value_method(symbol);
+        gmx_bool                 bShow;
+        bShow = (method->type == type)
+            && ((bMod && (method->flags & SMETH_MODIFIER))
+                || (!bMod && !(method->flags & SMETH_MODIFIER)));
+        if (bShow)
+        {
+            fprintf(stderr, " %c ",
+                    (method->help.nlhelp > 0 && method->help.help) ? '*' : ' ');
+            if (method->help.syntax)
+            {
+                fprintf(stderr, "%s\n", method->help.syntax);
+            }
+            else
+            {
+                const char *symname = _gmx_sel_sym_name(symbol);
+
+                fprintf(stderr, "%s", symname);
+                if (strcmp(symname, method->name) != 0)
+                {
+                    fprintf(stderr, " (synonym for %s)", method->name);
+                }
+                fprintf(stderr, "\n");
+            }
+        }
+        symbol = _gmx_sel_next_symbol(symbol, SYMBOL_METHOD);
+    }
+}
+
+/*!
+ * \param[in]   symtab  Symbol table to use to find available keywords.
+ * \param[in]  topic Topic to print help on, or NULL for general help.
+ *
+ * \p sc is used to get information on which keywords are available in the
+ * present context.
+ */
+void
+_gmx_sel_print_help(gmx_sel_symtab_t *symtab, const char *topic)
+{
+    const t_selection_help_item *item = NULL;
+    size_t i;
+
+    /* Find the item for the topic */
+    if (!topic)
+    {
+        item = &helpitems[0];
+    }
+    else if (strcmp(topic, "all") == 0)
+    {
+        for (i = 0; i < asize(helpitems); ++i)
+        {
+            item = &helpitems[i];
+            _gmx_sel_print_help(symtab, item->topic);
+            if (i != asize(helpitems) - 1)
+            {
+                fprintf(stderr, "\n\n");
+            }
+        }
+        return;
+    }
+    else
+    {
+        for (i = 1; i < asize(helpitems); ++i)
+        {
+            if (strncmp(helpitems[i].topic, topic, strlen(topic)) == 0)
+            {
+                item = &helpitems[i];
+                break;
+            }
+        }
+    }
+    /* If the topic is not found, check the available methods.
+     * If they don't provide any help either, tell the user and exit. */
+    if (!item)
+    {
+        gmx_sel_symrec_t *symbol;
+
+        symbol = _gmx_sel_first_symbol(symtab, SYMBOL_METHOD);
+        while (symbol)
+        {
+            gmx_ana_selmethod_t *method = _gmx_sel_sym_value_method(symbol);
+            if (method->help.nlhelp > 0 && method->help.help
+                && strncmp(method->name, topic, strlen(topic)) == 0)
+            {
+                print_tty_formatted(stderr, method->help.nlhelp,
+                        method->help.help, 0, NULL, NULL, FALSE);
+                return;
+            }
+            symbol = _gmx_sel_next_symbol(symbol, SYMBOL_METHOD);
+        }
+
+        fprintf(stderr, "No help available for '%s'.\n", topic);
+        return;
+    }
+    /* Print the help */
+    print_tty_formatted(stderr, item->nl, item->text, 0, NULL, NULL, FALSE);
+    /* Special handling of certain pages */
+    if (!topic)
+    {
+        int len = 0;
+
+        /* Print the subtopics on the main page */
+        fprintf(stderr, "\nAvailable subtopics:\n");
+        for (i = 1; i < asize(helpitems); ++i)
+        {
+            int len1 = strlen(helpitems[i].topic) + 2;
+
+            len += len1;
+            if (len > 79)
+            {
+                fprintf(stderr, "\n");
+                len = len1;
+            }
+            fprintf(stderr, "  %s", helpitems[i].topic);
+        }
+        fprintf(stderr, "\n");
+    }
+    else if (strcmp(item->topic, "keywords") == 0)
+    {
+        /* Print the list of keywords */
+        fprintf(stderr, "\nKeywords that select atoms by an integer property:\n");
+        fprintf(stderr, "(use in expressions or like \"atomnr 1 to 5 7 9\")\n");
+        print_keyword_list(symtab, INT_VALUE, FALSE);
+
+        fprintf(stderr, "\nKeywords that select atoms by a numeric property:\n");
+        fprintf(stderr, "(use in expressions or like \"occupancy 0.5 to 1\")\n");
+        print_keyword_list(symtab, REAL_VALUE, FALSE);
+
+        fprintf(stderr, "\nKeywords that select atoms by a string property:\n");
+        fprintf(stderr, "(use like \"name PATTERN [PATTERN] ...\")\n");
+        print_keyword_list(symtab, STR_VALUE, FALSE);
+
+        fprintf(stderr, "\nAdditional keywords that directly select atoms:\n");
+        print_keyword_list(symtab, GROUP_VALUE, FALSE);
+
+        fprintf(stderr, "\nKeywords that directly evaluate to positions:\n");
+        fprintf(stderr, "(see also \"help positions\")\n");
+        print_keyword_list(symtab, POS_VALUE, FALSE);
+
+        fprintf(stderr, "\nAdditional keywords:\n");
+        print_keyword_list(symtab, POS_VALUE, TRUE);
+        print_keyword_list(symtab, NO_VALUE, TRUE);
+    }
+}
diff --git a/src/gromacs/selection/selhelp.h b/src/gromacs/selection/selhelp.h
new file mode 100644 (file)
index 0000000..1072d0b
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief Functions for printing help for selections.
+ *
+ * This is an implementation header: there should be no need to use it outside
+ * this directory.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_selection
+ */
+#ifndef GMX_SELECTION_HELP_H
+#define GMX_SELECTION_HELP_H
+
+struct gmx_sel_symtab_t;
+
+/** Prints help for writing selections. */
+void
+_gmx_sel_print_help(struct gmx_sel_symtab_t *symtab, const char *topic);
+
+#endif
diff --git a/src/gromacs/selection/selmethod.cpp b/src/gromacs/selection/selmethod.cpp
new file mode 100644 (file)
index 0000000..6e10315
--- /dev/null
@@ -0,0 +1,696 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * Implements functions in selmethod.h.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_selection
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <ctype.h>
+#include <stdarg.h>
+
+#include <macros.h>
+#include <string2.h>
+
+#include "gromacs/selection/selmethod.h"
+
+#include "symrec.h"
+
+/*
+ * These global variables cannot be const because gmx_ana_selmethod_register()
+ * modifies them to set some defaults. This is a small price to pay for the
+ * convenience of not having to remember exactly how the selection compiler
+ * expects the structures to be filled, and even more so if the expectations
+ * change. Also, even if the gmx_ana_selmethod_t structures were made const,
+ * the parameters could not be without typecasts somewhere, because the param
+ * field in gmx_ana_selmethod_t cannot be declared const.
+ *
+ * Even though the variables may be modified, this should be thread-safe as
+ * modifications are done only in gmx_ana_selmethod_register(), and it should
+ * work even if called more than once for the same structure, and even if
+ * called concurrently from multiple threads (as long as the selection
+ * collection is not the same).
+ *
+ * All of these problems should go away if/when the selection methods are
+ * implemented as C++ classes.
+ */
+
+/* From sm_com.c */
+extern gmx_ana_selmethod_t sm_cog;
+extern gmx_ana_selmethod_t sm_com;
+/* From sm_simple.c */
+extern gmx_ana_selmethod_t sm_all;
+extern gmx_ana_selmethod_t sm_none;
+extern gmx_ana_selmethod_t sm_atomnr;
+extern gmx_ana_selmethod_t sm_resnr;
+extern gmx_ana_selmethod_t sm_resindex;
+extern gmx_ana_selmethod_t sm_molindex;
+extern gmx_ana_selmethod_t sm_atomname;
+extern gmx_ana_selmethod_t sm_atomtype;
+extern gmx_ana_selmethod_t sm_resname;
+extern gmx_ana_selmethod_t sm_insertcode;
+extern gmx_ana_selmethod_t sm_chain;
+extern gmx_ana_selmethod_t sm_mass;
+extern gmx_ana_selmethod_t sm_charge;
+extern gmx_ana_selmethod_t sm_altloc;
+extern gmx_ana_selmethod_t sm_occupancy;
+extern gmx_ana_selmethod_t sm_betafactor;
+extern gmx_ana_selmethod_t sm_x;
+extern gmx_ana_selmethod_t sm_y;
+extern gmx_ana_selmethod_t sm_z;
+/* From sm_distance.c */
+extern gmx_ana_selmethod_t sm_distance;
+extern gmx_ana_selmethod_t sm_mindistance;
+extern gmx_ana_selmethod_t sm_within;
+/* From sm_insolidangle.c */
+extern gmx_ana_selmethod_t sm_insolidangle;
+/* From sm_same.c */
+extern gmx_ana_selmethod_t sm_same;
+
+/* From sm_merge.c */
+extern gmx_ana_selmethod_t sm_merge;
+extern gmx_ana_selmethod_t sm_plus;
+/* From sm_permute.c */
+extern gmx_ana_selmethod_t sm_permute;
+
+/*! \internal \brief
+ * Helper structure for defining selection methods.
+ */
+typedef struct {
+    /*! \brief
+     * Name to register the method under.
+     *
+     * If NULL, use the actual name of the method.
+     * This field is used for defining synonyms.
+     */
+    const char            *name;
+    /** Method data structure to register. */
+    gmx_ana_selmethod_t   *method;
+} t_register_method;
+
+/** Array of selection methods defined in the library. */
+static const t_register_method smtable_def[] = {
+    {NULL,         &sm_cog},
+    {NULL,         &sm_com},
+
+    {NULL,         &sm_all},
+    {NULL,         &sm_none},
+    {NULL,         &sm_atomnr},
+    {NULL,         &sm_resnr},
+    {"resid",      &sm_resnr},
+    {NULL,         &sm_resindex},
+    {"residue",    &sm_resindex},
+    {NULL,         &sm_molindex},
+    {"mol",        &sm_molindex},
+    {"molecule",   &sm_molindex},
+    {NULL,         &sm_atomname},
+    {NULL,         &sm_atomtype},
+    {NULL,         &sm_resname},
+    {NULL,         &sm_insertcode},
+    {NULL,         &sm_chain},
+    {NULL,         &sm_mass},
+    {NULL,         &sm_charge},
+    {NULL,         &sm_altloc},
+    {NULL,         &sm_occupancy},
+    {NULL,         &sm_betafactor},
+    {NULL,         &sm_x},
+    {NULL,         &sm_y},
+    {NULL,         &sm_z},
+
+    {NULL,         &sm_distance},
+    {NULL,         &sm_mindistance},
+    {NULL,         &sm_within},
+    {NULL,         &sm_insolidangle},
+    {NULL,         &sm_same},
+
+    {NULL,         &sm_merge},
+    {NULL,         &sm_plus},
+    {NULL,         &sm_permute},
+};
+
+/*! \brief
+ * Convenience function for reporting errors found in selection methods.
+ */
+static void
+report_error(FILE *fp, const char *name, const char *fmt, ...)
+{
+    va_list ap;
+    va_start(ap, fmt);
+    if (fp)
+    {
+        fprintf(fp, "selection method '%s': ", name);
+        vfprintf(fp, fmt, ap);
+        fprintf(fp, "\n");
+    }
+    va_end(ap);
+}
+
+/*! \brief
+ * Convenience function for reporting errors found in selection method parameters.
+ */
+static void
+report_param_error(FILE *fp, const char *mname, const char *pname,
+                   const char *fmt, ...)
+{
+    va_list ap;
+    va_start(ap, fmt);
+    if (fp)
+    {
+        fprintf(fp, "selection method '%s': parameter '%s': ", mname, pname);
+        vfprintf(fp, fmt, ap);
+        fprintf(fp, "\n");
+    }
+    va_end(ap);
+}
+
+/*! \brief
+ * Checks the validity of parameters.
+ *
+ * \param[in]     fp      File handle to use for diagnostic messages
+ *   (can be NULL).
+ * \param[in]     name    Name of the method (used for error messages).
+ * \param[in]     nparams Number of parameters in \p param.
+ * \param[in,out] param   Parameter array
+ *   (only the \c flags field of gmx_boolean parameters may be modified).
+ * \param[in]     symtab  Symbol table (used for checking overlaps).
+ * \returns       TRUE if there are no problems with the parameters,
+ *   FALSE otherwise.
+ *
+ * This function performs some checks common to both check_method() and
+ * check_modifier().
+ * The purpose of these checks is to ensure that the selection parser does not
+ * need to check for the validity of the parameters at each turn, and to
+ * report programming errors as early as possible.
+ * If you remove a check, make sure that the parameter parser can handle the
+ * resulting parameters.
+ */
+static gmx_bool
+check_params(FILE *fp, const char *name, int nparams, gmx_ana_selparam_t param[],
+             gmx_sel_symtab_t *symtab)
+{
+    gmx_bool              bOk = TRUE;
+    gmx_sel_symrec_t *sym;
+    int               i, j;
+
+    if (nparams > 0 && !param)
+    {
+        report_error(fp, name, "error: missing parameter data");
+        bOk = FALSE;
+        return FALSE;
+    }
+    if (nparams == 0 && param)
+    {
+        report_error(fp, name, "warning: parameter data unused because nparams=0");
+    }
+    /* Check each parameter */
+    for (i = 0; i < nparams; ++i)
+    {
+        /* Check that there is at most one NULL name, in the beginning */
+        if (param[i].name == NULL && i > 0)
+        {
+            report_error(fp, name, "error: NULL parameter should be the first one");
+            bOk = FALSE;
+            continue;
+        }
+        /* Check for duplicates */
+        for (j = 0; j < i; ++j)
+        {
+            if (param[j].name == NULL)
+            {
+                continue;
+            }
+            if (!gmx_strcasecmp(param[i].name, param[j].name))
+            {
+                report_error(fp, name, "error: duplicate parameter name '%s'", param[i].name);
+                bOk = FALSE;
+                break;
+            }
+        }
+        /* Check flags */
+        if (param[i].flags & SPAR_SET)
+        {
+            report_param_error(fp, name, param[i].name, "warning: flag SPAR_SET is set");
+            param[i].flags &= ~SPAR_SET;
+        }
+        if (param[i].flags & SPAR_RANGES)
+        {
+            if (param[i].val.type != INT_VALUE && param[i].val.type != REAL_VALUE)
+            {
+                report_param_error(fp, name, param[i].name, "error: SPAR_RANGES cannot be set for a non-numeric parameter");
+                bOk = FALSE;
+            }
+            if (param[i].flags & SPAR_DYNAMIC)
+            {
+                report_param_error(fp, name, param[i].name, "warning: SPAR_DYNAMIC does not have effect with SPAR_RANGES");
+                param[i].flags &= ~SPAR_DYNAMIC;
+            }
+            if (!(param[i].flags & SPAR_VARNUM) && param[i].val.nr != 1)
+            {
+                report_param_error(fp, name, param[i].name, "error: range should take either one or an arbitrary number of values");
+                bOk = FALSE;
+            }
+            if (param[i].flags & SPAR_ATOMVAL)
+            {
+                report_param_error(fp, name, param[i].name, "error: SPAR_RANGES and SPAR_ATOMVAL both set");
+                bOk = FALSE;
+            }
+        }
+        if ((param[i].flags & SPAR_VARNUM) && (param[i].flags & SPAR_ATOMVAL))
+        {
+            report_param_error(fp, name, param[i].name, "error: SPAR_VARNUM and SPAR_ATOMVAL both set");
+            bOk = FALSE;
+        }
+        if (param[i].flags & SPAR_ENUMVAL)
+        {
+            if (param[i].val.type != STR_VALUE)
+            {
+                report_param_error(fp, name, param[i].name, "error: SPAR_ENUMVAL can only be set for string parameters");
+                bOk = FALSE;
+            }
+            if (param[i].val.nr != 1)
+            {
+                report_param_error(fp, name, param[i].name, "error: SPAR_ENUMVAL parameters should take exactly one value");
+                bOk = FALSE;
+            }
+            if (param[i].flags & (SPAR_DYNAMIC | SPAR_VARNUM | SPAR_ATOMVAL))
+            {
+                report_param_error(fp, name, param[i].name, "error: only SPAR_OPTIONAL supported with SPAR_ENUMVAL");
+                bOk = FALSE;
+            }
+        }
+        /* Check gmx_boolean parameters */
+        if (param[i].val.type == NO_VALUE)
+        {
+            if (param[i].val.nr != 0)
+            {
+                report_param_error(fp, name, param[i].name, "error: number of values should be zero for gmx_boolean parameters");
+                bOk = FALSE;
+            }
+            /* The gmx_boolean parameters should always be optional, so set the
+             * flag for convenience. */
+            param[i].flags |= SPAR_OPTIONAL;
+            /* Any other flags should not be specified */
+            if (param[i].flags & ~SPAR_OPTIONAL)
+            {
+                report_param_error(fp, name, param[i].name, "error: gmx_boolean parameter should not have any flags set");
+                bOk = FALSE;
+            }
+        }
+        /* Check val.nr */
+        if (param[i].flags & (SPAR_VARNUM | SPAR_ATOMVAL))
+        {
+            if (param[i].val.nr != -1)
+            {
+                report_param_error(fp, name, param[i].name, "warning: val.nr is not -1 although SPAR_VARNUM/SPAR_ATOMVAL is set");
+            }
+            param[i].val.nr = -1;
+        }
+        else if (param[i].val.type != NO_VALUE)
+        {
+            if (param[i].val.nr <= 0)
+            {
+                report_param_error(fp, name, param[i].name, "error: val.nr <= 0");
+                bOk = FALSE;
+            }
+        }
+        /* Check that the value pointer is NULL */
+        if (param[i].nvalptr != NULL)
+        {
+            report_param_error(fp, name, param[i].name, "warning: nvalptr is set");
+        }
+        if (param[i].val.u.ptr != NULL && !(param[i].flags & SPAR_ENUMVAL))
+        {
+            report_param_error(fp, name, param[i].name, "warning: value pointer is set");
+        }
+        /* Check that the name contains only valid characters */
+        if (param[i].name == NULL)
+        {
+            continue;
+        }
+        if (!isalpha(param[i].name[0]))
+        {
+            report_param_error(fp, name, param[i].name, "error: name does not begin with a letter");
+            bOk = FALSE;
+            continue;
+        }
+        for (j = 1; param[i].name[j] != 0; ++j)
+        {
+            if (param[i].name[j] != '_' && !isalnum(param[i].name[j]))
+            {
+                report_param_error(fp, name, param[i].name, "error: name contains non-alphanumeric characters");
+                bOk = FALSE;
+                break;
+            }
+        }
+        if (param[i].name[j] != 0)
+        {
+            continue;
+        }
+        /* Check that the name does not conflict with a method */
+        if (_gmx_sel_find_symbol(symtab, param[i].name, TRUE))
+        {
+            report_param_error(fp, name, param[i].name, "error: name conflicts with another method or a keyword");
+            bOk = FALSE;
+        }
+    } /* End of parameter loop */
+    /* Check parameters of existing methods */
+    sym = _gmx_sel_first_symbol(symtab, SYMBOL_METHOD);
+    while (sym)
+    {
+        gmx_ana_selmethod_t *method = _gmx_sel_sym_value_method(sym);
+        gmx_ana_selparam_t  *param =
+            gmx_ana_selmethod_find_param(name, method);
+        if (param)
+        {
+            report_param_error(fp, method->name, param->name, "error: name conflicts with another method or a keyword");
+            bOk = FALSE;
+        }
+        sym = _gmx_sel_next_symbol(sym, SYMBOL_METHOD);
+    }
+    return bOk;
+}
+
+/*! \brief
+ * Checks the validity of selection method callback functions.
+ *
+ * \param[in] fp        File handle to use for diagnostic messages
+ *   (can be NULL).
+ * \param[in] method    The method to check.
+ * \returns   TRUE if there are no problems, FALSE otherwise.
+ *
+ * This function performs some checks common to both check_method() and
+ * check_modifier().
+ * This function checks that all the required callbacks are defined, i.e.,
+ * not NULL, to find programming errors.
+ */
+static gmx_bool
+check_callbacks(FILE *fp, gmx_ana_selmethod_t *method)
+{
+    gmx_bool         bOk = TRUE;
+    gmx_bool         bNeedInit;
+    int          i;
+
+    /* Make some checks on init_data and free */
+    if (method->nparams > 0 && !method->init_data)
+    {
+        report_error(fp, method->name, "error: init_data should be provided because the method has parameters");
+        bOk = FALSE;
+    }
+    if (method->free && !method->init_data)
+    {
+        report_error(fp, method->name, "warning: free is not used because of missing init_data");
+    }
+    /* Check presence of outinit for position-valued methods */
+    if (method->type == POS_VALUE && !method->outinit)
+    {
+        report_error(fp, method->name, "error: outinit should be provided because the method has POS_VALUE");
+        bOk = FALSE;
+    }
+    /* Warn of dynamic callbacks in static methods */
+    if (!(method->flags & SMETH_MODIFIER))
+    {
+        if (method->pupdate && !(method->flags & SMETH_DYNAMIC))
+        {
+            report_error(fp, method->name, "warning: pupdate not used because the method is static");
+            method->pupdate = NULL;
+        }
+    }
+    /* Check that there is an evaluation function */
+    if (method->type != NO_VALUE && !method->update && !method->pupdate)
+    {
+        report_error(fp, method->name, "error: evaluation function missing");
+        bOk = FALSE;
+    }
+    /* Loop through the parameters to determine if initialization callbacks
+     * are needed. */
+    bNeedInit = FALSE;
+    for (i = 0; i < method->nparams; ++i)
+    {
+        if (method->param[i].val.type != POS_VALUE
+            && (method->param[i].flags & (SPAR_VARNUM | SPAR_ATOMVAL)))
+        {
+            bNeedInit = TRUE;
+        }
+    }
+    /* Check that the callbacks required by the parameters are present */
+    if (bNeedInit && !method->init)
+    {
+        report_error(fp, method->name, "error: init should be provided");
+        bOk = FALSE;
+    }
+    return bOk;
+}
+
+/*!
+ * Checks the validity of a selection method.
+ *
+ * \param[in]     fp     File handle to use for diagnostic messages
+ *   (can be NULL).
+ * \param[in,out] method Method to check.
+ * \param[in]     symtab Symbol table (used for checking overlaps).
+ *
+ * Checks the validity of the given selection method data structure
+ * that does not have \ref SMETH_MODIFIER set.
+ * If you remove a check, please make sure that the selection parser,
+ * compiler, and evaluation functions can deal with the method.
+ */
+static gmx_bool
+check_method(FILE *fp, gmx_ana_selmethod_t *method, gmx_sel_symtab_t *symtab)
+{
+    gmx_bool         bOk = TRUE;
+
+    /* Check the type */
+    if (method->type == NO_VALUE)
+    {
+        report_error(fp, method->name, "error: no value type specified");
+        bOk = FALSE;
+    }
+    if (method->type == STR_VALUE && method->nparams > 0)
+    {
+        report_error(fp, method->name, "error: evaluates to a string but is not a keyword");
+        bOk = FALSE;
+    }
+    /* Check flags */
+    if (method->type == GROUP_VALUE)
+    {
+        /* Group methods should always have SMETH_SINGLEVAL,
+         * so set it for convenience. */
+        method->flags |= SMETH_SINGLEVAL;
+        /* Check that conflicting flags are not present. */
+        if (method->flags & SMETH_VARNUMVAL)
+        {
+            report_error(fp, method->name, "error: SMETH_VARNUMVAL cannot be set for group-valued methods");
+            bOk = FALSE;
+        }
+    }
+    else
+    {
+        if ((method->flags & SMETH_SINGLEVAL)
+            && (method->flags & SMETH_VARNUMVAL))
+        {
+            report_error(fp, method->name, "error: SMETH_SINGLEVAL and SMETH_VARNUMVAL both set");
+            bOk = FALSE;
+        }
+    }
+    if ((method->flags & SMETH_CHARVAL) && method->type != STR_VALUE)
+    {
+        report_error(fp, method->name, "error: SMETH_CHARVAL can only be specified for STR_VALUE methods");
+        bOk = FALSE;
+    }
+    /* Check the parameters */
+    if (!check_params(fp, method->name, method->nparams, method->param, symtab))
+    {
+        bOk = FALSE;
+    }
+    /* Check the callback pointers */
+    if (!check_callbacks(fp, method))
+    {
+        bOk = FALSE;
+    }
+
+    return bOk;
+}
+
+/*!
+ * Checks the validity of a selection modifier method.
+ *
+ * \param[in]     fp     File handle to use for diagnostic messages
+ *   (can be NULL).
+ * \param[in,out] method Method to check.
+ * \param[in]     symtab Symbol table (used for checking overlaps).
+ *
+ * Checks the validity of the given selection method data structure
+ * that has \ref SMETH_MODIFIER set.
+ * If you remove a check, please make sure that the selection parser,
+ * compiler, and evaluation functions can deal with the method.
+ */
+static gmx_bool
+check_modifier(FILE *fp, gmx_ana_selmethod_t *method, gmx_sel_symtab_t *symtab)
+{
+    gmx_bool         bOk = TRUE;
+
+    /* Check the type */
+    if (method->type != NO_VALUE && method->type != POS_VALUE)
+    {
+        report_error(fp, method->name, "error: modifier should have type POS_VALUE or NO_VALUE");
+        bOk = FALSE;
+    }
+    /* Check flags */
+    if (method->flags & (SMETH_SINGLEVAL | SMETH_VARNUMVAL))
+    {
+        report_error(fp, method->name, "error: modifier should not have SMETH_SINGLEVAL or SMETH_VARNUMVAL set");
+        bOk = FALSE;
+    }
+    /* Check the parameters */
+    /* The first parameter is skipped */
+    if (!check_params(fp, method->name, method->nparams-1, method->param+1, symtab))
+    {
+        bOk = FALSE;
+    }
+    /* Check the callback pointers */
+    if (!check_callbacks(fp, method))
+    {
+        bOk = FALSE;
+    }
+    if (method->update)
+    {
+        report_error(fp, method->name, "error: modifier should not have update");
+        bOk = FALSE;
+    }
+    if (method->type == POS_VALUE && !method->pupdate)
+    {
+        report_error(fp, method->name, "error: evaluation function missing");
+        bOk = FALSE;
+    }
+
+    return bOk;
+}
+
+/*!
+ * \param[in,out] symtab Symbol table to register the method to.
+ * \param[in]     name   Name under which the method should be registered.
+ * \param[in]     method Method to register.
+ * \returns       0 on success, EINVAL if there was something wrong with the
+ *   method.
+ *
+ * \p name does not need to match the name of the method, and the same
+ * method can be registered multiple times under different names.
+ * If \p name equals some previously registered name,
+ * an error message is printed and the method is not registered.
+ *
+ * The function also performs some sanity checking on the input method,
+ * and refuses to register it if there are problems.
+ * Some problems only generate warnings.
+ * All problems are described to \p stderr.
+ */
+int
+gmx_ana_selmethod_register(gmx_sel_symtab_t *symtab,
+                           const char *name, gmx_ana_selmethod_t *method)
+{
+    gmx_bool bOk;
+
+    /* Check the method */
+    if (method->flags & SMETH_MODIFIER)
+    {
+        bOk = check_modifier(stderr, method, symtab);
+    }
+    else
+    {
+        bOk = check_method(stderr, method, symtab);
+    }
+    /* Try to register the method if everything is ok */
+    if (bOk) 
+    {
+        if (!_gmx_sel_add_method_symbol(symtab, name, method))
+        {
+            bOk = FALSE;
+        }
+    }
+    if (!bOk)
+    {
+        report_error(stderr, name, "warning: not registered");
+        return EINVAL;
+    }
+    return 0;
+}
+
+/*!
+ * \param[in,out] symtab Symbol table to register the methods to.
+ * \returns       0 on success, -1 if any of the default methods could not be
+ *   registered.
+ */
+int
+gmx_ana_selmethod_register_defaults(gmx_sel_symtab_t *symtab)
+{
+    size_t i;
+    int  rc;
+    gmx_bool bOk;
+
+    bOk = TRUE;
+    for (i = 0; i < asize(smtable_def); ++i)
+    {
+        gmx_ana_selmethod_t *method = smtable_def[i].method;
+
+        if (smtable_def[i].name == NULL)
+        {
+            rc = gmx_ana_selmethod_register(symtab, method->name, method);
+        }
+        else
+        {
+            rc = gmx_ana_selmethod_register(symtab, smtable_def[i].name, method);
+        }
+        if (rc != 0)
+        {
+            bOk = FALSE;
+        }
+    }
+    return bOk ? 0 : -1;
+}
+
+/*!
+ * \param[in] name   Name of the parameter to search.
+ * \param[in] method Method to search for the parameter.
+ * \returns   Pointer to the parameter in the
+ *   \ref gmx_ana_selmethod_t::param "method->param" array,
+ *   or NULL if no parameter with name \p name was found.
+ *
+ * This is a simple wrapper for gmx_ana_selparam_find().
+ */
+gmx_ana_selparam_t *
+gmx_ana_selmethod_find_param(const char *name, gmx_ana_selmethod_t *method)
+{
+    return gmx_ana_selparam_find(name, method->nparams, method->param);
+}
diff --git a/src/gromacs/selection/selmethod.h b/src/gromacs/selection/selmethod.h
new file mode 100644 (file)
index 0000000..0e08994
--- /dev/null
@@ -0,0 +1,668 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \page page_module_selection_custom Custom selection methods
+ *
+ * Custom selection methods are defined by creating a new instance of 
+ * \c gmx_ana_selmethod_t and filling it with the necessary data for handling
+ * the selection.
+ * The structure contains callback pointers that define the actual behavior
+ * of the method.
+ * The following sections discuss how the structure should be filled and how
+ * to implement the callbacks.
+ *
+ *
+ * \section selmethods_define \c gmx_ana_selmethod_t data structure
+ *
+ * An example \c gmx_ana_selmethod_t definition could look like this:
+ *
+ * \code
+ * gmx_ana_selmethod_t sm_example = {
+ *   "example", GROUP_VALUE, 0,
+ *   asize(sm_params_example), sm_params_example,
+ *   &init_data_example,
+ *    NULL,
+ *   &init_example,
+ *    NULL,
+ *   &free_data_example,
+ *   &init_frame_example,
+ *   &evaluate_example,
+ *    NULL,
+ *   {"example from POS_EXPR [cutoff REAL]", 0, NULL},
+ * };
+ * \endcode
+ *
+ * The first value defines the name of the method.
+ * It is used mostly for informational purposes; the actual name(s) recognized
+ * by the selection parser are defined by the call to
+ * gmx_ana_selmethod_register() (see \ref selmethods_register).
+ *
+ * The second value defines the type of the value the method returns.
+ * Possible values are
+ *  - \ref NO_VALUE : This is allowed only for methods that have the flag
+ *    \ref SMETH_MODIFIER set (see \ref selmethods_modifiers).
+ *  - \ref INT_VALUE : The method returns one or more integer values.
+ *  - \ref REAL_VALUE : The method returns one or more floating-point values.
+ *  - \ref STR_VALUE : The method returns one or more strings.
+ *  - \ref POS_VALUE : The method returns one or more 3D vectors.
+ *  - \ref GROUP_VALUE : The method returns a single index group.
+ *
+ * The third value gives additional information about the method using
+ * a combination of flags.
+ * Possible flags are:
+ *  - \ref SMETH_REQTOP : If set, the topology information is always loaded
+ *    and the \p top pointer passed to the callbacks is guaranteed to be
+ *    non-NULL. Should be set if the method requires topology information
+ *    for evaluation.
+ *  - \ref SMETH_DYNAMIC : If set, the method can only be evaluated dynamically,
+ *    i.e., it requires data from the trajectory frame.
+ *  - \ref SMETH_MODIFIER : If set, the method is a selection modifier and
+ *    not an actual selection method.
+ *    For more details, see \ref selmethods_modifiers.
+ *
+ * There are two additional flags that specify the number of values the
+ * method returns. Only one of them can be set at a time.
+ * If neither is set, the default behavior is to evaluate a value for each
+ * input atom (except for \ref GROUP_VALUE methods, which always return a
+ * single group).
+ * Other behaviors can be specified with these flags:
+ *  - \ref SMETH_SINGLEVAL : If set, the method evaluates to a single value.
+ *    This is automatically set if the type is \ref GROUP_VALUE.
+ *  - \ref SMETH_VARNUMVAL : If set, the method evaluates to an arbitrary
+ *    number of values.
+ *    The number of values is determined based on the values given by the user
+ *    to the method parameters (see \ref selmethods_params).
+ *  .
+ * If either of these flags is specified (and the method type is not
+ * \ref GROUP_VALUE), the group passed to the evaluation callback should not
+ * be used as it can be NULL.
+ * Currently, the above flags only work (have been tested) for \ref POS_VALUE
+ * methods.
+ *
+ * There is one additional flag that can only be specified for \ref STR_VALUE
+ * methods: \ref SMETH_CHARVAL . It is meant for to ease implementation of
+ * methods that evaluate to strings consisting of single characters.
+ *
+ * The next two values determine the number of parameters and a pointer to
+ * the parameter array. The contents of the parameter array are described in
+ * \ref selmethods_params. If the method does not take parameters, the first
+ * value should be 0 and the second can be NULL.
+ * Currently, \ref STR_VALUE methods cannot take parameters, but this limitation
+ * should be easy to lift if required.
+ *
+ * These are followed by function callbacks that determine the
+ * actual behavior of the method. Any of these except the evaluation callback
+ * can be NULL (the evaluation callback can also be NULL if \ref NO_VALUE is
+ * specified for a selection modifier). However, the presence of parameters
+ * can require some of the callbacks to be implemented.
+ * The details are described in \ref selmethods_callbacks.
+ *
+ * Finally, there is a data structure that gives help texts for the method.
+ *
+ * The \c gmx_ana_selmethod_t variable should be declared as a global variable
+ * or it should be otherwise ensured that the structure is not freed: only a
+ * pointer to the structure is stored by the library.
+ *
+ *
+ * \section selmethods_params Defining parameters
+ *
+ * Parameters to selection methods are defined in a separate array of
+ * \c gmx_ana_selparam_t structures.
+ * The order of the parameters does not matter (except possibly for callback
+ * implementation), with one important exception:
+ * If the method evaluates to a \ref POS_VALUE, the first parameter should 
+ * have \ref GROUP_VALUE and be the one that is used to calculate the
+ * positions.
+ *
+ * An example parameter definition:
+ * \code
+ * static gmx_ana_selparam_t sm_params_example[] = {
+ *   {"cutoff", {REAL_VALUE, 1, {NULL}}, NULL, SPAR_OPTIONAL},
+ *   {"from",   {POS_VALUE, -1, {NULL}}, NULL, SPAR_DYNAMIC | SPAR_VARNUM},
+ * };
+ * \endcode
+ *
+ * The first value gives the name of the parameter.
+ * The first parameter can have a NULL name, which means that the value should
+ * immediately follow the method name. This can be used to specify methods
+ * of the type 'within 5 of ...'.
+ *
+ * The second value specifies the type of the value that the parameter accepts.
+ * \ref NO_VALUE can be used to specify a boolean parameter, other possibilities
+ * are the same as for the selection method type.
+ *
+ * The third value gives the number of values that the parameter accepts.
+ * For boolean parameters (\ref NO_VALUE), it should be 0.
+ * For parameters with \ref SPAR_VARNUM of \ref SPAR_ATOMVAL, it should be set
+ * to -1 for consistency (it is not used).
+ * If \ref SPAR_RANGES is specified, it should be either 1 (to accept a single
+ * continuous range) or -1 (if combined with \ref SPAR_VARNUM).
+ * In all other cases, it should be a positive integer; in most cases, it
+ * should be 1.
+ *
+ * The nest two pointers should always be NULL (they should be initialized in
+ * the callbacks), except the first pointer in the case of \ref SPAR_ENUMVAL
+ * (see below).
+ *
+ * The final value gives additional information about the acceptable values
+ * for the parameter using a combination of flags.
+ * The possible flags are:
+ *  - \ref SPAR_OPTIONAL : If set, the user does not need to provide a value
+ *    for the parameter. If not set, an error is reported if the parameter
+ *    is not specified by the user.
+ *  - \ref SPAR_DYNAMIC : If set, the method can handle dynamic values for
+ *    the parameter, i.e., the value(s) can be given by an expression that
+ *    evaluates to different values for different frames.
+ *  - \ref SPAR_RANGES : Can be set only for \ref INT_VALUE and
+ *    \ref REAL_VALUE parameters,
+ *    and cannot be combined with \ref SPAR_DYNAMIC.
+ *    If set, the parameter accepts ranges of values.
+ *    The ranges are automatically sorted and compacted such that a minimum
+ *    amount of non-overlapping ranges are given for the method.
+ *  - \ref SPAR_VARNUM : If set, the parameter can have a variable number
+ *    of values. These can be provided by the user as a list of values, or
+ *    using a single \ref SMETH_VARNUMVAL (or a single \ref SMETH_SINGLEVAL)
+ *    method.
+ *  - \ref SPAR_ATOMVAL : If set, the parameter accepts either a single value
+ *    or an expression that evaluates to a value for each input atom.
+ *    The single input value is treated as if the same value was returned for
+ *    each atom.
+ *    Cannot be combined with \ref SPAR_RANGES or \ref SPAR_VARNUM.
+ *  - \ref SPAR_ENUMVAL : Can only be set for \ref STR_VALUE parameters that
+ *    take a single value, and cannot be combined with any other flag than
+ *    \ref SPAR_OPTIONAL. If set, the parameter only accepts one of predefined
+ *    string values. See \ref SPAR_ENUMVAL documentation for details on how
+ *    to specify the acceptable values.
+ *
+ *
+ * \section selmethods_callbacks Implementing callbacks
+ *
+ * There are eight differen callback functions that can be implemented for
+ * selection methods: sel_datafunc(), sel_posfunc(), sel_initfunc(),
+ * sel_outinitfunc(), sel_freefunc(), sel_framefunc(), and two update functions.
+ * They are in this order in the \c gmx_ana_selmethod_t data structure.
+ * In general, any of the callbacks can be NULL, but the presence of
+ * parameters or other callbacks imposes some restrictions:
+ *  - sel_datafunc() should be provided if the method takes parameters.
+ *  - sel_initfunc() should be provided if the method takes
+ *    any parameters with the \ref SPAR_VARNUM or \ref SPAR_ATOMVAL flags,
+ *    except if those parameters have a \ref POS_VALUE.
+ *  - sel_outinitfunc() should be provided for \ref POS_VALUE methods
+ *    and \ref SMETH_VARNUMVAL methods.
+ *  - sel_freefunc() should be provided if sel_datafunc() and/or
+ *    sel_initfunc() allocate any dynamic memory in addition to the data
+ *    structure itself.
+ *  - sel_updatefunc_pos() only makes sense for methods with \ref SMETH_DYNAMIC
+ *    set.
+ *  - At least one update function should be provided unless the method type is
+ *    \ref NO_VALUE.
+ *
+ * The documentations for the function pointer types provide more information
+ * about how the callbacks should be implemented.
+ *
+ *
+ * \section selmethods_modifiers Selection modifiers
+ *
+ * Selection modifiers are a special kind of selection methods that can be
+ * appended to the end of a selection. They are specified by adding the
+ * \ref SMETH_MODIFIER flag to the \c gmx_ana_selmethod_t.
+ * They can have two different types:
+ *  - \ref POS_VALUE : These modifiers are given the final positions
+ *    as an input, and they can make modifications to the selection that are
+ *    not possible otherwise (e.g., permute the atoms).
+ *    The modifier should implement sel_updatefunc_pos() and also have
+ *    one NULL parameter in the beginning of the parameter list that takes
+ *    \ref POS_VALUE and is used to give the input positions.
+ *  - \ref NO_VALUE : These modifiers do not modify the final selection, but
+ *    can be used to implement per-selection options for analysis tools
+ *    or to control the default behavior of the selection engine
+ *    (currently, such a framework is not implemented, but should be easy to
+ *    implement if required).
+ *
+ * In addition to restricting the type of the method, selection modifiers
+ * do not allow the flags \ref SMETH_SINGLEVAL and \ref SMETH_VARNUMVAL
+ * (they would not make sense).
+ *
+ * Parameters and callbacks should be implemented as with normal selection
+ * method, but beware that very little of the functionality has been tested.
+ *
+ * \todo
+ * The modifier handling could be made more flexible and more generic;
+ * the current implementation does not allow many things which would be
+ * possible with slight changes in the internals of the library.
+ *
+ *
+ * \section selmethods_register Registering the method
+ *
+ * After defining the method with \c gmx_ana_selmethod_t, it should be
+ * registered with the selection engine.
+ * In analysis programs, this can be done by calling
+ * gmx_ana_selmethod_register().
+ * If adding the method to the library, you should add a pointer to the new
+ * method structure into the \c smtable_def array (in selmethod.cpp), and it is
+ * registered automatically.
+ * In both cases, gmx_ana_selmethod_register() does several checks on the
+ * structure and reports any errors or inconsistencies it finds.
+ */
+/*! \file
+ * \brief API for handling selection methods.
+ *
+ * There should be no need to use the data structures or call the
+ * functions in this file directly unless implementing a custom selection
+ * method.
+ *
+ * Instructions for implementing custom selection methods can be found
+ * on a separate page: \ref page_module_selection_custom
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_selection
+ */
+#ifndef GMX_SELECTION_SELMETHOD_H
+#define GMX_SELECTION_SELMETHOD_H
+
+#include "../legacyheaders/typedefs.h"
+
+#include "indexutil.h"
+#include "selparam.h"
+#include "selvalue.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+struct gmx_ana_pos_t;
+struct gmx_ana_poscalc_coll_t;
+struct gmx_ana_selcollection_t;
+
+/*! \name Selection method flags
+ * \anchor selmethod_flags
+ */
+/*@{*/
+/*! \brief
+ * If set, the method requires topology information.
+ */
+#define SMETH_REQTOP     1
+/*! \brief
+ * If set, the method can only be evaluated dynamically.
+ */
+#define SMETH_DYNAMIC    2
+/*! \brief
+ * If set, the method evaluates to a single value.
+ *
+ * The default is that the method evaluates to a value for each input atom.
+ * Cannot be combined with \ref SMETH_VARNUMVAL.
+ */
+#define SMETH_SINGLEVAL  4
+/*! \brief
+ * If set, the method evaluates to an arbitrary number of values.
+ *
+ * The default is that the method evaluates to a value for each input atom.
+ * Cannot be combined with \ref SMETH_SINGLEVAL or with \ref GROUP_VALUE.
+ */
+#define SMETH_VARNUMVAL  8
+/*! \brief
+ * If set, the method evaluates to single-character strings.
+ *
+ * This flag can only be set for \ref STR_VALUE methods. If it is set, the
+ * selection engine automatically allocates and frees the required strings.
+ * The evaluation function should store the character values as the first
+ * character in the strings in the output data structure and should not change
+ * the string pointers.
+ */
+#define SMETH_CHARVAL    64
+/*! \brief
+ * If set, the method is a selection modifier.
+ *
+ * The method type should be \ref GROUP_VALUE or \ref NO_VALUE .
+ * Cannot be combined with \ref SMETH_SINGLEVAL or \ref SMETH_VARNUMVAL .
+ */
+#define SMETH_MODIFIER   256
+/*@}*/
+
+/*! \brief
+ * Allocates and initializes internal data and parameter values.
+ *
+ * \param[in]     npar  Number of parameters in \p param.
+ * \param[in,out] param Pointer to (a copy of) the method's
+ *   \c gmx_ana_selmethod_t::param.
+ * \returns       Pointer to method-specific data structure.
+ *   This pointer will be passed as the last parameter of all other function
+ *   calls.
+ *   Should return NULL on error (only error that should occur is out of
+ *   memory).
+ *
+ * Should allocate and initialize any internal data required by the method.
+ * Should also initialize the value pointers (\c gmx_ana_selparam_t::val) in
+ * \p param to point to variables within the internal data structure,
+ * with the exception of parameters that specify the \ref SPAR_VARNUM or
+ * the \ref SPAR_ATOMVAL flag (these should be handled in sel_initfunc()).
+ * However, parameters with a position value should be initialized.
+ * It is also possible to initialize \ref SPAR_ENUMVAL statically outside
+ * this function (see \ref SPAR_ENUMVAL).
+ * The \c gmx_ana_selparam_t::nvalptr should also be initialized for
+ * non-position-valued parameters that have both \ref SPAR_VARNUM and
+ * \ref SPAR_DYNAMIC set (it can also be initialized for other parameters if
+ * desired, but the same information will be available through other means).
+ * For optional parameters, the default values can (and should) be initialized
+ * here, as the parameter values are not changed if the parameter is not
+ * provided.
+ *
+ * For boolean parameters (type equals \ref NO_VALUE), the default value
+ * should be set here. The user can override the value by giving the parameter
+ * either as 'NAME'/'noNAME', or as 'NAME on/off/yes/no'.
+ *
+ * If the method takes any parameters, this function must be provided.
+ */
+typedef void *(*sel_datafunc)(int npar, gmx_ana_selparam_t *param);
+/*! \brief
+ * Sets the position calculation collection for the method.
+ *
+ * \param[in]  pcc   Position calculation collection that the method should use
+ *   for position calculations.
+ * \param      data  Internal data structure from sel_datafunc().
+ *
+ * This function should be provided if the method uses the routines from
+ * poscalc.h for calculating positions.
+ * The pointer \p pcc should then be stored and used for initialization for
+ * any position calculation structures.
+ */
+typedef void  (*sel_posfunc)(struct gmx_ana_poscalc_coll_t *pcc, void *data);
+/*! \brief
+ * Does initialization based on topology and/or parameter values.
+ *
+ * \param[in]  top   Topology structure
+ *   (can be NULL if \ref SMETH_REQTOP is not set).
+ * \param[in]  npar  Number of parameters in \p param.
+ * \param[in]  param Pointer to (an initialized copy of) the method's
+ *   \c gmx_ana_selmethod_t::param.
+ * \param      data  Internal data structure from sel_datafunc().
+ * \returns    0 on success, a non-zero error code on failure.
+ *
+ * This function is called after the parameters have been processed:
+ * the values of the parameters are stored at the locations set in
+ * sel_datafunc().
+ * The flags \ref SPAR_DYNAMIC and \ref SPAR_ATOMVAL are cleared before
+ * calling the function if the value is static or single-valued, respectively.
+ * If a parameter had the \ref SPAR_VARNUM or \ref SPAR_ATOMVAL flag (and
+ * is not \ref POS_VALUE), a pointer to the memory allocated for the values is
+ * found in \c gmx_ana_selparam_t::val.
+ * The pointer should be stored by this function, otherwise the values
+ * cannot be accessed.
+ * For \ref SPAR_VARNUM parameters, the number of values can be accessed
+ * through \c gmx_ana_selparam_t::val. For parameters with \ref SPAR_DYNAMIC,
+ * the number is the maximum number of values (the actual number can be
+ * accessed in sel_framefunc() and in the update callback through the value
+ * pointed by \c gmx_ana_selparam_t::nvalptr).
+ * For \ref SPAR_ATOMVAL parameters, \c gmx_ana_selparam_t::val::nr is set to
+ * 1 if a single value was provided, otherwise it is set to the maximum number
+ * of values possibly passed to the method.
+ * The value pointed by \c gmx_ana_selparam_t::nvalptr always contains the same
+ * value as \c gmx_ana_selparam_t::val::nr.
+ *
+ * For dynamic \ref GROUP_VALUE parameters (\ref SPAR_DYNAMIC set), the value
+ * will be the largest possible selection that may occur during the
+ * evaluation. For other types of dynamic parameters, the values are
+ * undefined.
+ *
+ * If the method takes any parameters with the \ref SPAR_VARNUM or
+ * \ref SPAR_ATOMVAL flags, this function must be provided, except if these
+ * parameters all have \ref POS_VALUE.
+ *
+ * This function may be called multiple times for the same method if the
+ * method takes parameters with \ref SPAR_ATOMVAL set.
+ */
+typedef int   (*sel_initfunc)(t_topology *top, int npar,
+                              gmx_ana_selparam_t *param, void *data);
+/*! \brief
+ * Initializes output data structure.
+ *
+ * \param[in]     top   Topology structure
+ *   (can be NULL if \ref SMETH_REQTOP is not set).
+ * \param[in,out] out   Output data structure.
+ * \param[in]     data  Internal data structure from sel_datafunc().
+ * \returns       0 on success, an error code on error.
+ *
+ * This function is called immediately after sel_initfunc().
+ *
+ * If the method evaluates to a position (\ref POS_VALUE), this function
+ * should be provided, and it should initialize the \c gmx_ana_pos_t data
+ * structure pointed by \p out.p (the pointer is guaranteed to be non-NULL).
+ * The \p out.p->g pointer should be initialized to the group that is used
+ * to evaluate positions in sel_updatefunc() or sel_updatefunc_pos().
+ *
+ * The function should also be provided for non-position-valued
+ * \ref SMETH_VARNUMVAL methods. For these methods, it suffices to set the
+ * \p out->nr field to reflect the maximum number of values returned by the
+ * method.
+ *
+ * Currently, this function is not needed for other types of methods.
+ *
+ * This function may be called multiple times for the same method if the
+ * method takes parameters with \ref SPAR_ATOMVAL set.
+ */
+typedef int   (*sel_outinitfunc)(t_topology *top, gmx_ana_selvalue_t *out,
+                                 void *data);
+/*! \brief
+ * Frees the internal data.
+ *
+ * \param[in] data Internal data structure from sel_datafunc().
+ *
+ * This function should be provided if the internal data structure contains
+ * dynamically allocated data, and should free any such data.
+ * The data structure itself should not be freed; this is handled automatically.
+ * If there is no dynamically allocated data within the structure,
+ * this function is not needed.
+ * Any memory pointers received as values of parameters are managed externally,
+ * and should not be freed.
+ * Pointers set as the value pointer of \ref SPAR_ENUMVAL parameters should not
+ * be freed.
+ */
+typedef void  (*sel_freefunc)(void *data);
+
+/*! \brief
+ * Initializes the evaluation for a new frame.
+ *
+ * \param[in]  top  Topology structure
+ *   (can be NULL if \ref SMETH_REQTOP is not set).
+ * \param[in]  fr   Current frame.
+ * \param[in]  pbc  Initialized periodic boundary condition structure,
+ *   or NULL if PBC should not be used.
+ * \param      data Internal data structure from sel_datafunc().
+ * \returns    0 on success, a non-zero error code on failure.
+ *
+ * This function should be implemented if the selection method needs to
+ * do some preprocessing for each frame, and the preprocessing does not
+ * depend on the evaluation group.
+ * Because \p sel_updatefunc_* can be called more than once for a frame,
+ * it is inefficient do the preprocessing there.
+ * It is ensured that this function will be called before
+ * \p sel_updatefunc_* for each frame, and that it will be called at most
+ * once for each frame.
+ * For static methods, it is called once, with \p fr and \p pbc set to
+ * NULL.
+ */
+typedef int   (*sel_framefunc)(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+                               void *data);
+/*! \brief
+ * Evaluates a selection method.
+ *
+ * \param[in]  top  Topology structure
+ *   (can be NULL if \ref SMETH_REQTOP is not set).
+ * \param[in]  fr   Current frame.
+ * \param[in]  pbc  Initialized periodic boundary condition structure,
+ *   or NULL if PBC should not be used.
+ * \param[in]  g    Index group for which the method should be evaluated.
+ * \param[out] out  Output data structure.
+ * \param      data Internal data structure from sel_datafunc().
+ * \returns    0 on success, a non-zero error code on error.
+ *
+ * This function should evaluate the method for each atom included in \p g,
+ * and write the output to \p out. The pointer in the union \p out->u that
+ * corresponds to the type of the method should be used.
+ * Enough memory has been allocated to store the output values.
+ * The number of values in \p out should also be updated if necessary.
+ * However, \ref POS_VALUE or \ref GROUP_VALUE methods should not touch
+ * \p out->nr (it should be 1 anyways).
+ *
+ * For \ref STR_VALUE methods, the pointers stored in \p out->s are discarded
+ * without freeing; it is the responsibility of this function to provide
+ * pointers that can be discarded without memory leaks.
+ */
+typedef int   (*sel_updatefunc)(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+                                gmx_ana_index_t *g, gmx_ana_selvalue_t *out,
+                                void *data);
+/*! \brief
+ * Evaluates a selection method using positions.
+ *
+ * \param[in]  top  Topology structure
+ *   (can be NULL if \ref SMETH_REQTOP is not set).
+ * \param[in]  fr   Current frame.
+ * \param[in]  pbc  Initialized periodic boundary condition structure,
+ *   or NULL if PBC should not be used.
+ * \param[in]  pos  Positions for which the method should be evaluated.
+ * \param[out] out  Output data structure.
+ * \param      data Internal data structure from sel_datafunc().
+ * \returns    0 on success, a non-zero error code on error.
+ *
+ * This function should evaluate the method for each position in \p g,
+ * and write the output values to \p out. The pointer in the union \p out->u
+ * that corresponds to the type of the method should be used.
+ * Enough memory has been allocated to store the output values.
+ * The number of values in \p out should also be updated if necessary.
+ * However, \ref POS_VALUE or \ref GROUP_VALUE methods should not touch
+ * \p out->nr (it should be 1 anyways).
+ *
+ * For \ref STR_VALUE methods, the pointers stored in \p out->s are discarded
+ * without freeing; it is the responsibility of this function to provide
+ * pointers that can be discarded without memory leaks.
+ */
+typedef int   (*sel_updatefunc_pos)(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+                                    struct gmx_ana_pos_t *pos,
+                                    gmx_ana_selvalue_t *out,
+                                    void *data);
+
+/*! \brief
+ * Help information for a selection method.
+ *
+ * If some information is not available, the corresponding field can be set to
+ * 0/NULL.
+ */
+typedef struct gmx_ana_selmethod_help_t
+{
+    /*! \brief
+     * One-line description of the syntax of the method.
+     *
+     * If NULL, the name of the method is used.
+     */
+    const char         *syntax;
+    /*! \brief
+     * Number of strings in \p help.
+     *
+     * Set to 0 if \p help is NULL.
+     */
+    int                 nlhelp;
+    /*! \brief
+     * Detailed help for the method.
+     *
+     * If there is no help available in addition to \p syntax, this can be set
+     * to NULL.
+     */
+    const char        **help;
+} gmx_ana_selmethod_help_t;
+
+/*! \brief
+ * Describes a selection method.
+ *
+ * Any of the function pointers except the update call can be NULL if the
+ * operation is not required or not supported. In this case,
+ * corresponding function calls are skipped.
+ *
+ * See the function pointer type documentation for details of how the
+ * functions should be implemented.
+ * More details on implementing new selection methods can be found on a
+ * separate page: \ref page_module_selection_custom.
+ */
+typedef struct gmx_ana_selmethod_t
+{
+    /** Name of the method. */
+    const char         *name;
+    /** Type which the method returns. */
+    e_selvalue_t        type;
+    /*! \brief
+     * Flags to specify how the method should be handled.
+     *
+     * See \ref selmethod_flags for allowed values.
+     */
+    int                 flags;
+    /** Number of parameters the method takes. */
+    int                 nparams;
+    /** Pointer to the array of parameter descriptions. */
+    gmx_ana_selparam_t *param;
+
+    /** Function for allocating and initializing internal data and parameters. */
+    sel_datafunc        init_data;
+    /** Function to set the position calculation collection. */
+    sel_posfunc         set_poscoll;
+    /** Function to do initialization based on topology and/or parameter values. */
+    sel_initfunc        init;
+    /** Function to initialize output data structure. */
+    sel_outinitfunc     outinit;
+    /** Function to free the internal data. */
+    sel_freefunc        free;
+
+    /** Function to initialize the calculation for a new frame. */
+    sel_framefunc       init_frame;
+    /** Function to evaluate the value. */
+    sel_updatefunc      update;
+    /** Function to evaluate the value using positions. */
+    sel_updatefunc_pos  pupdate;
+
+    /** Help data for the method. */
+    gmx_ana_selmethod_help_t help;
+} gmx_ana_selmethod_t;
+
+/** Registers a selection method. */
+int
+gmx_ana_selmethod_register(struct gmx_sel_symtab_t *symtab,
+                           const char *name, gmx_ana_selmethod_t *method);
+/** Registers all selection methods in the library. */
+int
+gmx_ana_selmethod_register_defaults(struct gmx_sel_symtab_t *symtab);
+
+/** Finds a parameter from a selection method by name. */
+gmx_ana_selparam_t *
+gmx_ana_selmethod_find_param(const char *name, gmx_ana_selmethod_t *method);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/gromacs/selection/selparam.h b/src/gromacs/selection/selparam.h
new file mode 100644 (file)
index 0000000..507d0fc
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \file
+ * \brief API for handling parameters used in selections.
+ *
+ * There should be no need to use the data structures or call the
+ * functions in this file directly unless implementing a custom selection
+ * method.
+ *
+ * More details can be found on the page discussing
+ * \ref page_module_selection_custom "custom selection methods".
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_selection
+ */
+#ifndef GMX_SELECTION_SELPARAM_H
+#define GMX_SELECTION_SELPARAM_H
+
+#include "indexutil.h"
+#include "selvalue.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*! \name Parameter flags
+ * \anchor selparam_flags
+ */
+/*@{*/
+/*! \brief
+ * This flag is set if the user has provided the parameter.
+ *
+ * This flag is set automatically, and should not be set by the user.
+ */
+#define SPAR_SET      1
+/*! \brief
+ * If not set, an error is reported if the parameter is not specified by the
+ * user.
+ */
+#define SPAR_OPTIONAL 2
+/*! \brief
+ * If set, the parameter value can be dynamic, i.e., be different for
+ * different frames.
+ *
+ * If set, the parameter value should only be accessed in the update function
+ * of \c gmx_ana_selmethod_t.
+ * The flag is cleared before sel_initfunc() if the value provided is actually
+ * static.
+ */
+#define SPAR_DYNAMIC  4
+/*! \brief
+ * If set, the parameter value is parsed into sorted ranges.
+ *
+ * Can only be specified for integer parameters.
+ * If specified, the value of the parameter (\c gmx_ana_selparam_t::val)
+ * consists of sets of two integers, each specifying a range.
+ * The values give the endpoints of the ranges (inclusive).
+ * The ranges are sorted and overlapping/continuous ranges are merged into
+ * a single range to minimize the number of ranges.
+ *
+ * If this flag is specified, \c gmx_ana_selparam_t::nval gives the number of
+ * ranges. \p gmx_ana_selparam_t::nval should be 1 or \ref SPAR_VARNUM should be
+ * specified; other values would lead to unpredictable behavior.
+ */
+#define SPAR_RANGES   8
+/*! \brief
+ * If set, the parameter can have any number of values.
+ *
+ * If specified, the data pointer in \c gmx_ana_selparam_t::val should be NULL;
+ * the memory is allocated by the parameter parser.
+ * The implementation of the method should ensure that the pointer to the
+ * allocated memory is stored somewhere in sel_initfunc();
+ * otherwise, the memory is lost.
+ *
+ * The initial value of \c gmx_ana_selparam_t::nval is not used with this flag.
+ * Instead, it will give the number of actual values provided by the user
+ * after the parameters have been parsed.
+ * For consistency, it should be initialized to -1.
+ *
+ * Cannot be combined with \ref GROUP_VALUE parameters.
+ */
+#define SPAR_VARNUM   16
+/*! \brief
+ * If set, the parameter can have a separate value for each atom.
+ *
+ * The flag is cleared before sel_initfunc() if the value provided is actually
+ * a single value.
+ *
+ * Cannot be combined with \ref POS_VALUE or \ref GROUP_VALUE parameters.
+ */
+#define SPAR_ATOMVAL  32
+/*! \brief
+ * If set, the parameter takes one of a set of predefined strings.
+ *
+ * Can only be specified for a \ref STR_VALUE parameter that takes a single
+ * string.
+ * The data pointer in \c gmx_ana_selparam_t::val should be initialized into an
+ * array of strings such that the first and last elements are NULL, and the
+ * rest give the possible values. For optional values, the second element in
+ * the array should give the default value. The string given by the user is
+ * matched against the beginnings of the given strings, and if a unique match
+ * is found, the first pointer in the array will be initialized to point to
+ * the matching string.
+ * The data pointer can be initialized as a static array; duplication of the
+ * array for multiple instances of the same method is automatically taken care
+ * of.
+ */
+#define SPAR_ENUMVAL  128
+/*@}*/
+
+/*! \brief
+ * Describes a single parameter for a selection method.
+ */
+typedef struct gmx_ana_selparam_t
+{
+    /** Name of the parameter. */
+    const char         *name;
+    /*! \brief
+     * The parameter value.
+     *
+     * Type \ref NO_VALUE can be used to define a boolean parameter.
+     * The number of values should be 0 for boolean parameters.
+     *
+     * The value pointer be initialized to NULL in the definition of a
+     * \c gmx_ana_selmethod_t and initialized in the
+     * \c gmx_ana_selmethod_t::init_data call
+     * (see sel_datafunc()).
+     * However, if \ref SPAR_VARNUM is provided and the parameter is not
+     * \ref POS_VALUE, this field should not be initialized. Instead,
+     * sufficient memory is allocated automatically and the pointer should be
+     * stored in \c gmx_ana_selmethod_t::init
+     * (see sel_initfunc()).
+     *
+     * The values cannot be accessed outside these two functions: the compiler
+     * makes a copy of the parameter structure for each instance of the
+     * method, and the original parameter array is not changed.
+     */
+    gmx_ana_selvalue_t  val;
+    /*! \brief
+     * Pointer to store the number of values.
+     *
+     * If not NULL, the number of values for the parameter is stored in the
+     * pointed value.
+     * Should be specified if \ref SPAR_VARNUM and \ref SPAR_DYNAMIC are both
+     * set.
+     *
+     * Should be initialized to NULL in the definition a \c gmx_ana_selmethod_t
+     * and initialized in sel_datafunc().
+     */
+    int                *nvalptr;
+    /*! \brief
+     * Flags that alter the way the parameter is parsed/handled.
+     *
+     * See \ref selparam_flags for allowed values.
+     */
+    int                 flags;
+} gmx_ana_selparam_t;
+
+/** Finds a parameter from an array by name. */
+gmx_ana_selparam_t *
+gmx_ana_selparam_find(const char *name, int nparam, gmx_ana_selparam_t *param);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/gromacs/selection/selvalue.cpp b/src/gromacs/selection/selvalue.cpp
new file mode 100644 (file)
index 0000000..5c455ca
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * Implements functions in selvalue.h.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_selection
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <smalloc.h>
+
+#include "gromacs/selection/indexutil.h"
+#include "gromacs/selection/position.h"
+#include "gromacs/selection/selvalue.h"
+
+/*!
+ * \param[out] val  Output structure
+ *
+ * The type of \p val is not touched.
+ * Any contents of \p val are discarded without freeing.
+ */
+void
+_gmx_selvalue_clear(gmx_ana_selvalue_t *val)
+{
+    val->nr     = 0;
+    val->u.ptr  = NULL;
+    val->nalloc = 0;
+}
+
+/*!
+ * \param[in,out] val  Value structure to allocate.
+ * \param[in]     n    Maximum number of values needed.
+ * \returns       Zero on success.
+ *
+ * Reserves memory for the values within \p val to store at least \p n values,
+ * of the type specified in the \p val structure.
+ *
+ * If the type is \ref POS_VALUE or \ref GROUP_VALUE, memory is reserved for
+ * the data structures, but no memory is reserved inside these newly allocated
+ * data structures.
+ * Similarly, for \ref STR_VALUE values, the pointers are set to NULL.
+ * For other values, the memory is uninitialized.
+ */
+int
+_gmx_selvalue_reserve(gmx_ana_selvalue_t *val, int n)
+{
+    int  i;
+
+    if (val->nalloc == -1)
+    {
+        return 0;
+    }
+
+    if (!val->u.ptr || val->nalloc < n)
+    {
+        switch (val->type)
+        {
+            case INT_VALUE:   srenew(val->u.i, n); break;
+            case REAL_VALUE:  srenew(val->u.r, n); break;
+            case STR_VALUE:
+                srenew(val->u.s, n);
+                for (i = val->nalloc; i < n; ++i)
+                {
+                    val->u.s[i] = NULL;
+                }
+                break;
+            case POS_VALUE:
+                srenew(val->u.p, n);
+                for (i = val->nalloc; i < n; ++i)
+                {
+                    gmx_ana_pos_clear(&val->u.p[i]);
+                }
+                break;
+            case GROUP_VALUE:
+                srenew(val->u.g, n);
+                for (i = val->nalloc; i < n; ++i)
+                {
+                    gmx_ana_index_clear(&val->u.g[i]);
+                }
+                break;
+            case NO_VALUE:    break;
+        }
+        val->nalloc = n;
+    }
+    return 0;
+}
+
+/*!
+ * \param[in,out] val    Value structure to allocate.
+ * \param[in]     ptr    Pointer where the values should be stored.
+ * \returns       Zero on success.
+ *
+ * Automatic memory management is disabled for \p ptr, unless \p ptr is NULL.
+ */
+int
+_gmx_selvalue_setstore(gmx_ana_selvalue_t *val, void *ptr)
+{
+    val->u.ptr  = ptr;
+    val->nalloc = (ptr ? -1 : 0);
+    return 0;
+}
+
+/*!
+ * \param[in,out] val    Value structure to allocate.
+ * \param[in]     ptr    Pointer where the values should be stored.
+ * \param[in]     nalloc Number of values allocated for \p ptr.
+ * \returns       Zero on success.
+ */
+int
+_gmx_selvalue_setstore_alloc(gmx_ana_selvalue_t *val, void *ptr, int nalloc)
+{
+    val->u.ptr  = ptr;
+    val->nalloc = nalloc;
+    return 0;
+}
diff --git a/src/gromacs/selection/selvalue.h b/src/gromacs/selection/selvalue.h
new file mode 100644 (file)
index 0000000..e789ef5
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \file
+ * \brief
+ * Declares ::gmx_ana_selvalue_t.
+ *
+ * There should be no need to use the data structures in this file directly
+ * unless implementing a custom selection routine.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_selection
+ */
+#ifndef GMX_SELECTION_SELVALUE_H
+#define GMX_SELECTION_SELVALUE_H
+
+#include "../legacyheaders/types/simple.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/** Defines the value type of a different selection objects. */
+typedef enum
+{
+    NO_VALUE,           /**< No value; either an error condition or an gmx_boolean 
+                             parameter. */
+    INT_VALUE,          /**< One or more integer values. */
+    REAL_VALUE,         /**< One or more real values. */
+    STR_VALUE,          /**< One or more string values. */
+    POS_VALUE,          /**< One or more position values. */
+    GROUP_VALUE         /**< One group of atoms. */
+} e_selvalue_t;
+
+/*! \brief
+ * Describes a value of a selection expression or of a selection method
+ * parameter.
+ *
+ * Which field in the union is used depends on the \p type.
+ */
+typedef struct gmx_ana_selvalue_t
+{
+    /** Type of the value. */
+    e_selvalue_t                type;
+    /*! \brief
+     * Number of values in the array pointed by the union.
+     *
+     * Note that for position and group values, it is the number of
+     * data structures in the array, not the number of positions or
+     * the number of atoms in the group.
+     */
+    int                         nr;
+    /** Pointer to the value. */
+    union {
+        /*! \brief
+         * Generic pointer for operations that do not need type information.
+         *
+         * Needs to be the first member to be able to use initialized arrays.
+         */
+        void                   *ptr;
+        /** Integer value(s) (type \ref INT_VALUE). */
+        int                    *i;
+        /** Real value(s) (type \ref REAL_VALUE). */
+        real                   *r;
+        /** String value(s) (type \ref STR_VALUE). */
+        char                  **s;
+        /** Structure for the position value(s) (type \ref POS_VALUE). */
+        struct gmx_ana_pos_t   *p;
+        /** Group value (type \ref GROUP_VALUE). */
+        struct gmx_ana_index_t *g;
+        /** Boolean value (only parameters of type \ref NO_VALUE); */
+        gmx_bool                   *b;
+    }                           u;
+    /*! \brief
+     * Number of elements allocated for the value array.
+     */
+    int                         nalloc;
+} gmx_ana_selvalue_t;
+
+/** Initializes an empty selection value structure. */
+void
+_gmx_selvalue_clear(gmx_ana_selvalue_t *val);
+/** Reserve memory for storing selection values. */
+int
+_gmx_selvalue_reserve(gmx_ana_selvalue_t *val, int n);
+/** Sets the memory for storing selection values. */
+int
+_gmx_selvalue_setstore(gmx_ana_selvalue_t *val, void *ptr);
+/** Sets the memory for storing selection values and marks it for automatic freeing. */
+int
+_gmx_selvalue_setstore_alloc(gmx_ana_selvalue_t *val, void *ptr, int nalloc);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/gromacs/selection/sm_compare.cpp b/src/gromacs/selection/sm_compare.cpp
new file mode 100644 (file)
index 0000000..d5aeb5e
--- /dev/null
@@ -0,0 +1,623 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * Implements internal selection method for comparison expressions.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_selection
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <maths.h>
+#include <macros.h>
+#include <smalloc.h>
+#include <gmx_fatal.h>
+
+#include "gromacs/selection/selmethod.h"
+
+/** Defines the comparison operator for comparison expressions. */
+typedef enum
+{
+    CMP_INVALID,        /**< Indicates an error */
+    CMP_LESS,           /**< '<' */
+    CMP_LEQ,            /**< '<=' */
+    CMP_GTR,            /**< '>' */
+    CMP_GEQ,            /**< '>=' */
+    CMP_EQUAL,          /**< '==' */
+    CMP_NEQ             /**< '!=' */
+} e_comparison_t;
+
+/** The operand has a single value. */
+#define CMP_SINGLEVAL  1
+/** The operand value is dynamic. */
+#define CMP_DYNAMICVAL 2
+/** The value is real. */
+#define CMP_REALVAL    4
+/** The integer array is allocated. */
+#define CMP_ALLOCINT   16
+/** The real array is allocated. */
+#define CMP_ALLOCREAL  32
+
+/*! \internal \brief
+ * Data structure for comparison expression operand values.
+ */
+typedef struct
+{
+    /** Flags that describe the type of the operand. */
+    int             flags;
+    /** (Array of) integer value(s). */
+    int        *i;
+    /** (Array of) real value(s). */
+    real       *r;
+} t_compare_value;
+
+/*! \internal \brief
+ * Data structure for comparison expression evaluation.
+ */
+typedef struct
+{
+    /** Comparison operator as a string. */
+    char            *cmpop;
+    /** Comparison operator type. */
+    e_comparison_t   cmpt;
+    /** Left value. */
+    t_compare_value  left;
+    /** Right value. */
+    t_compare_value  right;
+} t_methoddata_compare;
+
+/** Allocates data for comparison expression evaluation. */
+static void *
+init_data_compare(int npar, gmx_ana_selparam_t *param);
+/** Initializes data for comparison expression evaluation. */
+static int
+init_compare(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
+/** Frees the memory allocated for comparison expression evaluation. */
+static void
+free_data_compare(void *data);
+/** Evaluates comparison expressions. */
+static int
+evaluate_compare(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+                 gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
+
+/** Parameters for comparison expression evaluation. */
+static gmx_ana_selparam_t smparams_compare[] = {
+    {"int1",  {INT_VALUE,  -1, {NULL}}, NULL,
+     SPAR_OPTIONAL | SPAR_DYNAMIC | SPAR_ATOMVAL},
+    {"real1", {REAL_VALUE, -1, {NULL}}, NULL,
+     SPAR_OPTIONAL | SPAR_DYNAMIC | SPAR_ATOMVAL},
+    {"op",    {STR_VALUE,   1, {NULL}}, NULL, 0},
+    {"int2",  {INT_VALUE,  -1, {NULL}}, NULL,
+     SPAR_OPTIONAL | SPAR_DYNAMIC | SPAR_ATOMVAL},
+    {"real2", {REAL_VALUE, -1, {NULL}}, NULL,
+     SPAR_OPTIONAL | SPAR_DYNAMIC | SPAR_ATOMVAL},
+};
+
+/** \internal Selection method data for comparison expression evaluation. */
+gmx_ana_selmethod_t sm_compare = {
+    "cmp", GROUP_VALUE, SMETH_SINGLEVAL,
+    asize(smparams_compare), smparams_compare,
+    &init_data_compare,
+    NULL,
+    &init_compare,
+    NULL,
+    &free_data_compare,
+    NULL,
+    &evaluate_compare,
+    NULL,
+    {NULL, 0, NULL},
+};
+
+/*! \brief
+ * Returns a \c e_comparison_t value corresponding to an operator.
+ *
+ * \param[in] str  String to process.
+ * \returns   The comparison type corresponding to the first one or two
+ *   characters of \p str.
+ *
+ * \p str can contain any number of characters; only the first two
+ * are used.
+ * If the beginning of \p str does not match any of the recognized types,
+ * \ref CMP_INVALID is returned.
+ */
+static e_comparison_t
+comparison_type(char *str)
+{
+    switch (str[0])
+    {
+        case '<': return (str[1] == '=') ? CMP_LEQ   : CMP_LESS;
+        case '>': return (str[1] == '=') ? CMP_GEQ   : CMP_GTR;
+        case '=': return (str[1] == '=') ? CMP_EQUAL : CMP_INVALID;
+        case '!': return (str[1] == '=') ? CMP_NEQ   : CMP_INVALID;
+    }
+    return CMP_INVALID;
+}
+
+/*! \brief
+ * Returns a string corresponding to a \c e_comparison_t value.
+ *
+ * \param[in] cmpt  Comparison type to convert.
+ * \returns   Pointer to a string that corresponds to \p cmpt.
+ *
+ * The return value points to a string constant and should not be \p free'd.
+ * 
+ * The function returns NULL if \p cmpt is not one of the valid values.
+ */
+static const char *
+comparison_type_str(e_comparison_t cmpt)
+{
+    switch (cmpt)
+    {
+        case CMP_INVALID: return "INVALID"; break;
+        case CMP_LESS:    return "<";  break;
+        case CMP_LEQ:     return "<="; break;
+        case CMP_GTR:     return ">";  break;
+        case CMP_GEQ:     return ">="; break;
+        case CMP_EQUAL:   return "=="; break;
+        case CMP_NEQ:     return "!="; break;
+    }
+    return NULL;
+}
+
+/*!
+ * \param[in] fp    File to receive the output.
+ * \param[in] data  Should point to a \c t_methoddata_compare.
+ */
+void
+_gmx_selelem_print_compare_info(FILE *fp, void *data)
+{
+    t_methoddata_compare *d = (t_methoddata_compare *)data;
+
+    fprintf(fp, " \"");
+    /* Print the left value */
+    if ((d->left.flags & CMP_SINGLEVAL) && !(d->left.flags & CMP_DYNAMICVAL))
+    {
+        if (d->left.flags & CMP_REALVAL)
+        {
+            fprintf(fp, "%f ", d->left.r[0]);
+        }
+        else
+        {
+            fprintf(fp, "%d ", d->left.i[0]);
+        }
+    }
+    /* Print the operator */
+    if (d->cmpt != CMP_INVALID)
+    {
+        fprintf(fp, "%s", comparison_type_str(d->cmpt));
+    }
+    else
+    {
+        fprintf(fp, "%s", d->cmpop);
+    }
+    /* Print the right value */
+    if ((d->right.flags & CMP_SINGLEVAL) && !(d->right.flags & CMP_DYNAMICVAL))
+    {
+        if (d->right.flags & CMP_REALVAL)
+        {
+            fprintf(fp, " %f", d->right.r[0]);
+        }
+        else
+        {
+            fprintf(fp, " %d", d->right.i[0]);
+        }
+    }
+    fprintf(fp, "\"");
+}
+
+/*!
+ * \param[in]     npar  Not used (should be 5).
+ * \param[in,out] param Method parameters (should point to a copy of
+ *   \ref smparams_compare).
+ * \returns       Pointer to the allocated data (\c t_methoddata_compare).
+ *
+ * Allocates memory for a \c t_methoddata_compare structure.
+ */
+static void *
+init_data_compare(int npar, gmx_ana_selparam_t *param)
+{
+    t_methoddata_compare *data;
+
+    snew(data, 1);
+    param[2].val.u.s = &data->cmpop;
+    return data;
+}
+
+/* \brief
+ * Reverses a comparison operator.
+ *
+ * \param[in] type  Comparison operator to reverse.
+ * \returns   The correct comparison operator that equals \p type when the
+ *   left and right sides are interchanged.
+ */
+static e_comparison_t
+reverse_comparison_type(e_comparison_t type)
+{
+    switch (type)
+    {
+        case CMP_LESS: return CMP_GTR;
+        case CMP_LEQ:  return CMP_GEQ;
+        case CMP_GTR:  return CMP_LESS;
+        case CMP_GEQ:  return CMP_LEQ;
+        default:       break;
+    }
+    return type;
+}
+
+/*! \brief
+ * Initializes the value storage for comparison expression.
+ *
+ * \param[out] val   Value structure to initialize.
+ * \param[in]  param Parameters to use for initialization.
+ * \returns    The number of values provided for the value, 0 on error.
+ */
+static int
+init_comparison_value(t_compare_value *val, gmx_ana_selparam_t param[2])
+{
+    int  n;
+
+    val->flags = 0;
+    if (param[0].flags & SPAR_SET)
+    {
+        val->flags |=  (param[0].flags & SPAR_DYNAMIC) ? CMP_DYNAMICVAL : 0;
+        val->flags |= !(param[0].flags & SPAR_ATOMVAL) ? CMP_SINGLEVAL  : 0;
+        n           = param[0].val.nr;
+        val->i      = param[0].val.u.i;
+    }
+    else if (param[1].flags & SPAR_SET)
+    {
+        val->flags |=  (param[1].flags & SPAR_DYNAMIC) ? CMP_DYNAMICVAL : 0;
+        val->flags |= !(param[1].flags & SPAR_ATOMVAL) ? CMP_SINGLEVAL  : 0;
+        val->flags |= CMP_REALVAL;
+        n           = param[1].val.nr;
+        val->r      = param[1].val.u.r;
+    }
+    else
+    {
+        n           = 0;
+        val->i      = NULL;
+        val->r      = NULL;
+    }
+    return n;
+}
+
+/* \brief
+ * Converts an integer value to floating point.
+ *
+ * \param[in]     n   Number of values in the \p val->u array.
+ * \param[in,out] val Value to convert.
+ */
+static void
+convert_int_real(int n, t_compare_value *val)
+{
+    int   i;
+    real *rv;
+
+    snew(rv, n);
+    for (i = 0; i < n; ++i)
+    {
+        rv[i] = (real)val->i[i];
+    }
+    /* Free the previous value if one is present. */
+    sfree(val->r);
+    val->r      = rv;
+    val->flags |= CMP_REALVAL | CMP_ALLOCREAL;
+}
+
+/* \brief
+ * Converts a floating point value to integer.
+ *
+ * \param[in]     n      Number of values in the \p val->u array.
+ * \param[in,out] val    Value to convert.
+ * \param[in]     cmpt   Comparison operator type.
+ * \param[in]     bRight TRUE if \p val appears on the right hand size of
+ *   \p cmpt.
+ * \returns       0 on success, EINVAL on error.
+ *
+ * The values are rounded such that the same comparison operator can be used.
+ */
+static int
+convert_real_int(int n, t_compare_value *val, e_comparison_t cmpt, gmx_bool bRight)
+{
+    int   i;
+    int  *iv;
+
+    if (!bRight)
+    {
+        cmpt = reverse_comparison_type(cmpt);
+    }
+    snew(iv, n);
+    /* Round according to the comparison type */
+    for (i = 0; i < n; ++i)
+    {
+        switch (cmpt)
+        {
+            case CMP_LESS:
+            case CMP_GEQ:
+                iv[i] = (int)ceil(val->r[i]);
+                break;
+            case CMP_GTR:
+            case CMP_LEQ:
+                iv[i] = (int)floor(val->r[i]);
+                break;
+            case CMP_EQUAL:
+            case CMP_NEQ:
+                fprintf(stderr, "comparing equality an integer expression and a real value\n");
+                sfree(iv);
+                return EINVAL;
+            case CMP_INVALID: /* Should not be reached */
+                gmx_bug("internal error");
+                sfree(iv);
+                return EINVAL;
+        }
+    }
+    /* Free the previous value if one is present. */
+    sfree(val->i);
+    val->i      = iv;
+    val->flags &= ~CMP_REALVAL;
+    val->flags |= CMP_ALLOCINT;
+    return 0;
+}
+
+/*!
+ * \param[in] top   Not used.
+ * \param[in] npar  Not used (should be 5).
+ * \param[in] param Method parameters (should point to \ref smparams_compare).
+ * \param[in] data  Should point to a \c t_methoddata_compare.
+ * \returns   0 if the input data is valid, -1 on error.
+ */
+static int
+init_compare(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data)
+{
+    t_methoddata_compare *d = (t_methoddata_compare *)data;
+    int                   n1, n2;
+
+    /* Store the values */
+    n1 = init_comparison_value(&d->left, &param[0]);
+    n2 = init_comparison_value(&d->right, &param[3]);
+    if (n1 == 0 || n2 == 0)
+    {
+        gmx_bug("one of the values for comparison missing");
+        return -1;
+    }
+    /* Store the comparison type */
+    d->cmpt = comparison_type(d->cmpop);
+    if (d->cmpt == CMP_INVALID)
+    {
+        gmx_bug("invalid comparison type");
+        return -1;
+    }
+    /* Convert the values to the same type */
+    if ((d->left.flags & CMP_REALVAL) && !(d->right.flags & CMP_REALVAL))
+    {
+        if (d->left.flags & d->right.flags & CMP_DYNAMICVAL)
+        {
+            /* Nothing can be done */
+        }
+        else if (!(d->right.flags & CMP_DYNAMICVAL))
+        {
+            convert_int_real(n2, &d->right);
+        }
+        else /* d->left is static */
+        {
+            if (convert_real_int(n1, &d->left, d->cmpt, FALSE))
+            {
+                return -1;
+            }
+        }
+    }
+    else if (!(d->left.flags & CMP_REALVAL) && (d->right.flags & CMP_REALVAL))
+    {
+        if (d->left.flags & d->right.flags & CMP_DYNAMICVAL)
+        {
+            /* Reverse the sides to place the integer on the right */
+            int    flags;
+            d->left.r  = d->right.r;
+            d->right.r = NULL;
+            d->right.i = d->left.i;
+            d->left.i  = NULL;
+            flags          = d->left.flags;
+            d->left.flags  = d->right.flags;
+            d->right.flags = flags;
+            d->cmpt = reverse_comparison_type(d->cmpt);
+        }
+        else if (!(d->left.flags & CMP_DYNAMICVAL))
+        {
+            convert_int_real(n1, &d->left);
+        }
+        else /* d->right is static */
+        {
+            if (convert_real_int(n2, &d->right, d->cmpt, TRUE))
+            {
+                return -1;
+            }
+        }
+    }
+    return 0;
+}
+
+/*!
+ * \param data Data to free (should point to a \c t_methoddata_compare).
+ *
+ * Frees the memory allocated for \c t_methoddata_compare.
+ */
+static void
+free_data_compare(void *data)
+{
+    t_methoddata_compare *d = (t_methoddata_compare *)data;
+
+    sfree(d->cmpop);
+    if (d->left.flags & CMP_ALLOCINT)
+    {
+        sfree(d->left.i);
+    }
+    if (d->left.flags & CMP_ALLOCREAL)
+    {
+        sfree(d->left.r);
+    }
+    if (d->right.flags & CMP_ALLOCINT)
+    {
+        sfree(d->right.i);
+    }
+    if (d->right.flags & CMP_ALLOCREAL)
+    {
+        sfree(d->right.r);
+    }
+}
+
+/*!
+ * \param[in]  top   Not used.
+ * \param[in]  fr    Not used.
+ * \param[in]  pbc   Not used.
+ * \param[in]  g     Evaluation index group.
+ * \param[out] out   Output data structure (\p out->u.g is used).
+ * \param[in]  data  Should point to a \c t_methoddata_compare.
+ * \returns    0 for success.
+ */
+static int
+evaluate_compare_int(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+                     gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
+{
+    t_methoddata_compare *d = (t_methoddata_compare *)data;
+    int                   i, i1, i2, ig;
+    int                   a, b;
+    gmx_bool                  bAccept;
+
+    for (i = i1 = i2 = ig = 0; i < g->isize; ++i)
+    {
+        a = d->left.i[i1];
+        b = d->right.i[i2];
+        bAccept = FALSE;
+        switch (d->cmpt)
+        {
+            case CMP_INVALID: break;
+            case CMP_LESS:    bAccept = a <  b; break;
+            case CMP_LEQ:     bAccept = a <= b; break;
+            case CMP_GTR:     bAccept = a >  b; break;
+            case CMP_GEQ:     bAccept = a >= b; break;
+            case CMP_EQUAL:   bAccept = a == b; break;
+            case CMP_NEQ:     bAccept = a != b; break;
+        }
+        if (bAccept)
+        {
+            out->u.g->index[ig++] = g->index[i];
+        }
+        if (!(d->left.flags & CMP_SINGLEVAL))
+        {
+            ++i1;
+        }
+        if (!(d->right.flags & CMP_SINGLEVAL))
+        {
+            ++i2;
+        }
+    }
+    out->u.g->isize = ig;
+    return 0;
+}
+
+/*!
+ * \param[in]  top   Not used.
+ * \param[in]  fr    Not used.
+ * \param[in]  pbc   Not used.
+ * \param[in]  g     Evaluation index group.
+ * \param[out] out   Output data structure (\p out->u.g is used).
+ * \param[in]  data  Should point to a \c t_methoddata_compare.
+ * \returns    0 for success.
+ */
+static int
+evaluate_compare_real(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+                      gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
+{
+    t_methoddata_compare *d = (t_methoddata_compare *)data;
+    int                   i, i1, i2, ig;
+    real                  a, b;
+    gmx_bool                  bAccept;
+
+    for (i = i1 = i2 = ig = 0; i < g->isize; ++i)
+    {
+        a = d->left.r[i1];
+        b = (d->right.flags & CMP_REALVAL) ? d->right.r[i2] : d->right.i[i2];
+        bAccept = FALSE;
+        switch (d->cmpt)
+        {
+            case CMP_INVALID: break;
+            case CMP_LESS:    bAccept = a <  b; break;
+            case CMP_LEQ:     bAccept = a <= b; break;
+            case CMP_GTR:     bAccept = a >  b; break;
+            case CMP_GEQ:     bAccept = a >= b; break;
+            case CMP_EQUAL:   bAccept =  gmx_within_tol(a, b, GMX_REAL_EPS); break;
+            case CMP_NEQ:     bAccept = !gmx_within_tol(a, b, GMX_REAL_EPS); break;
+        }
+        if (bAccept)
+        {
+            out->u.g->index[ig++] = g->index[i];
+        }
+        if (!(d->left.flags & CMP_SINGLEVAL))
+        {
+            ++i1;
+        }
+        if (!(d->right.flags & CMP_SINGLEVAL))
+        {
+            ++i2;
+        }
+    }
+    out->u.g->isize = ig;
+    return 0;
+}
+
+/*!
+ * \param[in]  top   Not used.
+ * \param[in]  fr    Not used.
+ * \param[in]  pbc   Not used.
+ * \param[in]  g     Evaluation index group.
+ * \param[out] out   Output data structure (\p out->u.g is used).
+ * \param[in]  data  Should point to a \c t_methoddata_compare.
+ * \returns    0 for success.
+ */
+static int
+evaluate_compare(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+                 gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
+{
+    t_methoddata_compare *d = (t_methoddata_compare *)data;
+
+    if (!((d->left.flags | d->right.flags) & CMP_REALVAL))
+    {
+        return evaluate_compare_int(top, fr, pbc, g, out, data);
+    }
+    else
+    {
+        return evaluate_compare_real(top, fr, pbc, g, out, data);
+    }
+    return 0;
+}
diff --git a/src/gromacs/selection/sm_distance.cpp b/src/gromacs/selection/sm_distance.cpp
new file mode 100644 (file)
index 0000000..1a6b4c1
--- /dev/null
@@ -0,0 +1,310 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * Implements distance-based selection methods.
+ *
+ * This file implements the \p distance, \p mindistance and \p within
+ * selection methods.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_selection
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <macros.h>
+#include <pbc.h>
+#include <smalloc.h>
+#include <vec.h>
+
+#include "gromacs/selection/nbsearch.h"
+#include "gromacs/selection/position.h"
+#include "gromacs/selection/selmethod.h"
+
+/*! \internal \brief
+ * Data structure for distance-based selection method.
+ *
+ * The same data structure is used by all the distance-based methods.
+ */
+typedef struct
+{
+    /** Cutoff distance. */
+    real                cutoff;
+    /** Positions of the reference points. */
+    gmx_ana_pos_t       p;
+    /** Neighborhood search data. */
+    gmx_ana_nbsearch_t *nb;
+} t_methoddata_distance;
+
+/** Allocates data for distance-based selection methods. */
+static void *
+init_data_common(int npar, gmx_ana_selparam_t *param);
+/** Initializes a distance-based selection method. */
+static int
+init_common(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
+/** Frees the data allocated for a distance-based selection method. */
+static void
+free_data_common(void *data);
+/** Initializes the evaluation of a distance-based within selection method for a frame. */
+static int
+init_frame_common(t_topology *top, t_trxframe *fr, t_pbc *pbc, void *data);
+/** Evaluates the \p distance selection method. */
+static int
+evaluate_distance(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+                  gmx_ana_pos_t *pos, gmx_ana_selvalue_t *out, void *data);
+/** Evaluates the \p within selection method. */
+static int
+evaluate_within(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+                gmx_ana_pos_t *pos, gmx_ana_selvalue_t *out, void *data);
+
+/** Parameters for the \p distance selection method. */
+static gmx_ana_selparam_t smparams_distance[] = {
+    {"cutoff", {REAL_VALUE, 1, {NULL}}, NULL, SPAR_OPTIONAL},
+    {"from",   {POS_VALUE,  1, {NULL}}, NULL, SPAR_DYNAMIC},
+};
+
+/** Parameters for the \p mindistance selection method. */
+static gmx_ana_selparam_t smparams_mindistance[] = {
+    {"cutoff", {REAL_VALUE, 1, {NULL}}, NULL, SPAR_OPTIONAL},
+    {"from",   {POS_VALUE, -1, {NULL}}, NULL, SPAR_DYNAMIC | SPAR_VARNUM},
+};
+
+/** Parameters for the \p within selection method. */
+static gmx_ana_selparam_t smparams_within[] = {
+    {NULL, {REAL_VALUE,  1, {NULL}}, NULL, 0},
+    {"of", {POS_VALUE,  -1, {NULL}}, NULL, SPAR_DYNAMIC | SPAR_VARNUM},
+};
+
+/** Help text for the distance selection methods. */
+static const char *help_distance[] = {
+    "DISTANCE-BASED SELECTION KEYWORDS[PAR]",
+
+    "[TT]distance from POS [cutoff REAL][tt][BR]",
+    "[TT]mindistance from POS_EXPR [cutoff REAL][tt][BR]",
+    "[TT]within REAL of POS_EXPR[tt][PAR]",
+
+    "[TT]distance[tt] and [TT]mindistance[tt] calculate the distance from the",
+    "given position(s), the only difference being in that [TT]distance[tt]",
+    "only accepts a single position, while any number of positions can be",
+    "given for [TT]mindistance[tt], which then calculates the distance to the",
+    "closest position.",
+    "[TT]within[tt] directly selects atoms that are within [TT]REAL[tt] of",
+    "[TT]POS_EXPR[tt].[PAR]",
+
+    "For the first two keywords, it is possible to specify a cutoff to speed",
+    "up the evaluation: all distances above the specified cutoff are",
+    "returned as equal to the cutoff.",
+    "Currently, this does nothing, but in the future, it allows the use of",
+    "grid-based neighborhood search techniques.",
+};
+
+/** \internal Selection method data for the \p distance method. */
+gmx_ana_selmethod_t sm_distance = {
+    "distance", REAL_VALUE, SMETH_DYNAMIC,
+    asize(smparams_distance), smparams_distance,
+    &init_data_common,
+    NULL,
+    &init_common,
+    NULL,
+    &free_data_common,
+    &init_frame_common,
+    NULL,
+    &evaluate_distance,
+    {"distance from POS [cutoff REAL]", asize(help_distance), help_distance},
+};
+
+/** \internal Selection method data for the \p distance method. */
+gmx_ana_selmethod_t sm_mindistance = {
+    "mindistance", REAL_VALUE, SMETH_DYNAMIC,
+    asize(smparams_mindistance), smparams_mindistance,
+    &init_data_common,
+    NULL,
+    &init_common,
+    NULL,
+    &free_data_common,
+    &init_frame_common,
+    NULL,
+    &evaluate_distance,
+    {"mindistance from POS_EXPR [cutoff REAL]", asize(help_distance), help_distance},
+};
+
+/** \internal Selection method data for the \p within method. */
+gmx_ana_selmethod_t sm_within = {
+    "within", GROUP_VALUE, SMETH_DYNAMIC,
+    asize(smparams_within), smparams_within,
+    &init_data_common,
+    NULL,
+    &init_common,
+    NULL,
+    &free_data_common,
+    &init_frame_common,
+    NULL,
+    &evaluate_within,
+    {"within REAL of POS_EXPR", asize(help_distance), help_distance},
+};
+
+/*!
+ * \param[in]     npar  Not used (should be 2).
+ * \param[in,out] param Method parameters (should point to one of the distance
+ *   parameter arrays).
+ * \returns       Pointer to the allocated data (\c t_methoddata_distance).
+ *
+ * Allocates memory for a \c t_methoddata_distance structure and
+ * initializes the parameter as follows:
+ *  - the first parameter defines the value for
+ *    \c t_methoddata_distance::cutoff.
+ *  - the second parameter defines the reference positions and the value is
+ *    stored in \c t_methoddata_distance::p.
+ */
+static void *
+init_data_common(int npar, gmx_ana_selparam_t *param)
+{
+    t_methoddata_distance *data;
+
+    snew(data, 1);
+    data->cutoff     = -1;
+    param[0].val.u.r = &data->cutoff;
+    param[1].val.u.p = &data->p;
+    return data;
+}
+
+/*!
+ * \param   top   Not used.
+ * \param   npar  Not used (should be 2).
+ * \param   param Method parameters (should point to one of the distance
+ *   parameter arrays).
+ * \param   data  Pointer to \c t_methoddata_distance to initialize.
+ * \returns 0 on success, a non-zero error code on failure.
+ *
+ * Initializes the neighborhood search data structure
+ * (\c t_methoddata_distance::nb).
+ * Also checks that the cutoff is valid.
+ */
+static int
+init_common(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data)
+{
+    t_methoddata_distance *d = (t_methoddata_distance *)data;
+
+    if ((param[0].flags & SPAR_SET) && d->cutoff <= 0)
+    {
+        fprintf(stderr, "error: distance cutoff should be > 0");
+        return -1;
+    }
+    return gmx_ana_nbsearch_create(&d->nb, d->cutoff, d->p.nr);
+}
+
+/*!
+ * \param data Data to free (should point to a \c t_methoddata_distance).
+ *
+ * Frees the memory allocated for \c t_methoddata_distance::xref and
+ * \c t_methoddata_distance::nb.
+ */
+static void
+free_data_common(void *data)
+{
+    t_methoddata_distance *d = (t_methoddata_distance *)data;
+
+    if (d->nb)
+    {
+        gmx_ana_nbsearch_free(d->nb);
+    }
+}
+
+/*!
+ * \param[in]  top  Not used.
+ * \param[in]  fr   Current frame.
+ * \param[in]  pbc  PBC structure.
+ * \param      data Should point to a \c t_methoddata_distance.
+ * \returns    0 on success, a non-zero error code on error.
+ *
+ * Initializes the neighborhood search for the current frame.
+ */
+static int
+init_frame_common(t_topology *top, t_trxframe *fr, t_pbc *pbc, void *data)
+{
+    t_methoddata_distance *d = (t_methoddata_distance *)data;
+
+    return gmx_ana_nbsearch_pos_init(d->nb, pbc, &d->p);
+}
+
+/*!
+ * See sel_updatefunc_pos() for description of the parameters.
+ * \p data should point to a \c t_methoddata_distance.
+ *
+ * Calculates the distance of each position from \c t_methoddata_distance::p
+ * and puts them in \p out->u.r.
+ */
+static int
+evaluate_distance(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+                  gmx_ana_pos_t *pos, gmx_ana_selvalue_t *out, void *data)
+{
+    t_methoddata_distance *d = (t_methoddata_distance *)data;
+    int  b, i;
+    real n;
+
+    out->nr = pos->g->isize;
+    for (b = 0; b < pos->nr; ++b)
+    {
+        n = gmx_ana_nbsearch_pos_mindist(d->nb, pos, b);
+        for (i = pos->m.mapb.index[b]; i < pos->m.mapb.index[b+1]; ++i)
+        {
+            out->u.r[i] = n;
+        }
+    }
+    return 0;
+}
+
+/*!
+ * See sel_updatefunc() for description of the parameters.
+ * \p data should point to a \c t_methoddata_distance.
+ *
+ * Finds the atoms that are closer than the defined cutoff to
+ * \c t_methoddata_distance::xref and puts them in \p out.g.
+ */
+static int
+evaluate_within(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+                gmx_ana_pos_t *pos, gmx_ana_selvalue_t *out, void *data)
+{
+    t_methoddata_distance *d = (t_methoddata_distance *)data;
+    int                    b;
+
+    out->u.g->isize = 0;
+    for (b = 0; b < pos->nr; ++b)
+    {
+        if (gmx_ana_nbsearch_pos_is_within(d->nb, pos, b))
+        {
+            gmx_ana_pos_append(NULL, out->u.g, pos, b, 0);
+        }
+    }
+    return 0;
+}
diff --git a/src/gromacs/selection/sm_insolidangle.cpp b/src/gromacs/selection/sm_insolidangle.cpp
new file mode 100644 (file)
index 0000000..6f8d924
--- /dev/null
@@ -0,0 +1,968 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \page page_module_selection_insolidangle Selection method: insolidangle
+ *
+ * This method selects a subset of particles that are located in a solid
+ * angle defined by a center and a set of points.
+ * The solid angle is constructed as a union of small cones whose axis
+ * goes through the center and a point.
+ * So there's such a cone for each position, and a
+ * point is in the solid angle if it lies within any of these cones.
+ * The width of the cones can be adjusted.
+ *
+ * \internal
+ *
+ * The method is implemented by partitioning the surface of the unit sphere
+ * into bins using the polar coordinates \f$(\theta, \phi)\f$.
+ * The partitioning is always uniform in the zenith angle \f$\theta\f$,
+ * while the partitioning in the azimuthal angle \f$\phi\f$ varies.
+ * For each reference point, the unit vector from the center to the point
+ * is constructed, and it is stored in all the bins that overlap with the
+ * cone defined by the point.
+ * Bins that are completely covered by a single cone are marked as such.
+ * Checking whether a point is in the solid angle is then straightforward
+ * with this data structure: one finds the bin that corresponds to the point,
+ * and checks whether the bin is completely covered. If it is not, one
+ * additionally needs to check whether it is within the specified cutoff of
+ * any of the stored points.
+ *
+ * The above construction gives quite a lot of flexibility for constructing
+ * the bins without modifying the rest of the code.
+ * The current (quite inefficient) implementation is discussed below, but
+ * it should be optimized to get the most out of the code.
+ *
+ * The current way of constructing the bins constructs the boundaries
+ * statically: the bin size in the zenith direction is set to approximately
+ * half the angle cutoff, and the bins in the azimuthal direction have
+ * sizes such that the shortest edge of the bin is approximately equal to
+ * half the angle cutoff (for the regions close to the poles, a single bin
+ * is used).
+ * Each reference point is then added to the bins as follows:
+ *  -# Find the zenith angle range that is spanned by the cone centered at the
+ *     point (this is simple addition/subtraction).
+ *  -# Calculate the maximal span of the cone in the azimuthal direction using
+ *     the formula
+ *     \f[\sin \Delta \phi_{max} = \frac{\sin \alpha}{\sin \theta}\f]
+ *     (a sine formula in spherical coordinates),
+ *     where \f$\alpha\f$ is the width of the cone and \f$\theta\f$ is the
+ *     zenith angle of the cone center.
+ *     Similarly, the zenith angle at which this extent is achieved is
+ *     calculated using
+ *     \f[\cos \theta_{max} = \frac{\cos \theta}{\cos \alpha}\f]
+ *     (Pythagoras's theorem in spherical coordinates).
+ *  -# For each zenith angle bin that is at least partially covered by the
+ *     cone, calculate the span of the cone at the edges using
+ *     \f[\sin^2 \frac{\Delta \phi}{2} = \frac{\sin^2 \frac{\alpha}{2} - \sin^2 \frac{\theta - \theta'}{2}}{\sin \theta \sin \theta'}\f]
+ *     (distance in spherical geometry),
+ *     where \f$\theta'\f$ is the zenith angle of the bin edge.
+ *  -# Using the values calculated above, loop through the azimuthal bins that
+ *     are partially or completely covered by the cone and update them.
+ *
+ * The total solid angle (for covered fraction calculations) is estimated by
+ * taking the total area of completely covered bins plus
+ * half the area of partially covered bins.
+ * The second one is an approximation, but should give reasonable estimates
+ * for the averages as well as in cases where the bin size is small.
+ */
+/*! \internal \file
+ * \brief
+ * Implements the \ref sm_insolidangle "insolidangle" selection method.
+ *
+ * \todo
+ * The implementation could be optimized quite a bit.
+ *
+ * \todo
+ * Move the covered fraction stuff somewhere else and make it more generic
+ * (along the lines it is handled in selection.h and trajana.h in the old C
+ * API).
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_selection
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <math.h>
+
+#include <macros.h>
+#include <maths.h>
+#include <pbc.h>
+#include <physics.h>
+#include <smalloc.h>
+#include <vec.h>
+
+#include "gromacs/selection/indexutil.h"
+#include "gromacs/selection/position.h"
+#include "gromacs/selection/selection.h"
+#include "gromacs/selection/selmethod.h"
+
+#include "selelem.h"
+
+/*! \internal \brief
+ * Internal data structure for the \p insolidangle selection method.
+ *
+ * \see \c t_partition
+ */
+typedef struct
+{
+    /** Left edge of the partition. */
+    real                left;
+    /** Bin index corresponding to this partition. */
+    int                 bin;
+} t_partition_item;
+
+/*! \internal \brief
+ * Internal data structure for the \p insolidangle selection method.
+ *
+ * Describes the surface partitioning within one slice along the zenith angle.
+ * The slice from azimuthal angle \p p[i].left to \p p[i+1].left belongs to
+ * bin \p p[i].bin.
+ */
+typedef struct
+{
+    /** Number of partition items (\p p contains \p n+1 items). */
+    int                 n;
+    /** Array of partition edges and corresponding bins. */
+    t_partition_item   *p;
+} t_partition;
+
+/*! \internal \brief
+ * Internal data structure for the \p insolidangle selection method.
+ *
+ * Contains the reference points that partially cover a certain region on the
+ * surface of the unit sphere.
+ * If \p n is -1, the whole region described by the bin is covered.
+ */
+typedef struct
+{
+    /** Number of points in the array \p x, -1 if whole bin covered. */
+    int   n;
+    /** Number of elements allocated for \p x. */
+    int   n_alloc;
+    /** Array of points that partially cover the bin. */
+    rvec *x;
+} t_spheresurfacebin;
+
+/*! \internal \brief
+ * Data structure for the \p insolidangle selection method.
+ *
+ * All angle values are in the units of radians.
+ */
+typedef struct
+{
+    /** Center of the solid angle. */
+    gmx_ana_pos_t       center;
+    /** Positions that span the solid angle. */
+    gmx_ana_pos_t       span;
+    /** Cutoff angle. */
+    real                angcut;
+    /** Estimate of the covered fraction. */
+    real                cfrac;
+
+    /** Cutoff for the cosine (equals cos(angcut)). */
+    real                distccut;
+    /** Bin size to be used as the target bin size when constructing the bins. */
+    real                targetbinsize;
+
+    /** Number of bins in the \p tbin array. */
+    int                 ntbins;
+    /** Size of one bin in the zenith angle direction. */
+    real                tbinsize;
+    /** Array of zenith angle slices. */
+    t_partition        *tbin;
+    /** Number of elements allocated for the \p bin array. */
+    int                 maxbins;
+    /** Number of elements used in the \p bin array. */
+    int                 nbins;
+    /** Array of individual bins. */
+    t_spheresurfacebin *bin;
+} t_methoddata_insolidangle;
+
+/** Allocates data for the \p insolidangle selection method. */
+static void *
+init_data_insolidangle(int npar, gmx_ana_selparam_t *param);
+/** Initializes the \p insolidangle selection method. */
+static int
+init_insolidangle(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
+/** Sets the COM/COG data for the \p insolidangle selection method. */
+static void
+set_comg_insolidangle(gmx_ana_pos_t *pos, void *data);
+/** Frees the data allocated for the \p insolidangle selection method. */
+static void
+free_data_insolidangle(void *data);
+/** Initializes the evaluation of the \p insolidangle selection method for a frame. */
+static int
+init_frame_insolidangle(t_topology *top, t_trxframe *fr, t_pbc *pbc, void *data);
+/** Internal helper function for evaluate_insolidangle(). */
+static gmx_bool
+accept_insolidangle(rvec x, t_pbc *pbc, void *data);
+/** Evaluates the \p insolidangle selection method. */
+static int
+evaluate_insolidangle(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+                      gmx_ana_pos_t *pos, gmx_ana_selvalue_t *out, void *data);
+
+/** Calculates the distance between unit vectors. */
+static real
+sph_distc(rvec x1, rvec x2);
+/** Does a binary search on a \p t_partition to find a bin for a value. */
+static int
+find_partition_bin(t_partition *p, real value);
+/** Finds a bin that corresponds to a location on the unit sphere surface. */
+static int
+find_surface_bin(t_methoddata_insolidangle *surf, rvec x);
+/** Clears/initializes the bins on the unit sphere surface. */
+static void
+clear_surface_points(t_methoddata_insolidangle *surf);
+/** Frees memory allocated for storing the reference points in the surface bins. */
+static void
+free_surface_points(t_methoddata_insolidangle *surf);
+/** Adds a reference point to a given bin. */
+static void
+add_surface_point(t_methoddata_insolidangle *surf, int tbin, int pbin, rvec x);
+/** Marks a bin as completely covered. */
+static void
+mark_surface_covered(t_methoddata_insolidangle *surf, int tbin, int pbin);
+/** Helper function for store_surface_point() to update a single zenith angle bin. */
+static void
+update_surface_bin(t_methoddata_insolidangle *surf, int tbin,
+                   real phi, real pdelta1, real pdelta2, real pdeltamax,
+                   rvec x);
+/** Adds a single reference point and updates the surface bins. */
+static void
+store_surface_point(t_methoddata_insolidangle *surf, rvec x);
+/** Optimizes the surface bins for faster searching. */
+static void
+optimize_surface_points(t_methoddata_insolidangle *surf);
+/** Estimates the area covered by the reference cones. */
+static real
+estimate_covered_fraction(t_methoddata_insolidangle *surf);
+/** Checks whether a point lies within a solid angle. */
+static gmx_bool
+is_surface_covered(t_methoddata_insolidangle *surf, rvec x);
+
+/** Parameters for the \p insolidangle selection method. */
+static gmx_ana_selparam_t smparams_insolidangle[] = {
+    {"center", {POS_VALUE,   1, {NULL}}, NULL, SPAR_DYNAMIC},
+    {"span",   {POS_VALUE,  -1, {NULL}}, NULL, SPAR_DYNAMIC | SPAR_VARNUM},
+    {"cutoff", {REAL_VALUE,  1, {NULL}}, NULL, SPAR_OPTIONAL},
+};
+
+/** Help text for the \p insolidangle selection method. */
+static const char *help_insolidangle[] = {
+    "SELECTING ATOMS IN A SOLID ANGLE[PAR]",
+
+    "[TT]insolidangle center POS span POS_EXPR [cutoff REAL][tt][PAR]",
+
+    "This keyword selects atoms that are within [TT]REAL[tt] degrees",
+    "(default=5) of any position in [TT]POS_EXPR[tt] as seen from [TT]POS[tt]",
+    "a position expression that evaluates to a single position), i.e., atoms",
+    "in the solid angle spanned by the positions in [TT]POS_EXPR[tt] and",
+    "centered at [TT]POS[tt].[PAR]"
+
+    "Technically, the solid angle is constructed as a union of small cones",
+    "whose tip is at [TT]POS[tt] and the axis goes through a point in",
+    "[TT]POS_EXPR[tt]. There is such a cone for each position in",
+    "[TT]POS_EXPR[tt], and point is in the solid angle if it lies within any",
+    "of these cones. The cutoff determines the width of the cones.",
+};
+
+/** \internal Selection method data for the \p insolidangle method. */
+gmx_ana_selmethod_t sm_insolidangle = {
+    "insolidangle", GROUP_VALUE, SMETH_DYNAMIC,
+    asize(smparams_insolidangle), smparams_insolidangle,
+    &init_data_insolidangle,
+    NULL,
+    &init_insolidangle,
+    NULL,
+    &free_data_insolidangle,
+    &init_frame_insolidangle,
+    NULL,
+    &evaluate_insolidangle,
+    {"insolidangle center POS span POS_EXPR [cutoff REAL]",
+     asize(help_insolidangle), help_insolidangle},
+};
+
+/*!
+ * \param[in]     npar  Not used (should be 3).
+ * \param[in,out] param Method parameters (should point to 
+ *   \ref smparams_insolidangle).
+ * \returns Pointer to the allocated data (\ref t_methoddata_insolidangle).
+ *
+ * Allocates memory for a \ref t_methoddata_insolidangle structure and
+ * initializes the parameter as follows:
+ *  - \p center defines the value for t_methoddata_insolidangle::center.
+ *  - \p span   defines the value for t_methoddata_insolidangle::span.
+ *  - \p cutoff defines the value for t_methoddata_insolidangle::angcut.
+ */
+static void *
+init_data_insolidangle(int npar, gmx_ana_selparam_t *param)
+{
+    t_methoddata_insolidangle *data;
+
+    snew(data, 1);
+    data->angcut = 5.0;
+    param[0].val.u.p = &data->center;
+    param[1].val.u.p = &data->span;
+    param[2].val.u.r = &data->angcut;
+    return data;
+}
+
+/*!
+ * \param   top  Not used.
+ * \param   npar Not used.
+ * \param   param Not used.
+ * \param   data Pointer to \ref t_methoddata_insolidangle to initialize.
+ * \returns 0 on success, -1 on failure.
+ *
+ * Converts t_methoddata_insolidangle::angcut to radians and allocates
+ * and allocates memory for the bins used during the evaluation.
+ */
+static int
+init_insolidangle(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data)
+{
+    t_methoddata_insolidangle *surf = (t_methoddata_insolidangle *)data;
+    int                        i, c;
+
+    if (surf->angcut <= 0)
+    {
+        fprintf(stderr, "error: angle cutoff should be > 0");
+        return -1;
+    }
+
+    surf->angcut *= DEG2RAD;
+
+    surf->distccut = -cos(surf->angcut);
+    surf->targetbinsize = surf->angcut / 2;
+    surf->ntbins = (int) (M_PI / surf->targetbinsize);
+    surf->tbinsize = (180.0 / surf->ntbins)*DEG2RAD;
+
+    snew(surf->tbin, (int)(M_PI/surf->tbinsize) + 1);
+    surf->maxbins = 0;
+    for (i = 0; i < surf->ntbins; ++i)
+    {
+        c = max(sin(surf->tbinsize*i), sin(surf->tbinsize*(i+1)))
+              * M_2PI / surf->targetbinsize + 1;
+        snew(surf->tbin[i].p, c+1);
+        surf->maxbins += c;
+    }
+    surf->nbins = 0;
+    snew(surf->bin, surf->maxbins);
+
+    return 0;
+}
+
+/*!
+ * \param data Data to free (should point to a \ref t_methoddata_insolidangle).
+ *
+ * Frees the memory allocated for \c t_methoddata_insolidangle::center and
+ * \c t_methoddata_insolidangle::span, as well as the memory for the internal
+ * bin structure.
+ */
+static void
+free_data_insolidangle(void *data)
+{
+    t_methoddata_insolidangle *d = (t_methoddata_insolidangle *)data;
+    int                        i;
+
+    if (d->tbin)
+    {
+        for (i = 0; i < d->ntbins; ++i)
+        {
+            sfree(d->tbin[i].p);
+        }
+        sfree(d->tbin);
+    }
+    free_surface_points(d);
+    sfree(d->bin);
+}
+
+/*!
+ * \param[in]  top  Not used.
+ * \param[in]  fr   Current frame.
+ * \param[in]  pbc  PBC structure.
+ * \param      data Should point to a \ref t_methoddata_insolidangle.
+ * \returns    0 on success, a non-zero error code on error.
+ *
+ * Creates a lookup structure that enables fast queries of whether a point
+ * is within the solid angle or not.
+ */
+static int
+init_frame_insolidangle(t_topology *top, t_trxframe *fr, t_pbc *pbc, void *data)
+{
+    t_methoddata_insolidangle *d = (t_methoddata_insolidangle *)data;
+    rvec                       dx;
+    int                        i;
+
+    free_surface_points(d);
+    clear_surface_points(d);
+    for (i = 0; i < d->span.nr; ++i)
+    {
+        if (pbc)
+        {
+            pbc_dx(pbc, d->span.x[i], d->center.x[0], dx);
+        }
+        else
+        {
+            rvec_sub(d->span.x[i], d->center.x[0], dx);
+        }
+        unitv(dx, dx);
+        store_surface_point(d, dx);
+    }
+    optimize_surface_points(d);
+    d->cfrac = -1;
+    return 0;
+}
+
+/*!
+ * \param[in] x    Test point.
+ * \param[in] pbc  PBC data (if NULL, no PBC are used).
+ * \param[in] data Pointer to a \c t_methoddata_insolidangle data structure.
+ * \returns   TRUE if \p x is within the solid angle, FALSE otherwise.
+ */
+static gmx_bool
+accept_insolidangle(rvec x, t_pbc *pbc, void *data)
+{
+    t_methoddata_insolidangle *d = (t_methoddata_insolidangle *)data;
+    rvec                       dx;
+
+    if (pbc)
+    {
+        pbc_dx(pbc, x, d->center.x[0], dx);
+    }
+    else
+    {
+        rvec_sub(x, d->center.x[0], dx);
+    }
+    unitv(dx, dx);
+    return is_surface_covered(d, dx);
+}
+
+/*!
+ * See sel_updatefunc() for description of the parameters.
+ * \p data should point to a \c t_methoddata_insolidangle.
+ *
+ * Calculates which atoms in \p g are within the solid angle spanned by
+ * \c t_methoddata_insolidangle::span and centered at
+ * \c t_methoddata_insolidangle::center, and stores the result in \p out->u.g.
+ */
+static int
+evaluate_insolidangle(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+                      gmx_ana_pos_t *pos, gmx_ana_selvalue_t *out, void *data)
+{
+    t_methoddata_insolidangle *d = (t_methoddata_insolidangle *)data;
+    int                        b;
+
+    out->u.g->isize = 0;
+    for (b = 0; b < pos->nr; ++b)
+    {
+        if (accept_insolidangle(pos->x[b], pbc, data))
+        {
+            gmx_ana_pos_append(NULL, out->u.g, pos, b, 0);
+        }
+    }
+    return 0;
+}
+
+/*!
+ * \param[in] sel Selection element to query.
+ * \returns   TRUE if the covered fraction can be estimated for \p sel with
+ *   _gmx_selelem_estimate_coverfrac(), FALSE otherwise.
+ */
+gmx_bool
+_gmx_selelem_can_estimate_cover(t_selelem *sel)
+{
+    t_selelem   *child;
+    gmx_bool         bFound;
+    gmx_bool         bDynFound;
+
+    if (sel->type == SEL_BOOLEAN && sel->u.boolt == BOOL_OR)
+    {
+        return FALSE;
+    }
+    bFound    = FALSE;
+    bDynFound = FALSE;
+    child     = sel->child;
+    while (child)
+    {
+        if (child->type == SEL_EXPRESSION)
+        {
+            if (child->u.expr.method->name == sm_insolidangle.name)
+            {
+                if (bFound || bDynFound)
+                {
+                    return FALSE;
+                }
+                bFound = TRUE;
+            }
+            else if (child->u.expr.method
+                     && (child->u.expr.method->flags & SMETH_DYNAMIC))
+            {
+                if (bFound)
+                {
+                    return FALSE;
+                }
+                bDynFound = TRUE;
+            }
+        }
+        else if (!_gmx_selelem_can_estimate_cover(child))
+        {
+            return FALSE;
+        }
+        child = child->next;
+    }
+    return TRUE;
+}
+
+/*!
+ * \param[in] sel Selection for which the fraction should be calculated.
+ * \returns Fraction of angles covered by the selection (between zero and one).
+ *
+ * The return value is undefined if _gmx_selelem_can_estimate_cover() returns
+ * FALSE.
+ * Should be called after gmx_ana_evaluate_selections() has been called for the
+ * frame.
+ */
+real
+_gmx_selelem_estimate_coverfrac(t_selelem *sel)
+{
+    t_selelem   *child;
+    real         cfrac;
+
+    if (sel->type == SEL_EXPRESSION && sel->u.expr.method->name == sm_insolidangle.name)
+    {
+        t_methoddata_insolidangle *d = (t_methoddata_insolidangle *)sel->u.expr.mdata;
+        if (d->cfrac < 0)
+        {
+            d->cfrac = estimate_covered_fraction(d);        
+        }
+        return d->cfrac;
+    }
+    if (sel->type == SEL_BOOLEAN && sel->u.boolt == BOOL_NOT)
+    {
+        cfrac = _gmx_selelem_estimate_coverfrac(sel->child);
+        if (cfrac < 1.0)
+        {
+            return 1 - cfrac;
+        }
+        return 1;
+    }
+
+    /* Here, we assume that the selection is simple enough */
+    child = sel->child;
+    while (child)
+    {
+        cfrac = _gmx_selelem_estimate_coverfrac(child); 
+        if (cfrac < 1.0)
+        {
+            return cfrac;
+        }
+        child = child->next;
+    }
+    return 1.0;
+}
+
+/*!
+ * \param[in] x1  Unit vector 1.
+ * \param[in] x2  Unit vector 2.
+ * \returns   Minus the dot product of \p x1 and \p x2.
+ *
+ * This function is used internally to calculate the distance between the
+ * unit vectors \p x1 and \p x2 to find out whether \p x2 is within the
+ * cone centered at \p x1. Currently, the cosine of the angle is used
+ * for efficiency, and the minus is there to make it behave like a normal
+ * distance (larger values mean longer distances).
+ */
+static real
+sph_distc(rvec x1, rvec x2)
+{
+    return -iprod(x1, x2);
+}
+
+/*!
+ * \param[in] p     Partition to search.
+ * \param[in] value Value to search for.
+ * \returns   The partition index in \p p that contains \p value.
+ *
+ * If \p value is outside the range of \p p, the first/last index is returned.
+ * Otherwise, the return value \c i satisfies \c p->p[i].left<=value and
+ * \c p->p[i+1].left>value
+ */
+static int
+find_partition_bin(t_partition *p, real value)
+{
+    int pmin, pmax, pbin;
+
+    /* Binary search the partition */
+    pmin = 0; pmax = p->n;
+    while (pmax > pmin + 1)
+    {
+        pbin = pmin + (pmax - pmin) / 2;
+        if (p->p[pbin].left <= value)
+        {
+            pmin = pbin;
+        }
+        else
+        {
+            pmax = pbin;
+        }
+    }
+    pbin = pmin;
+    return pbin;
+}
+
+/*!
+ * \param[in] surf  Surface data structure to search.
+ * \param[in] x     Unit vector to find.
+ * \returns   The bin index that contains \p x.
+ *
+ * The return value is an index to the \p surf->bin array.
+ */
+static int
+find_surface_bin(t_methoddata_insolidangle *surf, rvec x)
+{
+    real theta, phi;
+    int  tbin, pbin;
+    
+    theta = acos(x[ZZ]);
+    phi = atan2(x[YY], x[XX]);
+    tbin = floor(theta / surf->tbinsize);
+    if (tbin >= surf->ntbins)
+    {
+        tbin = surf->ntbins - 1;
+    }
+    pbin = find_partition_bin(&surf->tbin[tbin], phi);
+    return surf->tbin[tbin].p[pbin].bin;
+}
+
+/*!
+ * \param[in,out] surf Surface data structure.
+ *
+ * Clears the reference points from the bins and (re)initializes the edges
+ * of the azimuthal bins.
+ */
+static void
+clear_surface_points(t_methoddata_insolidangle *surf)
+{
+    int i, j, c;
+
+    surf->nbins = 0;
+    for (i = 0; i < surf->ntbins; ++i)
+    {
+        c = min(sin(surf->tbinsize*i), sin(surf->tbinsize*(i+1)))
+              * M_2PI / surf->targetbinsize + 1;
+        if (c <= 0)
+        {
+            c = 1;
+        }
+        surf->tbin[i].n = c;
+        for (j = 0; j < c; ++j)
+        {
+            surf->tbin[i].p[j].left = -M_PI + j*M_2PI/c - 0.0001;
+            surf->tbin[i].p[j].bin = surf->nbins;
+            surf->bin[surf->nbins].n = 0;
+            surf->nbins++;
+        }
+        surf->tbin[i].p[c].left = M_PI + 0.0001;
+        surf->tbin[i].p[c].bin = -1;
+    }
+}
+
+/*!
+ * \param[in,out] surf Surface data structure.
+ */
+static void
+free_surface_points(t_methoddata_insolidangle *surf)
+{
+    int i;
+
+    for (i = 0; i < surf->nbins; ++i)
+    {
+        if (surf->bin[i].x)
+        {
+            sfree(surf->bin[i].x);
+        }
+        surf->bin[i].n_alloc = 0;
+        surf->bin[i].x = NULL;
+    }
+}
+
+/*!
+ * \param[in,out] surf Surface data structure.
+ * \param[in]     tbin Bin number in the zenith angle direction.
+ * \param[in]     pbin Bin number in the azimuthal angle direction.
+ * \param[in]     x    Point to store.
+ */
+static void
+add_surface_point(t_methoddata_insolidangle *surf, int tbin, int pbin, rvec x)
+{
+    int bin;
+
+    bin = surf->tbin[tbin].p[pbin].bin;
+    /* Return if bin is already completely covered */
+    if (surf->bin[bin].n == -1)
+        return;
+    /* Allocate more space if necessary */
+    if (surf->bin[bin].n == surf->bin[bin].n_alloc) {
+        surf->bin[bin].n_alloc += 10;
+        srenew(surf->bin[bin].x, surf->bin[bin].n_alloc);
+    }
+    /* Add the point to the bin */
+    copy_rvec(x, surf->bin[bin].x[surf->bin[bin].n]);
+    ++surf->bin[bin].n;
+}
+
+/*!
+ * \param[in,out] surf Surface data structure.
+ * \param[in]     tbin Bin number in the zenith angle direction.
+ * \param[in]     pbin Bin number in the azimuthal angle direction.
+ */
+static void
+mark_surface_covered(t_methoddata_insolidangle *surf, int tbin, int pbin)
+{
+    int bin;
+
+    bin = surf->tbin[tbin].p[pbin].bin;
+    surf->bin[bin].n = -1;
+}
+
+/*!
+ * \param[in,out] surf      Surface data structure.
+ * \param[in]     tbin      Bin number in the zenith angle direction.
+ * \param[in]     phi       Azimuthal angle of \p x.
+ * \param[in]     pdelta1   Width of the cone at the lower edge of \p tbin.
+ * \param[in]     pdelta2   Width of the cone at the uppper edge of \p tbin.
+ * \param[in]     pdeltamax Max. width of the cone inside \p tbin.
+ * \param[in]     x         Point to store (should have unit length).
+ */
+static void
+update_surface_bin(t_methoddata_insolidangle *surf, int tbin,
+                   real phi, real pdelta1, real pdelta2, real pdeltamax,
+                   rvec x)
+{
+    real pdelta, phi1, phi2;
+    int  pbin1, pbin2, pbin;
+
+    /* Find the edges of the bins affected */
+    pdelta = max(max(pdelta1, pdelta2), pdeltamax);
+    phi1 = phi - pdelta;
+    if (phi1 < -M_PI)
+    {
+        phi1 += M_2PI;
+    }
+    phi2 = phi + pdelta;
+    if (phi2 > M_PI)
+    {
+        phi2 -= M_2PI;
+    }
+    pbin1 = find_partition_bin(&surf->tbin[tbin], phi1);
+    pbin2 = find_partition_bin(&surf->tbin[tbin], phi2);
+    /* Find the edges of completely covered region */
+    pdelta = min(pdelta1, pdelta2);
+    phi1 = phi - pdelta;
+    if (phi1 < -M_PI)
+    {
+        phi1 += M_2PI;
+    }
+    phi2 = phi + pdelta;
+    /* Loop over all affected bins */
+    pbin = pbin1;
+    do
+    {
+        /* Wrap bin around if end reached */
+        if (pbin == surf->tbin[tbin].n)
+        {
+            pbin = 0;
+            phi1 -= M_2PI;
+            phi2 -= M_2PI;
+        }
+        /* Check if bin is completely covered and update */
+        if (surf->tbin[tbin].p[pbin].left >= phi1
+            && surf->tbin[tbin].p[pbin+1].left <= phi2)
+        {
+            mark_surface_covered(surf, tbin, pbin);
+        }
+        else
+        {
+            add_surface_point(surf, tbin, pbin, x);
+        }
+    }
+    while (pbin++ != pbin2); /* Loop including pbin2 */
+}
+
+/*!
+ * \param[in,out] surf Surface data structure.
+ * \param[in]     x    Point to store (should have unit length).
+ *
+ * Finds all the bins covered by the cone centered at \p x and calls
+ * update_surface_bin() to update them.
+ */
+static void
+store_surface_point(t_methoddata_insolidangle *surf, rvec x)
+{
+    real theta, phi;
+    real pdeltamax, tmax;
+    real theta1, theta2, pdelta1, pdelta2;
+    int  tbin, pbin, bin;
+
+    theta = acos(x[ZZ]);
+    phi = atan2(x[YY], x[XX]);
+    /* Find the maximum extent in the phi direction */
+    if (theta <= surf->angcut)
+    {
+        pdeltamax = M_PI;
+        tmax = 0;
+    }
+    else if (theta >= M_PI - surf->angcut)
+    {
+        pdeltamax = M_PI;
+        tmax = M_PI;
+    }
+    else
+    {
+        pdeltamax = asin(sin(surf->angcut) / sin(theta));
+        tmax = acos(cos(theta) / cos(surf->angcut));
+    }
+    /* Find the first affected bin */
+    tbin = max(floor((theta - surf->angcut) / surf->tbinsize), 0);
+    theta1 = tbin * surf->tbinsize;
+    if (theta1 < theta - surf->angcut)
+    {
+        pdelta1 = 0;
+    }
+    else
+    {
+        pdelta1 = M_PI;
+    }
+    /* Loop through all affected bins */
+    while (tbin < ceil((theta + surf->angcut) / surf->tbinsize)
+           && tbin < surf->ntbins)
+    {
+        /* Calculate the next boundaries */
+        theta2 = (tbin+1) * surf->tbinsize;
+        if (theta2 > theta + surf->angcut)
+        {
+            pdelta2 = 0;
+        }
+        else if (tbin == surf->ntbins - 1)
+        {
+            pdelta2 = M_PI;
+        }
+        else
+        {
+            pdelta2 = 2*asin(sqrt(
+                    (sqr(sin(surf->angcut/2)) - sqr(sin((theta2-theta)/2))) /
+                    (sin(theta) * sin(theta2))));
+        }
+        /* Update the bin */
+        if (tmax >= theta1 && tmax <= theta2)
+        {
+            update_surface_bin(surf, tbin, phi, pdelta1, pdelta2, pdeltamax, x);
+        }
+        else
+        {
+            update_surface_bin(surf, tbin, phi, pdelta1, pdelta2, 0, x);
+        }
+        /* Next bin */
+        theta1 = theta2;
+        pdelta1 = pdelta2;
+        ++tbin;
+    }
+}
+
+/*!
+ * \param[in,out] surf Surface data structure.
+ *
+ * Currently, this function does nothing.
+ */
+static void
+optimize_surface_points(t_methoddata_insolidangle *surf)
+{
+    /* TODO: Implement */
+}
+
+/*!
+ * \param[in] surf Surface data structure.
+ * \returns   An estimate for the area covered by the reference points.
+ */
+static real
+estimate_covered_fraction(t_methoddata_insolidangle *surf)
+{
+    int  t, p, n;
+    real cfrac, tfrac, pfrac;
+
+    cfrac = 0.0;
+    for (t = 0; t < surf->ntbins; ++t)
+    {
+        tfrac = cos(t * surf->tbinsize) - cos((t+1) * surf->tbinsize);
+        for (p = 0; p < surf->tbin[t].n; ++p)
+        {
+            pfrac = surf->tbin[t].p[p+1].left - surf->tbin[t].p[p].left;
+            n = surf->bin[surf->tbin[t].p[p].bin].n;
+            if (n == -1) /* Bin completely covered */
+            {
+                cfrac += tfrac * pfrac;
+            }
+            else if (n > 0) /* Bin partially covered */
+            {
+                cfrac += tfrac * pfrac / 2; /* A rough estimate */
+            }
+        }
+    }
+    return cfrac / (4*M_PI);
+}
+
+/*!
+ * \param[in] surf  Surface data structure to search.
+ * \param[in] x     Unit vector to check.
+ * \returns   TRUE if \p x is within the solid angle, FALSE otherwise.
+ */
+static gmx_bool
+is_surface_covered(t_methoddata_insolidangle *surf, rvec x)
+{
+    int  bin, i;
+
+    bin = find_surface_bin(surf, x);
+    /* Check for completely covered bin */
+    if (surf->bin[bin].n == -1)
+    {
+        return TRUE;
+    }
+    /* Check each point that partially covers the bin */
+    for (i = 0; i < surf->bin[bin].n; ++i)
+    {
+        if (sph_distc(x, surf->bin[bin].x[i]) < surf->distccut)
+        {
+            return TRUE;
+        }
+    }
+    return FALSE;
+}
diff --git a/src/gromacs/selection/sm_keywords.cpp b/src/gromacs/selection/sm_keywords.cpp
new file mode 100644 (file)
index 0000000..eeaff1f
--- /dev/null
@@ -0,0 +1,758 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * Implements internal selection methods for numeric and string keyword
+ * evaluation.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_selection
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <ctype.h>
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>  /*old Mac needs types before regex.h*/
+#endif
+#ifdef HAVE_REGEX_H
+#include <regex.h>
+#define USE_REGEX
+#endif
+
+#include <macros.h>
+#include <smalloc.h>
+#include <string2.h>
+
+#include "gromacs/errorreporting/errorcontext.h"
+#include "gromacs/fatalerror/fatalerror.h"
+#include "gromacs/selection/selmethod.h"
+
+#include "keywords.h"
+#include "parsetree.h"
+#include "scanner.h"
+#include "selelem.h"
+
+/** Allocates data for integer keyword evaluation. */
+static void *
+init_data_kwint(int npar, gmx_ana_selparam_t *param);
+/** Allocates data for real keyword evaluation. */
+static void *
+init_data_kwreal(int npar, gmx_ana_selparam_t *param);
+/** Allocates data for string keyword evaluation. */
+static void *
+init_data_kwstr(int npar, gmx_ana_selparam_t *param);
+/** Initializes data for integer keyword evaluation. */
+static int
+init_kwint(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
+/** Initializes data for real keyword evaluation. */
+static int
+init_kwreal(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
+/** Initializes data for string keyword evaluation. */
+static int
+init_kwstr(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
+/** Frees the memory allocated for string keyword evaluation. */
+static void
+free_data_kwstr(void *data);
+/** Evaluates integer selection keywords. */
+static int
+evaluate_keyword_int(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+                     gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
+/** Evaluates real selection keywords. */
+static int
+evaluate_keyword_real(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+                      gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
+/** Evaluates string selection keywords. */
+static int
+evaluate_keyword_str(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+                     gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
+
+/*! \internal \brief
+ * Data structure for integer keyword expression evaluation.
+ */
+typedef struct t_methoddata_kwint
+{
+    /** Array of values for the keyword. */
+    int               *v;
+    /** Number of ranges in the \p r array. */
+    int                n;
+    /*! \brief
+     * Array of sorted integer ranges to match against.
+     *
+     * Each range is made of two integers, giving the endpoints (inclusive).
+     * This field stores the pointer to the ranges allocated by the
+     * parameter parser; see \ref SPAR_RANGES for more information.
+     */
+    int               *r;
+} t_methoddata_kwint;
+
+/*! \internal \brief
+ * Data structure for real keyword expression evaluation.
+ */
+typedef struct t_methoddata_kwreal
+{
+    /** Array of values for the keyword. */
+    real              *v;
+    /** Number of ranges in the \p r array. */
+    int                n;
+    /*! \brief
+     * Array of sorted ranges to match against.
+     *
+     * Each range is made of two values, giving the endpoints (inclusive).
+     * This field stores the pointer to the ranges allocated by the
+     * parameter parser; see \ref SPAR_RANGES for more information.
+     */
+    real              *r;
+} t_methoddata_kwreal;
+
+/*! \internal \brief
+ * Data structure for string keyword expression evaluation.
+ */
+typedef struct t_methoddata_kwstr
+{
+    /** Array of values for the keyword. */
+    char             **v;
+    /** Number of elements in the \p val array. */
+    int                n;
+    /*! \internal \brief
+     * Array of strings/regular expressions to match against.
+     */
+    struct t_methoddata_kwstr_match {
+        /** TRUE if the expression is a regular expression, FALSE otherwise. */
+        gmx_bool           bRegExp;
+        /** The value to match against. */
+        union {
+#ifdef USE_REGEX
+            /** Compiled regular expression if \p bRegExp is TRUE. */
+            regex_t    r;
+#endif
+            /** The string if \p bRegExp is FALSE; */
+            char      *s;
+        }              u;
+    }                 *m;
+} t_methoddata_kwstr;
+
+/** Parameters for integer keyword evaluation. */
+static gmx_ana_selparam_t smparams_keyword_int[] = {
+    {NULL, {INT_VALUE, -1, {NULL}}, NULL, SPAR_ATOMVAL},
+    {NULL, {INT_VALUE, -1, {NULL}}, NULL, SPAR_RANGES | SPAR_VARNUM},
+};
+
+/** Parameters for real keyword evaluation. */
+static gmx_ana_selparam_t smparams_keyword_real[] = {
+    {NULL, {REAL_VALUE, -1, {NULL}}, NULL, SPAR_ATOMVAL | SPAR_DYNAMIC},
+    {NULL, {REAL_VALUE, -1, {NULL}}, NULL, SPAR_RANGES | SPAR_VARNUM},
+};
+
+/** Parameters for string keyword evaluation. */
+static gmx_ana_selparam_t smparams_keyword_str[] = {
+    {NULL, {STR_VALUE, -1, {NULL}}, NULL, SPAR_ATOMVAL},
+    {NULL, {STR_VALUE, -1, {NULL}}, NULL, SPAR_VARNUM},
+};
+
+/** \internal Selection method data for integer keyword evaluation. */
+gmx_ana_selmethod_t sm_keyword_int = {
+    "kw_int", GROUP_VALUE, SMETH_SINGLEVAL,
+    asize(smparams_keyword_int), smparams_keyword_int,
+    &init_data_kwint,
+     NULL,
+    &init_kwint,
+     NULL,
+     NULL,
+     NULL,
+    &evaluate_keyword_int,
+     NULL,
+    {NULL, 0, NULL},
+};
+
+/** \internal Selection method data for real keyword evaluation. */
+gmx_ana_selmethod_t sm_keyword_real = {
+    "kw_real", GROUP_VALUE, SMETH_SINGLEVAL,
+    asize(smparams_keyword_real), smparams_keyword_real,
+    &init_data_kwreal,
+     NULL,
+    &init_kwreal,
+     NULL,
+     NULL,
+     NULL,
+    &evaluate_keyword_real,
+     NULL,
+    {NULL, 0, NULL},
+};
+
+/** \internal Selection method data for string keyword evaluation. */
+gmx_ana_selmethod_t sm_keyword_str = {
+    "kw_str", GROUP_VALUE, SMETH_SINGLEVAL,
+    asize(smparams_keyword_str), smparams_keyword_str,
+    &init_data_kwstr,
+     NULL,
+    &init_kwstr,
+     NULL,
+    &free_data_kwstr,
+     NULL,
+    &evaluate_keyword_str,
+     NULL,
+    {NULL, 0, NULL},
+};
+
+/** Initializes keyword evaluation for an arbitrary group. */
+static int
+init_kweval(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
+/** Initializes output for keyword evaluation in an arbitrary group. */
+static int
+init_output_kweval(t_topology *top, gmx_ana_selvalue_t *out, void *data);
+/** Frees the data allocated for keyword evaluation in an arbitrary group. */
+static void
+free_data_kweval(void *data);
+/** Initializes frame evaluation for keyword evaluation in an arbitrary group. */
+static int
+init_frame_kweval(t_topology *top, t_trxframe *fr, t_pbc *pbc, void *data);
+/** Evaluates keywords in an arbitrary group. */
+static int
+evaluate_kweval(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+                gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
+
+/*! \internal \brief
+ * Data structure for keyword evaluation in arbitrary groups.
+ */
+typedef struct
+{
+    /** Wrapped keyword method for evaluating the values. */
+    gmx_ana_selmethod_t  *kwmethod;
+    /** Method data for \p kwmethod. */
+    void                 *kwmdata;
+    /** Group in which \p kwmethod should be evaluated. */
+    gmx_ana_index_t       g;
+} t_methoddata_kweval;
+
+/** Parameters for keyword evaluation in an arbitrary group. */
+static gmx_ana_selparam_t smparams_kweval[] = {
+    {NULL,   {GROUP_VALUE, 1, {NULL}}, NULL, SPAR_DYNAMIC},
+};
+
+
+/********************************************************************
+ * INTEGER KEYWORD EVALUATION
+ ********************************************************************/
+
+/*!
+ * \param[in] npar  Not used.
+ * \param     param Not used.
+ * \returns   Pointer to the allocated data (\ref t_methoddata_kwint).
+ *
+ * Allocates memory for a \ref t_methoddata_kwint structure.
+ */
+static void *
+init_data_kwint(int npar, gmx_ana_selparam_t *param)
+{
+    t_methoddata_kwint *data;
+
+    snew(data, 1);
+    return data;
+}
+
+/*!
+ * \param[in] top   Not used.
+ * \param[in] npar  Not used (should be 2).
+ * \param[in] param Method parameters (should point to \ref smparams_keyword_int).
+ * \param[in] data  Should point to \ref t_methoddata_kwint.
+ * \returns   0 (the initialization always succeeds).
+ */
+static int
+init_kwint(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data)
+{
+    t_methoddata_kwint *d = (t_methoddata_kwint *)data;
+
+    d->v = param[0].val.u.i;
+    d->n = param[1].val.nr;
+    d->r = param[1].val.u.i;
+    return 0;
+}
+
+/*!
+ * See sel_updatefunc() for description of the parameters.
+ * \p data should point to a \c t_methoddata_kwint.
+ *
+ * Does a binary search to find which atoms match the ranges in the
+ * \c t_methoddata_kwint structure for this selection.
+ * Matching atoms are stored in \p out->u.g.
+ */
+static int
+evaluate_keyword_int(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+                     gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
+{
+    t_methoddata_kwint *d = (t_methoddata_kwint *)data;
+    int                 n, i, j, jmin, jmax;
+    int                 val;
+
+    out->u.g->isize = 0;
+    n    = d->n;
+    for (i = 0; i < g->isize; ++i)
+    {
+        val = d->v[i];
+        if (d->r[0] > val || d->r[2*n-1] < val)
+        {
+            continue;
+        }
+        jmin = 0;
+        jmax = n;
+        while (jmax - jmin > 1)
+        {
+            j = jmin + (jmax - jmin) / 2;
+            if (val < d->r[2*j])
+            {
+                jmax = j;
+            }
+            else
+            {
+                jmin = j;
+                if (val <= d->r[2*j+1])
+                {
+                    break;
+                }
+                /* ++jmin;*/
+            }
+        }
+        if (val <= d->r[2*jmin+1])
+        {
+            out->u.g->index[out->u.g->isize++] = g->index[i];
+        }
+    }
+    return 0;
+}
+
+
+/********************************************************************
+ * REAL KEYWORD EVALUATION
+ ********************************************************************/
+
+/*!
+ * \param[in] npar  Not used.
+ * \param     param Not used.
+ * \returns   Pointer to the allocated data (\ref t_methoddata_kwreal).
+ *
+ * Allocates memory for a \ref t_methoddata_kwreal structure.
+ */
+static void *
+init_data_kwreal(int npar, gmx_ana_selparam_t *param)
+{
+    t_methoddata_kwreal *data;
+
+    snew(data, 1);
+    return data;
+}
+
+/*!
+ * \param[in] top   Not used.
+ * \param[in] npar  Not used (should be 2).
+ * \param[in] param Method parameters (should point to \ref smparams_keyword_real).
+ * \param[in] data  Should point to \ref t_methoddata_kwreal.
+ * \returns   0 (the initialization always succeeds).
+ */
+static int
+init_kwreal(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data)
+{
+    t_methoddata_kwreal *d = (t_methoddata_kwreal *)data;
+
+    d->v = param[0].val.u.r;
+    d->n = param[1].val.nr;
+    d->r = param[1].val.u.r;
+    return 0;
+}
+
+/*!
+ * See sel_updatefunc() for description of the parameters.
+ * \p data should point to a \c t_methoddata_kwreal.
+ *
+ * Does a binary search to find which atoms match the ranges in the
+ * \c t_methoddata_kwreal structure for this selection.
+ * Matching atoms are stored in \p out->u.g.
+ */
+static int
+evaluate_keyword_real(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+                     gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
+{
+    t_methoddata_kwreal *d = (t_methoddata_kwreal *)data;
+    int                  n, i, j, jmin, jmax;
+    real                 val;
+
+    out->u.g->isize = 0;
+    n    = d->n;
+    for (i = 0; i < g->isize; ++i)
+    {
+        val = d->v[i];
+        if (d->r[0] > val || d->r[2*n-1] < val)
+        {
+            continue;
+        }
+        jmin = 0;
+        jmax = n;
+        while (jmax - jmin > 1)
+        {
+            j = jmin + (jmax - jmin) / 2;
+            if (val < d->r[2*j])
+            {
+                jmax = j;
+            }
+            else
+            {
+                jmin = j;
+                if (val <= d->r[2*j+1])
+                {
+                    break;
+                }
+                /* ++jmin;*/
+            }
+        }
+        if (val <= d->r[2*jmin+1])
+        {
+            out->u.g->index[out->u.g->isize++] = g->index[i];
+        }
+    }
+    return 0;
+}
+
+
+/********************************************************************
+ * STRING KEYWORD EVALUATION
+ ********************************************************************/
+
+/*!
+ * \param[in] npar  Not used.
+ * \param     param Not used.
+ * \returns Pointer to the allocated data (\ref t_methoddata_kwstr).
+ *
+ * Allocates memory for a \ref t_methoddata_kwstr structure.
+ */
+static void *
+init_data_kwstr(int npar, gmx_ana_selparam_t *param)
+{
+    t_methoddata_kwstr *data;
+
+    snew(data, 1);
+    return data;
+}
+
+/*!
+ * \param[in] top   Not used.
+ * \param[in] npar  Not used (should be 2).
+ * \param[in] param Method parameters (should point to \ref smparams_keyword_str).
+ * \param[in] data  Should point to \ref t_methoddata_kwstr.
+ * \returns   0 (the initialization always succeeds).
+ */
+static int
+init_kwstr(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data)
+{
+    t_methoddata_kwstr *d = (t_methoddata_kwstr *)data;
+    char               *buf;
+    char               *s;
+    int                 i;
+    size_t              j;
+    gmx_bool                bRegExp;
+
+    d->v   = param[0].val.u.s;
+    d->n   = param[1].val.nr;
+    /* Return if this is not the first time */
+    if (d->m)
+    {
+        return 0;
+    }
+    snew(d->m, d->n);
+    for (i = 0; i < d->n; ++i)
+    {
+        s = param[1].val.u.s[i];
+        bRegExp = FALSE;
+        for (j = 0; j < strlen(s); ++j)
+        {
+            if (ispunct(s[j]) && s[j] != '?' && s[j] != '*')
+            {
+                bRegExp = TRUE;
+                break;
+            }
+        }
+        if (bRegExp)
+        {
+#ifdef USE_REGEX
+            snew(buf, strlen(s) + 3);
+            sprintf(buf, "^%s$", s);
+            if (regcomp(&d->m[i].u.r, buf, REG_EXTENDED | REG_NOSUB))
+            {
+                bRegExp = FALSE;
+                fprintf(stderr, "WARNING: error in regular expression,\n"
+                                "         will match '%s' as a simple string\n", s);
+            }
+            sfree(buf);
+#else
+            bRegExp = FALSE;
+            fprintf(stderr, "WARNING: no regular expressions support,\n"
+                            "         will match '%s' as a simple string\n", s);
+#endif
+        }
+        if (!bRegExp)
+        {
+            d->m[i].u.s = s;
+        }
+        d->m[i].bRegExp = bRegExp;
+    }
+    return 0;
+}
+
+/*!
+ * \param data Data to free (should point to a \ref t_methoddata_kwstr).
+ *
+ * Frees the memory allocated for t_methoddata_kwstr::val.
+ */
+static void
+free_data_kwstr(void *data)
+{
+    t_methoddata_kwstr *d = (t_methoddata_kwstr *)data;
+    int                 i;
+
+    for (i = 0; i < d->n; ++i)
+    {
+        if (d->m[i].bRegExp)
+        {
+#ifdef USE_REGEX
+            /* This branch should only be taken if regular expressions
+             * are available, but the ifdef is still needed. */
+            regfree(&d->m[i].u.r);
+#endif
+        }
+    }
+    sfree(d->m);
+}
+
+/*!
+ * See sel_updatefunc() for description of the parameters.
+ * \p data should point to a \c t_methoddata_kwstr.
+ *
+ * Does a linear search to find which atoms match the strings in the
+ * \c t_methoddata_kwstr structure for this selection.
+ * Wildcards are allowed in the strings.
+ * Matching atoms are stored in \p out->u.g.
+ */
+static int
+evaluate_keyword_str(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+                     gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
+{
+    t_methoddata_kwstr *d = (t_methoddata_kwstr *)data;
+    int                 i, j;
+    gmx_bool                bFound;
+
+    out->u.g->isize = 0;
+    for (i = 0; i < g->isize; ++i)
+    {
+        bFound = FALSE;
+        for (j = 0; j < d->n && !bFound; ++j)
+        {
+            if (d->m[j].bRegExp)
+            {
+#ifdef USE_REGEX
+                /* This branch should only be taken if regular expressions
+                 * are available, but the ifdef is still needed. */
+                if (!regexec(&d->m[j].u.r, d->v[i], 0, NULL, 0))
+                {
+                    bFound = TRUE;
+                }
+#endif
+            }
+            else
+            {
+                if (gmx_wcmatch(d->m[j].u.s, d->v[i]) == 0)
+                {
+                    bFound = TRUE;
+                }
+            }
+        }
+        if (bFound)
+        {
+            out->u.g->index[out->u.g->isize++] = g->index[i];
+        }
+    }
+    return 0;
+}
+
+
+/********************************************************************
+ * KEYWORD EVALUATION FOR ARBITRARY GROUPS
+ ********************************************************************/
+
+/*!
+ * \param[in] top   Not used.
+ * \param[in] npar  Not used.
+ * \param[in] param Not used.
+ * \param[in] data  Should point to \ref t_methoddata_kweval.
+ * \returns   0 on success, a non-zero error code on return.
+ *
+ * Calls the initialization method of the wrapped keyword.
+ */
+static int
+init_kweval(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data)
+{
+    t_methoddata_kweval *d = (t_methoddata_kweval *)data;
+
+    return d->kwmethod->init(top, 0, NULL, d->kwmdata);
+}
+
+/*!
+ * \param[in]     top   Not used.
+ * \param[in,out] out   Pointer to output data structure.
+ * \param[in,out] data  Should point to \c t_methoddata_kweval.
+ * \returns       0 for success.
+ */
+static int
+init_output_kweval(t_topology *top, gmx_ana_selvalue_t *out, void *data)
+{
+    t_methoddata_kweval *d = (t_methoddata_kweval *)data;
+
+    out->nr = d->g.isize;
+    return 0;
+}
+
+/*!
+ * \param data Data to free (should point to a \c t_methoddata_kweval).
+ *
+ * Frees the memory allocated for all the members of \c t_methoddata_kweval.
+ */
+static void
+free_data_kweval(void *data)
+{
+    t_methoddata_kweval *d = (t_methoddata_kweval *)data;
+
+    _gmx_selelem_free_method(d->kwmethod, d->kwmdata);
+}
+
+/*!
+ * \param[in]  top  Topology.
+ * \param[in]  fr   Current frame.
+ * \param[in]  pbc  PBC structure.
+ * \param      data Should point to a \ref t_methoddata_kweval.
+ * \returns    0 on success, a non-zero error code on error.
+ *
+ * Creates a lookup structure that enables fast queries of whether a point
+ * is within the solid angle or not.
+ */
+static int
+init_frame_kweval(t_topology *top, t_trxframe *fr, t_pbc *pbc, void *data)
+{
+    t_methoddata_kweval *d = (t_methoddata_kweval *)data;
+
+    return d->kwmethod->init_frame(top, fr, pbc, d->kwmdata);
+}
+
+/*!
+ * See sel_updatefunc() for description of the parameters.
+ * \p data should point to a \c t_methoddata_kweval.
+ *
+ * Calls the evaluation function of the wrapped keyword with the given
+ * parameters, with the exception of using \c t_methoddata_kweval::g for the
+ * evaluation group.
+ */
+static int
+evaluate_kweval(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+                gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
+{
+    t_methoddata_kweval *d = (t_methoddata_kweval *)data;
+
+    return d->kwmethod->update(top, fr, pbc, &d->g, out, d->kwmdata);
+}
+
+/*!
+ * \param[out]  selp    Pointer to receive a pointer to the created selection
+ *      element (set to NULL on error).
+ * \param[in]   method  Keyword selection method to evaluate.
+ * \param[in]   param   Parameter that gives the group to evaluate \p method in.
+ * \param[in]   scanner Scanner data structure.
+ * \returns     0 on success, non-zero error code on error.
+ *
+ * Creates a \ref SEL_EXPRESSION selection element (pointer put in \c *selp)
+ * that evaluates the keyword method given by \p method in the group given by
+ * \p param.
+ */
+int
+_gmx_sel_init_keyword_evaluator(t_selelem **selp, gmx_ana_selmethod_t *method,
+                                t_selexpr_param *param, void *scanner)
+{
+    t_selelem            *sel;
+    t_methoddata_kweval  *data;
+
+    gmx::AbstractErrorReporter *errors = _gmx_sel_lexer_error_reporter(scanner);
+    char  buf[1024];
+    sprintf(buf, "In evaluation of '%s'", method->name);
+    gmx::ErrorContext  context(errors, buf);
+
+    if ((method->flags & (SMETH_SINGLEVAL | SMETH_VARNUMVAL))
+        || method->outinit || method->pupdate)
+    {
+        _gmx_selexpr_free_params(param);
+        GMX_ERROR(gmx::eeInternalError,
+                  "Unsupported keyword method for arbitrary group evaluation");
+    }
+
+    *selp = NULL;
+    sel = _gmx_selelem_create(SEL_EXPRESSION);
+    _gmx_selelem_set_method(sel, method, scanner);
+
+    snew(data, 1);
+    data->kwmethod = sel->u.expr.method;
+    data->kwmdata  = sel->u.expr.mdata;
+    gmx_ana_index_clear(&data->g);
+
+    snew(sel->u.expr.method, 1);
+    memcpy(sel->u.expr.method, data->kwmethod, sizeof(gmx_ana_selmethod_t));
+    sel->u.expr.method->flags       |= SMETH_VARNUMVAL;
+    sel->u.expr.method->init_data    = NULL;
+    sel->u.expr.method->set_poscoll  = NULL;
+    sel->u.expr.method->init         = method->init ? &init_kweval : NULL;
+    sel->u.expr.method->outinit      = &init_output_kweval;
+    sel->u.expr.method->free         = &free_data_kweval;
+    sel->u.expr.method->init_frame   = method->init_frame ? &init_frame_kweval : NULL;
+    sel->u.expr.method->update       = &evaluate_kweval;
+    sel->u.expr.method->pupdate      = NULL;
+    sel->u.expr.method->nparams      = asize(smparams_kweval);
+    sel->u.expr.method->param        = smparams_kweval;
+    _gmx_selelem_init_method_params(sel, scanner);
+    sel->u.expr.mdata = data;
+
+    sel->u.expr.method->param[0].val.u.g = &data->g;
+
+    sfree(param->name);
+    param->name = NULL;
+    if (!_gmx_sel_parse_params(param, sel->u.expr.method->nparams,
+                               sel->u.expr.method->param, sel, scanner))
+    {
+        _gmx_selelem_free(sel);
+        return -1;
+    }
+    *selp = sel;
+    return 0;
+}
diff --git a/src/gromacs/selection/sm_merge.cpp b/src/gromacs/selection/sm_merge.cpp
new file mode 100644 (file)
index 0000000..b0a16e6
--- /dev/null
@@ -0,0 +1,386 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * Implements the \p merge and \p plus selection modifiers.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_selection
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <macros.h>
+#include <smalloc.h>
+#include <vec.h>
+
+#include "gromacs/selection/position.h"
+#include "gromacs/selection/selmethod.h"
+
+/*! \internal \brief
+ * Data structure for the merging selection modifiers.
+ */
+typedef struct
+{
+    /** Input positions. */
+    gmx_ana_pos_t    p1;
+    /** Other input positions. */
+    gmx_ana_pos_t    p2;
+    /** Group to store the output atom indices. */
+    gmx_ana_index_t  g;
+    /** Stride for merging (\c stride values from \c p1 for each in \c p2). */
+    int              stride;
+} t_methoddata_merge;
+
+/** Allocates data for the merging selection modifiers. */
+static void *
+init_data_merge(int npar, gmx_ana_selparam_t *param);
+/** Initializes data for the merging selection modifiers. */
+static int
+init_merge(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
+/** Initializes output for the \p merge selection modifier. */
+static int
+init_output_merge(t_topology *top, gmx_ana_selvalue_t *out, void *data);
+/** Initializes output for the \p plus selection modifier. */
+static int
+init_output_plus(t_topology *top, gmx_ana_selvalue_t *out, void *data);
+/** Frees the memory allocated for the merging selection modifiers. */
+static void
+free_data_merge(void *data);
+/** Evaluates the \p merge selection modifier. */
+static int
+evaluate_merge(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+               gmx_ana_pos_t *p, gmx_ana_selvalue_t *out, void *data);
+/** Evaluates the \p plus selection modifier. */
+static int
+evaluate_plus(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+              gmx_ana_pos_t *p, gmx_ana_selvalue_t *out, void *data);
+
+/** Parameters for the merging selection modifiers. */
+static gmx_ana_selparam_t smparams_merge[] = {
+    {NULL,       {POS_VALUE, -1, {NULL}}, NULL, SPAR_DYNAMIC | SPAR_VARNUM},
+    {NULL,       {POS_VALUE, -1, {NULL}}, NULL, SPAR_DYNAMIC | SPAR_VARNUM},
+    {"stride",   {INT_VALUE,  1, {NULL}}, NULL, SPAR_OPTIONAL},
+};
+
+/** Help text for the merging selection modifiers. */
+static const char *help_merge[] = {
+    "MERGING SELECTIONS[PAR]",
+
+    "[TT]POSEXPR merge POSEXPR [stride INT][tt][BR]",
+    "[TT]POSEXPR merge POSEXPR [merge POSEXPR ...][tt][BR]",
+    "[TT]POSEXPR plus POSEXPR [plus POSEXPR ...][tt][PAR]",
+
+    "Basic selection keywords can only create selections where each atom",
+    "occurs at most once. The [TT]merge[tt] and [TT]plus[tt] selection",
+    "keywords can be used to work around this limitation. Both create",
+    "a selection that contains the positions from all the given position",
+    "expressions, even if they contain duplicates.",
+    "The difference between the two is that [TT]merge[tt] expects two or more",
+    "selections with the same number of positions, and the output contains",
+    "the input positions selected from each expression in turn, i.e.,",
+    "the output is like A1 B1 A2 B2 and so on. It is also possible to merge",
+    "selections of unequal size as long as the size of the first is a",
+    "multiple of the second one. The [TT]stride[tt] parameter can be used",
+    "to explicitly provide this multiplicity.",
+    "[TT]plus[tt] simply concatenates the positions after each other, and",
+    "can work also with selections of different sizes.",
+    "These keywords are valid only at the selection level, not in any",
+    "subexpressions.[PAR]",
+};
+
+/** \internal Selection method data for the \p plus modifier. */
+gmx_ana_selmethod_t sm_merge = {
+    "merge", POS_VALUE, SMETH_MODIFIER,
+    asize(smparams_merge), smparams_merge,
+    &init_data_merge,
+    NULL,
+    &init_merge,
+    &init_output_merge,
+    &free_data_merge,
+    NULL,
+    NULL,
+    &evaluate_merge,
+    {"merge POSEXPR", asize(help_merge), help_merge},
+};
+
+/** \internal Selection method data for the \p plus modifier. */
+gmx_ana_selmethod_t sm_plus = {
+    "plus", POS_VALUE, SMETH_MODIFIER,
+    asize(smparams_merge)-1, smparams_merge,
+    &init_data_merge,
+    NULL,
+    &init_merge,
+    &init_output_plus,
+    &free_data_merge,
+    NULL,
+    NULL,
+    &evaluate_plus,
+    {"plus POSEXPR", asize(help_merge), help_merge},
+};
+
+/*!
+ * \param[in]     npar  Should be 2 for \c plus and 3 for \c merge.
+ * \param[in,out] param Method parameters (should point to a copy of
+ *   \ref smparams_merge).
+ * \returns Pointer to the allocated data (\p t_methoddata_merge).
+ *
+ * Allocates memory for a \p t_methoddata_merge structure.
+ */
+static void *
+init_data_merge(int npar, gmx_ana_selparam_t *param)
+{
+    t_methoddata_merge *data;
+
+    snew(data, 1);
+    data->stride = 0;
+    param[0].val.u.p = &data->p1;
+    param[1].val.u.p = &data->p2;
+    if (npar > 2)
+    {
+        param[2].val.u.i = &data->stride;
+    }
+    return data;
+}
+
+/*!
+ * \param[in] top   Not used.
+ * \param[in] npar  Not used (should be 2 or 3).
+ * \param[in] param Method parameters (should point to \ref smparams_merge).
+ * \param[in] data  Should point to a \p t_methoddata_merge.
+ * \returns   0 if everything is successful, -1 on error.
+ */
+static int
+init_merge(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data)
+{
+    t_methoddata_merge *d = (t_methoddata_merge *)data;
+    int                 i;
+
+    if (d->stride < 0)
+    {
+        fprintf(stderr, "error: stride for merging should be positive\n");
+        return -1;
+    }
+    /* If no stride given, deduce it from the input sizes */
+    if (d->stride == 0)
+    {
+        d->stride = d->p1.nr / d->p2.nr;
+    }
+    if (d->p1.nr != d->stride*d->p2.nr)
+    {
+        fprintf(stderr, "error: the number of positions to be merged are not compatible\n");
+        return -1;
+    }
+    /* We access the m.b.nra field instead of g->isize in the position
+     * data structures to handle cases where g is NULL
+     * (this occurs with constant positions. */
+    gmx_ana_index_reserve(&d->g, d->p1.m.b.nra + d->p2.m.b.nra);
+    d->g.isize = d->p1.m.b.nra + d->p2.m.b.nra;
+    return 0;
+}
+
+/*! \brief
+ * Does common initialization to all merging modifiers.
+ *
+ * \param[in]     top   Topology data structure.
+ * \param[in,out] out   Pointer to output data structure.
+ * \param[in,out] data  Should point to \c t_methoddata_merge.
+ * \returns       0 for success.
+ */
+static int
+init_output_common(t_topology *top, gmx_ana_selvalue_t *out, void *data)
+{
+    t_methoddata_merge *d = (t_methoddata_merge *)data;
+
+    if (d->p1.m.type != d->p2.m.type)
+    {
+        /* TODO: Maybe we could pick something else here? */
+        out->u.p->m.type = INDEX_UNKNOWN;
+    }
+    else
+    {
+        out->u.p->m.type = d->p1.m.type;
+    }
+    gmx_ana_pos_reserve(out->u.p, d->p1.nr + d->p2.nr, d->g.isize);
+    if (d->p1.v)
+    {
+        gmx_ana_pos_reserve_velocities(out->u.p);
+    }
+    if (d->p1.f)
+    {
+        gmx_ana_pos_reserve_forces(out->u.p);
+    }
+    gmx_ana_pos_set_evalgrp(out->u.p, &d->g);
+    gmx_ana_pos_empty_init(out->u.p);
+    d->g.isize = 0;
+    return 0;
+}
+
+/*!
+ * \param[in]     top   Topology data structure.
+ * \param[in,out] out   Pointer to output data structure.
+ * \param[in,out] data  Should point to \c t_methoddata_merge.
+ * \returns       0 for success.
+ */
+static int
+init_output_merge(t_topology *top, gmx_ana_selvalue_t *out, void *data)
+{
+    t_methoddata_merge *d = (t_methoddata_merge *)data;
+    int                 i, j;
+
+    init_output_common(top, out, data);
+    for (i = 0; i < d->p2.nr; ++i)
+    {
+        for (j = 0; j < d->stride; ++j)
+        {
+            gmx_ana_pos_append_init(out->u.p, &d->g, &d->p1, d->stride*i+j);
+        }
+        gmx_ana_pos_append_init(out->u.p, &d->g, &d->p2, i);
+    }
+    return 0;
+}
+
+/*!
+ * \param[in]     top   Topology data structure.
+ * \param[in,out] out   Pointer to output data structure.
+ * \param[in,out] data  Should point to \c t_methoddata_merge.
+ * \returns       0 for success.
+ */
+static int
+init_output_plus(t_topology *top, gmx_ana_selvalue_t *out, void *data)
+{
+    t_methoddata_merge *d = (t_methoddata_merge *)data;
+    int                 i;
+
+    init_output_common(top, out, data);
+    for (i = 0; i < d->p1.nr; ++i)
+    {
+        gmx_ana_pos_append_init(out->u.p, &d->g, &d->p1, i);
+    }
+    for (i = 0; i < d->p2.nr; ++i)
+    {
+        gmx_ana_pos_append_init(out->u.p, &d->g, &d->p2, i);
+    }
+    return 0;
+}
+
+/*!
+ * \param data Data to free (should point to a \p t_methoddata_merge).
+ *
+ * Frees the memory allocated for \c t_methoddata_merge.
+ */
+static void
+free_data_merge(void *data)
+{
+    t_methoddata_merge *d = (t_methoddata_merge *)data;
+
+    gmx_ana_index_deinit(&d->g);
+}
+
+/*!
+ * \param[in]  top   Not used.
+ * \param[in]  fr    Not used.
+ * \param[in]  pbc   Not used.
+ * \param[in]  p     Positions to merge (should point to \p data->p1).
+ * \param[out] out   Output data structure (\p out->u.p is used).
+ * \param[in]  data  Should point to a \p t_methoddata_merge.
+ * \returns    0 on success.
+ */
+static int
+evaluate_merge(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+               gmx_ana_pos_t *p, gmx_ana_selvalue_t *out, void *data)
+{
+    t_methoddata_merge *d = (t_methoddata_merge *)data;
+    int                 i, j;
+    int                 refid;
+
+    if (d->p1.nr != d->stride*d->p2.nr)
+    {
+        fprintf(stderr, "error: the number of positions to be merged are not compatible\n");
+        return -1;
+    }
+    d->g.isize = 0;
+    gmx_ana_pos_empty(out->u.p);
+    for (i = 0; i < d->p2.nr; ++i)
+    {
+        for (j = 0; j < d->stride; ++j)
+        {
+            refid = d->p1.m.refid[d->stride*i+j];
+            if (refid != -1)
+            {
+                refid = (d->stride+1) * (refid / d->stride) + (refid % d->stride);
+            }
+            gmx_ana_pos_append(out->u.p, &d->g, &d->p1, d->stride*i+j, refid);
+        }
+        refid = (d->stride+1)*d->p2.m.refid[i]+d->stride;
+        gmx_ana_pos_append(out->u.p, &d->g, &d->p2, i, refid);
+    }
+    gmx_ana_pos_append_finish(out->u.p);
+    return 0;
+}
+
+/*!
+ * \param[in]  top   Not used.
+ * \param[in]  fr    Not used.
+ * \param[in]  pbc   Not used.
+ * \param[in]  p     Positions to merge (should point to \p data->p1).
+ * \param[out] out   Output data structure (\p out->u.p is used).
+ * \param[in]  data  Should point to a \p t_methoddata_merge.
+ * \returns    0 on success.
+ */
+static int
+evaluate_plus(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+              gmx_ana_pos_t *p, gmx_ana_selvalue_t *out, void *data)
+{
+    t_methoddata_merge *d = (t_methoddata_merge *)data;
+    int                 i;
+    int                 refid;
+
+    d->g.isize = 0;
+    gmx_ana_pos_empty(out->u.p);
+    for (i = 0; i < d->p1.nr; ++i)
+    {
+        refid = d->p1.m.refid[i];
+        gmx_ana_pos_append(out->u.p, &d->g, &d->p1, i, refid);
+    }
+    for (i = 0; i < d->p2.nr; ++i)
+    {
+        refid = d->p2.m.refid[i];
+        if (refid != -1)
+        {
+            refid += d->p1.m.b.nr;
+        }
+        gmx_ana_pos_append(out->u.p, &d->g, &d->p2, i, refid);
+    }
+    gmx_ana_pos_append_finish(out->u.p);
+    return 0;
+}
diff --git a/src/gromacs/selection/sm_permute.cpp b/src/gromacs/selection/sm_permute.cpp
new file mode 100644 (file)
index 0000000..7b6deeb
--- /dev/null
@@ -0,0 +1,271 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * Implements the \p permute selection modifier.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_selection
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <macros.h>
+#include <smalloc.h>
+#include <vec.h>
+
+#include "gromacs/selection/position.h"
+#include "gromacs/selection/selmethod.h"
+
+/*! \internal \brief
+ * Data structure for the \p permute selection modifier.
+ */
+typedef struct
+{
+    /** Positions to permute. */
+    gmx_ana_pos_t    p;
+    /** Group to receive the output permutation. */
+    gmx_ana_index_t  g;
+    /** Number of elements in the permutation. */
+    int              n;
+    /** Array describing the permutation. */
+    int             *perm;
+    /** Array that has the permutation reversed. */
+    int             *rperm;
+} t_methoddata_permute;
+
+/** Allocates data for the \p permute selection modifier. */
+static void *
+init_data_permute(int npar, gmx_ana_selparam_t *param);
+/** Initializes data for the \p permute selection modifier. */
+static int
+init_permute(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
+/** Initializes output for the \p permute selection modifier. */
+static int
+init_output_permute(t_topology *top, gmx_ana_selvalue_t *out, void *data);
+/** Frees the memory allocated for the \p permute selection modifier. */
+static void
+free_data_permute(void *data);
+/** Evaluates the \p permute selection modifier. */
+static int
+evaluate_permute(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+                 gmx_ana_pos_t *p, gmx_ana_selvalue_t *out, void *data);
+
+/** Parameters for the \p permute selection modifier. */
+static gmx_ana_selparam_t smparams_permute[] = {
+    {NULL,       {POS_VALUE, -1, {NULL}}, NULL, SPAR_DYNAMIC | SPAR_VARNUM},
+    {NULL,       {INT_VALUE, -1, {NULL}}, NULL, SPAR_VARNUM},
+};
+
+/** Help text for the \p permute selection modifier. */
+static const char *help_permute[] = {
+    "PERMUTING SELECTIONS[PAR]",
+
+    "[TT]permute P1 ... PN[tt][PAR]",
+
+    "By default, all selections are evaluated such that the atom indices are",
+    "returned in ascending order. This can be changed by appending",
+    "[TT]permute P1 P2 ... PN[tt] to an expression.",
+    "The [TT]Pi[tt] should form a permutation of the numbers 1 to N.",
+    "This keyword permutes each N-position block in the selection such that",
+    "the i'th position in the block becomes Pi'th.",
+    "Note that it is the positions that are permuted, not individual atoms.",
+    "A fatal error occurs if the size of the selection is not a multiple of n.",
+    "It is only possible to permute the whole selection expression, not any",
+    "subexpressions, i.e., the [TT]permute[tt] keyword should appear last in",
+    "a selection.",
+};
+
+/** \internal Selection method data for the \p permute modifier. */
+gmx_ana_selmethod_t sm_permute = {
+    "permute", POS_VALUE, SMETH_MODIFIER,
+    asize(smparams_permute), smparams_permute,
+    &init_data_permute,
+    NULL,
+    &init_permute,
+    &init_output_permute,
+    &free_data_permute,
+    NULL,
+    NULL,
+    &evaluate_permute,
+    {"permute P1 ... PN", asize(help_permute), help_permute},
+};
+
+/*!
+ * \param[in]     npar  Not used (should be 2).
+ * \param[in,out] param Method parameters (should point to a copy of
+ *   \ref smparams_permute).
+ * \returns Pointer to the allocated data (\p t_methoddata_permute).
+ *
+ * Allocates memory for a \p t_methoddata_permute structure.
+ */
+static void *
+init_data_permute(int npar, gmx_ana_selparam_t *param)
+{
+    t_methoddata_permute *data;
+
+    snew(data, 1);
+    param[0].val.u.p = &data->p;
+    return data;
+}
+
+/*!
+ * \param[in] top   Not used.
+ * \param[in] npar  Not used (should be 2).
+ * \param[in] param Method parameters (should point to \ref smparams_permute).
+ * \param[in] data  Should point to a \p t_methoddata_permute.
+ * \returns   0 if the input permutation is valid, -1 on error.
+ */
+static int
+init_permute(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data)
+{
+    t_methoddata_permute *d = (t_methoddata_permute *)data;
+    int                   i;
+
+    gmx_ana_index_reserve(&d->g, d->p.g->isize);
+    d->n    = param[1].val.nr;
+    d->perm = param[1].val.u.i;
+    if (d->p.nr % d->n != 0)
+    {
+        fprintf(stderr, "error: the number of positions to be permuted is not divisible by %d\n",
+                d->n);
+        return -1;
+    }
+    snew(d->rperm, d->n);
+    for (i = 0; i < d->n; ++i)
+    {
+        d->rperm[i] = -1;
+    }
+    for (i = 0; i < d->n; ++i)
+    {
+        d->perm[i]--;
+        if (d->perm[i] < 0 || d->perm[i] >= d->n)
+        {
+            fprintf(stderr, "invalid permutation");
+            return -1;
+        }
+        if (d->rperm[d->perm[i]] >= 0)
+        {
+            fprintf(stderr, "invalid permutation");
+            return -1;
+        }
+        d->rperm[d->perm[i]] = i;
+    }
+    return 0;
+}
+
+/*!
+ * \param[in]     top   Topology data structure.
+ * \param[in,out] out   Pointer to output data structure.
+ * \param[in,out] data  Should point to \c t_methoddata_permute.
+ * \returns       0 for success.
+ */
+static int
+init_output_permute(t_topology *top, gmx_ana_selvalue_t *out, void *data)
+{
+    t_methoddata_permute *d = (t_methoddata_permute *)data;
+    int                   i, j, b, k;
+
+    gmx_ana_pos_copy(out->u.p, &d->p, TRUE);
+    gmx_ana_pos_set_evalgrp(out->u.p, &d->g);
+    d->g.isize = 0;
+    gmx_ana_pos_empty_init(out->u.p);
+    for (i = 0; i < d->p.nr; i += d->n)
+    {
+        for (j = 0; j < d->n; ++j)
+        {
+            b = i + d->rperm[j];
+            gmx_ana_pos_append_init(out->u.p, &d->g, &d->p, b);
+        }
+    }
+    return 0;
+}
+
+/*!
+ * \param data Data to free (should point to a \p t_methoddata_permute).
+ *
+ * Frees the memory allocated for \c t_methoddata_permute.
+ */
+static void
+free_data_permute(void *data)
+{
+    t_methoddata_permute *d = (t_methoddata_permute *)data;
+
+    gmx_ana_index_deinit(&d->g);
+    sfree(d->rperm);
+}
+
+/*!
+ * \param[in]  top   Not used.
+ * \param[in]  fr    Not used.
+ * \param[in]  pbc   Not used.
+ * \param[in]  p     Positions to permute (should point to \p data->p).
+ * \param[out] out   Output data structure (\p out->u.p is used).
+ * \param[in]  data  Should point to a \p t_methoddata_permute.
+ * \returns    0 if \p p could be permuted, -1 on error.
+ *
+ * Returns -1 if the size of \p p is not divisible by the number of
+ * elements in the permutation.
+ */
+static int
+evaluate_permute(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+                 gmx_ana_pos_t *p, gmx_ana_selvalue_t *out, void *data)
+{
+    t_methoddata_permute *d = (t_methoddata_permute *)data;
+    int                   i, j, b, k;
+    int                   refid;
+
+    if (d->p.nr % d->n != 0)
+    {
+        fprintf(stderr, "error: the number of positions to be permuted is not divisible by %d\n",
+                d->n);
+        return -1;
+    }
+    d->g.isize = 0;
+    gmx_ana_pos_empty(out->u.p);
+    for (i = 0; i < d->p.nr; i += d->n)
+    {
+        for (j = 0; j < d->n; ++j)
+        {
+            b = i + d->rperm[j];
+            refid = d->p.m.refid[b];
+            if (refid != -1)
+            {
+                /* De-permute the reference ID */
+                refid = refid - (refid % d->n) + d->perm[refid % d->n];
+            }
+            gmx_ana_pos_append(out->u.p, &d->g, p, b, refid);
+        }
+    }
+    gmx_ana_pos_append_finish(out->u.p);
+    return 0;
+}
diff --git a/src/gromacs/selection/sm_position.cpp b/src/gromacs/selection/sm_position.cpp
new file mode 100644 (file)
index 0000000..ea699ba
--- /dev/null
@@ -0,0 +1,377 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * Implements position evaluation selection methods.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_selection
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <macros.h>
+#include <smalloc.h>
+#include <string2.h>
+
+#include "gromacs/selection/indexutil.h"
+#include "gromacs/selection/poscalc.h"
+#include "gromacs/selection/position.h"
+#include "gromacs/selection/selmethod.h"
+
+#include "keywords.h"
+#include "selelem.h"
+
+/*! \internal \brief
+ * Data structure for position keyword evaluation.
+ */
+typedef struct
+{
+    /** Position calculation collection to use. */
+    gmx_ana_poscalc_coll_t *pcc;
+    /** Index group for which the center should be evaluated. */
+    gmx_ana_index_t    g;
+    /** Position evaluation data structure. */
+    gmx_ana_poscalc_t *pc;
+    /** TRUE if periodic boundary conditions should be used. */
+    gmx_bool               bPBC;
+    /** Type of positions to calculate. */
+    char              *type;
+    /** Flags for the position calculation. */
+    int                flags;
+} t_methoddata_pos;
+
+/** Allocates data for position evaluation selection methods. */
+static void *
+init_data_pos(int npar, gmx_ana_selparam_t *param);
+/** Sets the position calculation collection for position evaluation selection methods. */
+static void
+set_poscoll_pos(gmx_ana_poscalc_coll_t *pcc, void *data);
+/** Initializes position evaluation keywords. */
+static int
+init_kwpos(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
+/** Initializes the \p cog selection method. */
+static int
+init_cog(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
+/** Initializes the \p cog selection method. */
+static int
+init_com(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
+/** Initializes output for position evaluation selection methods. */
+static int
+init_output_pos(t_topology *top, gmx_ana_selvalue_t *out, void *data);
+/** Frees the data allocated for position evaluation selection methods. */
+static void
+free_data_pos(void *data);
+/** Evaluates position evaluation selection methods. */
+static int
+evaluate_pos(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+             gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
+
+/** Parameters for position keyword evaluation. */
+static gmx_ana_selparam_t smparams_keyword_pos[] = {
+    {NULL,   {GROUP_VALUE, 1, {NULL}}, NULL, SPAR_DYNAMIC},
+};
+
+/** Parameters for the \p cog and \p com selection methods. */
+static gmx_ana_selparam_t smparams_com[] = {
+    {"of",   {GROUP_VALUE, 1, {NULL}}, NULL, SPAR_DYNAMIC},
+    {"pbc",  {NO_VALUE,    0, {NULL}}, NULL, 0},
+};
+
+/** \internal Selection method data for position keyword evaluation. */
+gmx_ana_selmethod_t sm_keyword_pos = {
+    "kw_pos", POS_VALUE, SMETH_DYNAMIC | SMETH_VARNUMVAL,
+    asize(smparams_keyword_pos), smparams_keyword_pos,
+    &init_data_pos,
+    &set_poscoll_pos,
+    &init_kwpos,
+    &init_output_pos,
+    &free_data_pos,
+     NULL,
+    &evaluate_pos,
+     NULL,
+    {NULL, 0, NULL},
+};
+
+/** \internal Selection method data for the \p cog method. */
+gmx_ana_selmethod_t sm_cog = {
+    "cog", POS_VALUE, SMETH_DYNAMIC | SMETH_SINGLEVAL,
+    asize(smparams_com), smparams_com,
+    &init_data_pos,
+    &set_poscoll_pos,
+    &init_cog,
+    &init_output_pos,
+    &free_data_pos,
+     NULL,
+    &evaluate_pos,
+     NULL,
+    {"cog of ATOM_EXPR [pbc]", 0, NULL},
+};
+
+/** \internal Selection method data for the \p com method. */
+gmx_ana_selmethod_t sm_com = {
+    "com", POS_VALUE, SMETH_REQTOP | SMETH_DYNAMIC | SMETH_SINGLEVAL,
+    asize(smparams_com), smparams_com,
+    &init_data_pos,
+    &set_poscoll_pos,
+    &init_com,
+    &init_output_pos,
+    &free_data_pos,
+     NULL,
+    &evaluate_pos,
+     NULL,
+    {"com of ATOM_EXPR [pbc]", 0, NULL},
+};
+
+/*!
+ * \param[in]     npar  Should be 1 or 2.
+ * \param[in,out] param Method parameters (should point to
+ *   \ref smparams_keyword_pos or \ref smparams_com).
+ * \returns       Pointer to the allocated data (\c t_methoddata_pos).
+ *
+ * Allocates memory for a \c t_methoddata_pos structure and initializes
+ * the first parameter to define the value for \c t_methoddata_pos::g.
+ * If a second parameter is present, it is used for setting the
+ * \c t_methoddata_pos::bPBC flag.
+ */
+static void *
+init_data_pos(int npar, gmx_ana_selparam_t *param)
+{
+    t_methoddata_pos *data;
+
+    snew(data, 1);
+    param[0].val.u.g = &data->g;
+    if (npar > 1)
+    {
+        param[1].val.u.b = &data->bPBC;
+    }
+    data->pc       = NULL;
+    data->bPBC     = FALSE;
+    data->type     = NULL;
+    data->flags    = -1;
+    return data;
+}
+
+/*!
+ * \param[in]     pcc   Position calculation collection to use.
+ * \param[in,out] data  Should point to \c t_methoddata_pos.
+ */
+static void
+set_poscoll_pos(gmx_ana_poscalc_coll_t *pcc, void *data)
+{
+    ((t_methoddata_pos *)data)->pcc = pcc;
+}
+
+/*!
+ * \param[in,out] sel   Selection element to initialize.
+ * \param[in]     type  One of the enum values acceptable for
+ *   gmx_ana_poscalc_type_from_enum().
+ *
+ * Initializes the reference position type for position evaluation.
+ * If called multiple times, the first setting takes effect, and later calls
+ * are neglected.
+ */
+void
+_gmx_selelem_set_kwpos_type(t_selelem *sel, const char *type)
+{
+    t_methoddata_pos *d = (t_methoddata_pos *)sel->u.expr.mdata;
+
+    if (sel->type != SEL_EXPRESSION || !sel->u.expr.method
+        || sel->u.expr.method->name != sm_keyword_pos.name)
+    {
+        return;
+    }
+    if (!d->type && type)
+    {
+        d->type  = strdup(type);
+        /* FIXME: It would be better not to have the string here hardcoded. */
+        if (type[0] != 'a')
+        {
+            sel->u.expr.method->flags |= SMETH_REQTOP;
+        }
+    }
+}
+
+/*!
+ * \param[in,out] sel   Selection element to initialize.
+ * \param[in]     flags Default completion flags
+ *   (see gmx_ana_poscalc_type_from_enum()).
+ *
+ * Initializes the flags for position evaluation.
+ * If called multiple times, the first setting takes effect, and later calls
+ * are neglected.
+ */
+void
+_gmx_selelem_set_kwpos_flags(t_selelem *sel, int flags)
+{
+    t_methoddata_pos *d = (t_methoddata_pos *)sel->u.expr.mdata;
+
+    if (sel->type != SEL_EXPRESSION || !sel->u.expr.method
+        || sel->u.expr.method->name != sm_keyword_pos.name)
+    {
+        return;
+    }
+    if (d->flags == -1)
+    {
+        d->flags = flags;
+    }
+}
+
+/*!
+ * \param[in] top   Not used.
+ * \param[in] npar  Not used.
+ * \param[in] param Not used.
+ * \param[in,out] data  Should point to \c t_methoddata_pos.
+ * \returns       0 on success, a non-zero error code on error.
+ *
+ * The \c t_methoddata_pos::type field should have been initialized
+ * externally using _gmx_selelem_set_kwpos_type().
+ */
+static int
+init_kwpos(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data)
+{
+    t_methoddata_pos *d = (t_methoddata_pos *)data;
+    int               rc;
+
+    if (!(param[0].flags & SPAR_DYNAMIC))
+    {
+        d->flags &= ~(POS_DYNAMIC | POS_MASKONLY);
+    }
+    else if (!(d->flags & POS_MASKONLY))
+    {
+        d->flags |= POS_DYNAMIC;
+    }
+    rc = gmx_ana_poscalc_create_enum(&d->pc, d->pcc, d->type, d->flags);
+    if (rc != 0)
+    {
+        return rc;
+    }
+    gmx_ana_poscalc_set_maxindex(d->pc, &d->g);
+    return 0;
+}
+
+/*!
+ * \param[in]     top   Topology data structure.
+ * \param[in]     npar  Not used.
+ * \param[in]     param Not used.
+ * \param[in,out] data  Should point to \c t_methoddata_pos.
+ * \returns       0 on success, a non-zero error code on error.
+ */
+static int
+init_cog(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data)
+{
+    t_methoddata_pos *d = (t_methoddata_pos *)data;
+    int               rc;
+
+    d->flags = (param[0].flags & SPAR_DYNAMIC) ? POS_DYNAMIC : 0;
+    rc = gmx_ana_poscalc_create(&d->pc, d->pcc, d->bPBC ? POS_ALL_PBC : POS_ALL,
+                                d->flags);
+    if (rc != 0)
+    {
+        return rc;
+    }
+    gmx_ana_poscalc_set_maxindex(d->pc, &d->g);
+    return 0;
+}
+
+/*!
+ * \param[in]     top   Topology data structure.
+ * \param[in]     npar  Not used.
+ * \param[in]     param Not used.
+ * \param[in,out] data  Should point to \c t_methoddata_pos.
+ * \returns       0 on success, a non-zero error code on error.
+ */
+static int
+init_com(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data)
+{
+    t_methoddata_pos *d = (t_methoddata_pos *)data;
+    int               rc;
+
+    d->flags  = (param[0].flags & SPAR_DYNAMIC) ? POS_DYNAMIC : 0;
+    d->flags |= POS_MASS;
+    rc = gmx_ana_poscalc_create(&d->pc, d->pcc, d->bPBC ? POS_ALL_PBC : POS_ALL,
+                                d->flags);
+    if (rc != 0)
+    {
+        return rc;
+    }
+    gmx_ana_poscalc_set_maxindex(d->pc, &d->g);
+    return 0;
+}
+
+/*!
+ * \param[in]     top   Topology data structure.
+ * \param[in,out] out   Pointer to output data structure.
+ * \param[in,out] data  Should point to \c t_methoddata_pos.
+ * \returns       0 for success.
+ */
+static int
+init_output_pos(t_topology *top, gmx_ana_selvalue_t *out, void *data)
+{
+    t_methoddata_pos *d = (t_methoddata_pos *)data;
+
+    gmx_ana_poscalc_init_pos(d->pc, out->u.p);
+    gmx_ana_pos_set_evalgrp(out->u.p, &d->g);
+    return 0;
+}
+
+/*!
+ * \param data Data to free (should point to a \c t_methoddata_pos).
+ *
+ * Frees the memory allocated for \c t_methoddata_pos::g and
+ * \c t_methoddata_pos::pc.
+ */
+static void
+free_data_pos(void *data)
+{
+    t_methoddata_pos *d = (t_methoddata_pos *)data;
+
+    sfree(d->type);
+    gmx_ana_poscalc_free(d->pc);
+}
+
+/*!
+ * See sel_updatefunc() for description of the parameters.
+ * \p data should point to a \c t_methoddata_pos.
+ *
+ * Calculates the positions using \c t_methoddata_pos::pc for the index group
+ * in \c t_methoddata_pos::g and stores the results in \p out->u.p.
+ */
+static int
+evaluate_pos(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+             gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
+{
+    t_methoddata_pos *d = (t_methoddata_pos *)data;
+
+    gmx_ana_poscalc_update(d->pc, out->u.p, &d->g, fr, pbc);
+    return 0;
+}
diff --git a/src/gromacs/selection/sm_same.cpp b/src/gromacs/selection/sm_same.cpp
new file mode 100644 (file)
index 0000000..2108f70
--- /dev/null
@@ -0,0 +1,533 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * Implements the \p same selection method.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_selection
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+
+#include <macros.h>
+#include <smalloc.h>
+#include <string2.h>
+
+#include "gromacs/selection/selmethod.h"
+
+#include "keywords.h"
+#include "parsetree.h"
+#include "selelem.h"
+
+/*! \internal \brief
+ * Data structure for the \p same selection method.
+ *
+ * To avoid duplicate initialization code, the same data structure is used
+ * for matching both integer and string keywords; hence the unions.
+ */
+typedef struct
+{
+    /** Value for each atom to match. */
+    union
+    {
+        int                 *i;
+        char               **s;
+        void                *ptr;
+    }                        val;
+    /*! \brief
+     * Number of values in the \p as array.
+     *
+     * For string values, this is actually the number of values in the
+     * \p as_s_sorted array.
+     */
+    int                      nas;
+    /** Values to match against. */
+    union
+    {
+        int                 *i;
+        char               **s;
+        void                *ptr;
+    }                        as;
+    /*! \brief
+     * Separate array for sorted \p as.s array.
+     *
+     * The array of strings returned as the output value of a parameter should
+     * not be messed with to avoid memory corruption (the pointers in the array
+     * may be reused for several evaluations), so we keep our own copy for
+     * modifications.
+     */
+    char                   **as_s_sorted;
+    /** Whether simple matching can be used. */
+    gmx_bool                     bSorted;
+} t_methoddata_same;
+
+/** Allocates data for the \p same selection method. */
+static void *
+init_data_same(int npar, gmx_ana_selparam_t *param);
+/** Initializes the \p same selection method. */
+static int
+init_same(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
+/** Frees the data allocated for the \p same selection method. */
+static void
+free_data_same(void *data);
+/** Initializes the evaluation of the \p same selection method for a frame. */
+static int
+init_frame_same_int(t_topology *top, t_trxframe *fr, t_pbc *pbc, void *data);
+/** Evaluates the \p same selection method. */
+static int
+evaluate_same_int(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+                  gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
+/** Initializes the evaluation of the \p same selection method for a frame. */
+static int
+init_frame_same_str(t_topology *top, t_trxframe *fr, t_pbc *pbc, void *data);
+/** Evaluates the \p same selection method. */
+static int
+evaluate_same_str(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+                 gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
+
+/** Parameters for the \p same selection method. */
+static gmx_ana_selparam_t smparams_same_int[] = {
+    {NULL, {INT_VALUE, -1, {NULL}}, NULL, SPAR_DYNAMIC | SPAR_ATOMVAL},
+    {"as", {INT_VALUE, -1, {NULL}}, NULL, SPAR_DYNAMIC | SPAR_VARNUM},
+};
+
+/** Parameters for the \p same selection method. */
+static gmx_ana_selparam_t smparams_same_str[] = {
+    {NULL, {STR_VALUE, -1, {NULL}}, NULL, SPAR_DYNAMIC | SPAR_ATOMVAL},
+    {"as", {STR_VALUE, -1, {NULL}}, NULL, SPAR_DYNAMIC | SPAR_VARNUM},
+};
+
+/** Help text for the \p same selection method. */
+static const char *help_same[] = {
+    "EXTENDING SELECTIONS[PAR]",
+
+    "[TT]same KEYWORD as ATOM_EXPR[tt][PAR]",
+
+    "The keyword [TT]same[tt] can be used to select all atoms for which",
+    "the given [TT]KEYWORD[tt] matches any of the atoms in [TT]ATOM_EXPR[tt].",
+    "Keywords that evaluate to integer or string values are supported.",
+};
+
+/*! \internal \brief Selection method data for the \p same method. */
+gmx_ana_selmethod_t sm_same = {
+    "same", GROUP_VALUE, 0,
+    asize(smparams_same_int), smparams_same_int,
+    &init_data_same,
+    NULL,
+    &init_same,
+    NULL,
+    &free_data_same,
+    &init_frame_same_int,
+    &evaluate_same_int,
+    NULL,
+    {"same KEYWORD as ATOM_EXPR", asize(help_same), help_same},
+};
+
+/*! \brief
+ * Selection method data for the \p same method.
+ *
+ * This selection method is used for matching string keywords. The parser
+ * never sees this method; _gmx_selelem_custom_init_same() replaces sm_same
+ * with this method in cases where it is required.
+ */
+static gmx_ana_selmethod_t sm_same_str = {
+    "same", GROUP_VALUE, SMETH_SINGLEVAL,
+    asize(smparams_same_str), smparams_same_str,
+    &init_data_same,
+    NULL,
+    &init_same,
+    NULL,
+    &free_data_same,
+    &init_frame_same_str,
+    &evaluate_same_str,
+    NULL,
+    {"same KEYWORD as ATOM_EXPR", asize(help_same), help_same},
+};
+
+/*!
+ * \param[in]     npar  Not used (should be 2).
+ * \param[in,out] param Method parameters (should point to 
+ *   \ref smparams_same).
+ * \returns Pointer to the allocated data (\ref t_methoddata_same).
+ */
+static void *
+init_data_same(int npar, gmx_ana_selparam_t *param)
+{
+    t_methoddata_same *data;
+
+    snew(data, 1);
+    data->as_s_sorted = NULL;
+    param[1].nvalptr = &data->nas;
+    return data;
+}
+
+/*!
+ * \param[in,out] method  The method to initialize.
+ * \param[in,out] params  Pointer to the first parameter.
+ * \param[in]     scanner Scanner data structure.
+ * \returns       0 on success, a non-zero error code on error.
+ *
+ * If \p *method is not a \c same method, this function returns zero
+ * immediately.
+ */
+int
+_gmx_selelem_custom_init_same(gmx_ana_selmethod_t **method,
+                              t_selexpr_param *params,
+                              void *scanner)
+{
+    gmx_ana_selmethod_t *kwmethod;
+    t_selelem           *kwelem;
+    t_selexpr_param     *param;
+    char                *pname;
+    int                  rc;
+
+    /* Do nothing if this is not a same method. */
+    if (!*method || (*method)->name != sm_same.name)
+    {
+        return 0;
+    }
+
+    if (params->nval != 1 || !params->value->bExpr
+        || params->value->u.expr->type != SEL_EXPRESSION)
+    {
+        _gmx_selparser_error(scanner, "'same' should be followed by a single keyword");
+        return -1;
+    }
+    kwmethod = params->value->u.expr->u.expr.method;
+
+    if (kwmethod->type == STR_VALUE)
+    {
+        *method = &sm_same_str;
+    }
+
+    /* We do custom processing with the second parameter, so remove it from
+     * the params list, but save the name for later. */
+    param        = params->next;
+    params->next = NULL;
+    pname        = param->name;
+    param->name  = NULL;
+    /* Create a second keyword evaluation element for the keyword given as
+     * the first parameter, evaluating the keyword in the group given by the
+     * second parameter. */
+    rc = _gmx_sel_init_keyword_evaluator(&kwelem, kwmethod, param, scanner);
+    if (rc != 0)
+    {
+        sfree(pname);
+        return rc;
+    }
+    /* Replace the second parameter with one with a value from \p kwelem. */
+    param        = _gmx_selexpr_create_param(pname);
+    param->nval  = 1;
+    param->value = _gmx_selexpr_create_value_expr(kwelem);
+    params->next = param;
+    return 0;
+}
+
+/*!
+ * \param   top   Not used.
+ * \param   npar  Not used (should be 2).
+ * \param   param Initialized method parameters (should point to a copy of
+ *      \ref smparams_same).
+ * \param   data  Pointer to \ref t_methoddata_same to initialize.
+ * \returns 0 on success, -1 on failure.
+ */
+static int
+init_same(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data)
+{
+    t_methoddata_same *d = (t_methoddata_same *)data;
+
+    d->val.ptr = param[0].val.u.ptr;
+    d->as.ptr  = param[1].val.u.ptr;
+    if (param[1].val.type == STR_VALUE)
+    {
+        snew(d->as_s_sorted, d->nas);
+    }
+    if (!(param[0].flags & SPAR_ATOMVAL))
+    {
+        fprintf(stderr, "ERROR: the same selection keyword combined with a "
+                        "non-keyword does not make sense\n");
+        return -1;
+    }
+    return 0;
+}
+
+/*!
+ * \param data Data to free (should point to a \ref t_methoddata_same).
+ */
+static void
+free_data_same(void *data)
+{
+    t_methoddata_same *d = (t_methoddata_same *)data;
+
+    sfree(d->as_s_sorted);
+}
+
+/*! \brief
+ * Helper function for comparison of two integers.
+ */
+static int
+cmp_int(const void *a, const void *b)
+{
+    if (*(int *)a < *(int *)b)
+    {
+        return -1;
+    }
+    if (*(int *)a > *(int *)b)
+    {
+        return 1;
+    }
+    return 0;
+}
+
+/*!
+ * \param[in]  top  Not used.
+ * \param[in]  fr   Current frame.
+ * \param[in]  pbc  PBC structure.
+ * \param      data Should point to a \ref t_methoddata_same.
+ * \returns    0 on success, a non-zero error code on error.
+ *
+ * Sorts the \c data->as.i array and removes identical values for faster and
+ * simpler lookup.
+ */
+static int
+init_frame_same_int(t_topology *top, t_trxframe *fr, t_pbc *pbc, void *data)
+{
+    t_methoddata_same *d = (t_methoddata_same *)data;
+    int                i, j;
+
+    /* Collapse adjacent values, and check whether the array is sorted. */
+    d->bSorted = TRUE;
+    for (i = 1, j = 0; i < d->nas; ++i)
+    {
+        if (d->as.i[i] != d->as.i[j])
+        {
+            if (d->as.i[i] < d->as.i[j])
+            {
+                d->bSorted = FALSE;
+            }
+            ++j;
+            d->as.i[j] = d->as.i[i];
+        }
+    }
+    d->nas = j + 1;
+
+    if (!d->bSorted)
+    {
+        qsort(d->as.i, d->nas, sizeof(d->as.i[0]), &cmp_int);
+        /* More identical values may become adjacent after sorting. */
+        for (i = 1, j = 0; i < d->nas; ++i)
+        {
+            if (d->as.i[i] != d->as.i[j])
+            {
+                ++j;
+                d->as.i[j] = d->as.i[i];
+            }
+        }
+        d->nas = j + 1;
+    }
+    return 0;
+}
+
+/*!
+ * See sel_updatefunc() for description of the parameters.
+ * \p data should point to a \c t_methoddata_same.
+ *
+ * Calculates which values in \c data->val.i can be found in \c data->as.i
+ * (assumed sorted), and writes the corresponding atoms to output.
+ * If \c data->val is sorted, uses a linear scan of both arrays, otherwise a
+ * binary search of \c data->as is performed for each block of values in
+ * \c data->val.
+ */
+static int
+evaluate_same_int(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+                  gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
+{
+    t_methoddata_same *d = (t_methoddata_same *)data;
+    int                    i, j;
+
+    out->u.g->isize = 0;
+    i = j = 0;
+    while (j < g->isize)
+    {
+        if (d->bSorted)
+        {
+            /* If we are sorted, we can do a simple linear scan. */
+            while (i < d->nas && d->as.i[i] < d->val.i[j]) ++i;
+        }
+        else
+        {
+            /* If not, we must do a binary search of all the values. */
+            int i1, i2;
+
+            i1 = 0;
+            i2 = d->nas;
+            while (i2 - i1 > 1)
+            {
+                int itry = (i1 + i2) / 2;
+                if (d->as.i[itry] <= d->val.i[j])
+                {
+                    i1 = itry;
+                }
+                else
+                {
+                    i2 = itry;
+                }
+            }
+            i = (d->as.i[i1] == d->val.i[j] ? i1 : d->nas);
+        }
+        /* Check whether the value was found in the as list. */
+        if (i == d->nas || d->as.i[i] != d->val.i[j])
+        {
+            /* If not, skip all atoms with the same value. */
+            int tmpval = d->val.i[j];
+            ++j;
+            while (j < g->isize && d->val.i[j] == tmpval) ++j;
+        }
+        else
+        {
+            /* Copy all the atoms with this value to the output. */
+            while (j < g->isize && d->val.i[j] == d->as.i[i])
+            {
+                out->u.g->index[out->u.g->isize++] = g->index[j];
+                ++j;
+            }
+        }
+        if (j < g->isize && d->val.i[j] < d->val.i[j - 1])
+        {
+            d->bSorted = FALSE;
+        }
+    }
+    return 0;
+}
+
+/*! \brief
+ * Helper function for comparison of two strings.
+ */
+static int
+cmp_str(const void *a, const void *b)
+{
+    return strcmp(*(char **)a, *(char **)b);
+}
+
+/*!
+ * \param[in]  top  Not used.
+ * \param[in]  fr   Current frame.
+ * \param[in]  pbc  PBC structure.
+ * \param      data Should point to a \ref t_methoddata_same.
+ * \returns    0 on success, a non-zero error code on error.
+ *
+ * Sorts the \c data->as.s array and removes identical values for faster and
+ * simpler lookup.
+ */
+static int
+init_frame_same_str(t_topology *top, t_trxframe *fr, t_pbc *pbc, void *data)
+{
+    t_methoddata_same *d = (t_methoddata_same *)data;
+    int                i, j;
+
+    /* Collapse adjacent values.
+     * For strings, it's unlikely that the values would be sorted originally,
+     * so set bSorted always to FALSE. */
+    d->bSorted = FALSE;
+    d->as_s_sorted[0] = d->as.s[0];
+    for (i = 1, j = 0; i < d->nas; ++i)
+    {
+        if (strcmp(d->as.s[i], d->as_s_sorted[j]) != 0)
+        {
+            ++j;
+            d->as_s_sorted[j] = d->as.s[i];
+        }
+    }
+    d->nas = j + 1;
+
+    qsort(d->as_s_sorted, d->nas, sizeof(d->as_s_sorted[0]), &cmp_str);
+    /* More identical values may become adjacent after sorting. */
+    for (i = 1, j = 0; i < d->nas; ++i)
+    {
+        if (strcmp(d->as_s_sorted[i], d->as_s_sorted[j]) != 0)
+        {
+            ++j;
+            d->as_s_sorted[j] = d->as_s_sorted[i];
+        }
+    }
+    d->nas = j + 1;
+    return 0;
+}
+
+/*!
+ * See sel_updatefunc() for description of the parameters.
+ * \p data should point to a \c t_methoddata_same.
+ *
+ * Calculates which strings in \c data->val.s can be found in \c data->as.s
+ * (assumed sorted), and writes the corresponding atoms to output.
+ * A binary search of \c data->as is performed for each block of values in
+ * \c data->val.
+ */
+static int
+evaluate_same_str(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+                  gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
+{
+    t_methoddata_same *d = (t_methoddata_same *)data;
+    int                    i, j;
+
+    out->u.g->isize = 0;
+    j = 0;
+    while (j < g->isize)
+    {
+        /* Do a binary search of the strings. */
+        void *ptr;
+        ptr = bsearch(&d->val.s[j], d->as_s_sorted, d->nas,
+                      sizeof(d->as_s_sorted[0]), &cmp_str);
+        /* Check whether the value was found in the as list. */
+        if (ptr == NULL)
+        {
+            /* If not, skip all atoms with the same value. */
+            const char *tmpval = d->val.s[j];
+            ++j;
+            while (j < g->isize && strcmp(d->val.s[j], tmpval) == 0) ++j;
+        }
+        else
+        {
+            const char *tmpval = d->val.s[j];
+            /* Copy all the atoms with this value to the output. */
+            while (j < g->isize && strcmp(d->val.s[j], tmpval) == 0)
+            {
+                out->u.g->index[out->u.g->isize++] = g->index[j];
+                ++j;
+            }
+        }
+    }
+    return 0;
+}
diff --git a/src/gromacs/selection/sm_simple.cpp b/src/gromacs/selection/sm_simple.cpp
new file mode 100644 (file)
index 0000000..79dcec1
--- /dev/null
@@ -0,0 +1,870 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * Implements simple keyword selection methods.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_selection
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "gromacs/selection/position.h"
+#include "gromacs/selection/selmethod.h"
+
+/** Evaluates the \p all selection keyword. */
+static int
+evaluate_all(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+             gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
+/** Evaluates the \p none selection keyword. */
+static int
+evaluate_none(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+              gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
+/** Evaluates the \p atomnr selection keyword. */
+static int
+evaluate_atomnr(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+                gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
+/** Evaluates the \p resnr selection keyword. */
+static int
+evaluate_resnr(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+               gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
+/** Evaluates the \p resindex selection keyword. */
+static int
+evaluate_resindex(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+                  gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
+/** Checks whether molecule information is present in the topology. */
+static int
+check_molecules(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
+/** Evaluates the \p molindex selection keyword. */
+static int
+evaluate_molindex(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+                  gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
+/** Evaluates the \p name selection keyword. */
+static int
+evaluate_atomname(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+                  gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
+/** Checks whether atom types are present in the topology. */
+static int
+check_atomtype(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
+/** Evaluates the \p type selection keyword. */
+static int
+evaluate_atomtype(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+                  gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
+/** Evaluates the \p insertcode selection keyword. */
+static int
+evaluate_insertcode(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+                    gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
+/** Evaluates the \p chain selection keyword. */
+static int
+evaluate_chain(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+               gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
+/** Evaluates the \p mass selection keyword. */
+static int
+evaluate_mass(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+              gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
+/** Evaluates the \p charge selection keyword. */
+static int
+evaluate_charge(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+                gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
+/** Checks whether PDB info is present in the topology. */
+static int
+check_pdbinfo(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
+/** Evaluates the \p altloc selection keyword. */
+static int
+evaluate_altloc(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+                gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
+/** Evaluates the \p occupancy selection keyword. */
+static int
+evaluate_occupancy(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+                   gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
+/** Evaluates the \p betafactor selection keyword. */
+static int
+evaluate_betafactor(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+                    gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
+/** Evaluates the \p resname selection keyword. */
+static int
+evaluate_resname(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+                 gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
+
+/** Evaluates the \p x selection keyword. */
+static int
+evaluate_x(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+           gmx_ana_pos_t *pos, gmx_ana_selvalue_t *out, void *data);
+/** Evaluates the \p y selection keyword. */
+static int
+evaluate_y(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+           gmx_ana_pos_t *pos, gmx_ana_selvalue_t *out, void *data);
+/** Evaluates the \p z selection keyword. */
+static int
+evaluate_z(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+           gmx_ana_pos_t *pos, gmx_ana_selvalue_t *out, void *data);
+
+/** \internal Selection method data for \p all selection keyword. */
+gmx_ana_selmethod_t sm_all = {
+    "all", GROUP_VALUE, 0,
+    0, NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    &evaluate_all,
+    NULL,
+};
+
+/** \internal Selection method data for \p none selection keyword. */
+gmx_ana_selmethod_t sm_none = {
+    "none", GROUP_VALUE, 0,
+    0, NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    &evaluate_none,
+    NULL,
+};
+
+/** \internal Selection method data for \p atomnr selection keyword. */
+gmx_ana_selmethod_t sm_atomnr = {
+    "atomnr", INT_VALUE, 0,
+    0, NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    &evaluate_atomnr,
+    NULL,
+};
+
+/** \internal Selection method data for \p resnr selection keyword. */
+gmx_ana_selmethod_t sm_resnr = {
+    "resnr", INT_VALUE, SMETH_REQTOP,
+    0, NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    &evaluate_resnr,
+    NULL,
+};
+
+/** \internal Selection method data for \p resindex selection keyword. */
+gmx_ana_selmethod_t sm_resindex = {
+    "resindex", INT_VALUE, SMETH_REQTOP,
+    0, NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    &evaluate_resindex,
+    NULL,
+};
+
+/** \internal Selection method data for \p molindex selection keyword. */
+gmx_ana_selmethod_t sm_molindex = {
+    "molindex", INT_VALUE, SMETH_REQTOP,
+    0, NULL,
+    NULL,
+    NULL,
+    &check_molecules,
+    NULL,
+    NULL,
+    NULL,
+    &evaluate_molindex,
+    NULL,
+};
+
+/** \internal Selection method data for \p name selection keyword. */
+gmx_ana_selmethod_t sm_atomname = {
+    "name", STR_VALUE, SMETH_REQTOP,
+    0, NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    &evaluate_atomname,
+    NULL,
+};
+
+/** \internal Selection method data for \p type selection keyword. */
+gmx_ana_selmethod_t sm_atomtype = {
+    "type", STR_VALUE, SMETH_REQTOP,
+    0, NULL,
+    NULL,
+    NULL,
+    &check_atomtype,
+    NULL,
+    NULL,
+    NULL,
+    &evaluate_atomtype,
+    NULL,
+};
+
+/** \internal Selection method data for \p resname selection keyword. */
+gmx_ana_selmethod_t sm_resname = {
+    "resname", STR_VALUE, SMETH_REQTOP,
+    0, NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    &evaluate_resname,
+    NULL,
+};
+
+/** \internal Selection method data for \p chain selection keyword. */
+gmx_ana_selmethod_t sm_insertcode = {
+    "insertcode", STR_VALUE, SMETH_REQTOP | SMETH_CHARVAL,
+    0, NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    &evaluate_insertcode,
+    NULL,
+};
+
+/** \internal Selection method data for \p chain selection keyword. */
+gmx_ana_selmethod_t sm_chain = {
+    "chain", STR_VALUE, SMETH_REQTOP | SMETH_CHARVAL,
+    0, NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    &evaluate_chain,
+    NULL,
+};
+
+/** \internal Selection method data for \p mass selection keyword. */
+gmx_ana_selmethod_t sm_mass = {
+    "mass", REAL_VALUE, SMETH_REQTOP,
+    0, NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    &evaluate_mass,
+    NULL,
+};
+
+/** \internal Selection method data for \p charge selection keyword. */
+gmx_ana_selmethod_t sm_charge = {
+    "charge", REAL_VALUE, SMETH_REQTOP,
+    0, NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    &evaluate_charge,
+    NULL,
+};
+
+/** \internal Selection method data for \p chain selection keyword. */
+gmx_ana_selmethod_t sm_altloc = {
+    "altloc", STR_VALUE, SMETH_REQTOP | SMETH_CHARVAL,
+    0, NULL,
+    NULL,
+    NULL,
+    &check_pdbinfo,
+    NULL,
+    NULL,
+    NULL,
+    &evaluate_altloc,
+    NULL,
+};
+
+/** \internal Selection method data for \p occupancy selection keyword. */
+gmx_ana_selmethod_t sm_occupancy = {
+    "occupancy", REAL_VALUE, SMETH_REQTOP,
+    0, NULL,
+    NULL,
+    NULL,
+    &check_pdbinfo,
+    NULL,
+    NULL,
+    NULL,
+    &evaluate_occupancy,
+    NULL,
+};
+
+/** \internal Selection method data for \p betafactor selection keyword. */
+gmx_ana_selmethod_t sm_betafactor = {
+    "betafactor", REAL_VALUE, SMETH_REQTOP,
+    0, NULL,
+    NULL,
+    NULL,
+    &check_pdbinfo,
+    NULL,
+    NULL,
+    NULL,
+    &evaluate_betafactor,
+    NULL,
+};
+
+/** \internal Selection method data for \p x selection keyword. */
+gmx_ana_selmethod_t sm_x = {
+    "x", REAL_VALUE, SMETH_DYNAMIC,
+    0, NULL,
+     NULL,
+     NULL,
+     NULL,
+     NULL,
+     NULL,
+     NULL,
+     NULL,
+    &evaluate_x,
+};
+
+/** \internal Selection method data for \p y selection keyword. */
+gmx_ana_selmethod_t sm_y = {
+    "y", REAL_VALUE, SMETH_DYNAMIC,
+    0, NULL,
+     NULL,
+     NULL,
+     NULL,
+     NULL,
+     NULL,
+     NULL,
+     NULL,
+    &evaluate_y,
+};
+
+/** \internal Selection method data for \p z selection keyword. */
+gmx_ana_selmethod_t sm_z = {
+    "z", REAL_VALUE, SMETH_DYNAMIC,
+    0, NULL,
+     NULL,
+     NULL,
+     NULL,
+     NULL,
+     NULL,
+     NULL,
+     NULL,
+    &evaluate_z,
+};
+
+/*!
+ * See sel_updatefunc() for description of the parameters.
+ * \p data is not used.
+ *
+ * Copies \p g to \p out->u.g.
+ */
+static int
+evaluate_all(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+             gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
+{
+    gmx_ana_index_copy(out->u.g, g, FALSE);
+    return 0;
+}
+
+/*!
+ * See sel_updatefunc() for description of the parameters.
+ * \p data is not used.
+ *
+ * Returns an empty \p out->u.g.
+ */
+static int
+evaluate_none(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+              gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
+{
+    out->u.g->isize = 0;
+    return 0;
+}
+
+/*!
+ * See sel_updatefunc() for description of the parameters.
+ * \p data is not used.
+ *
+ * Returns the indices for each atom in \p out->u.i.
+ */
+static int
+evaluate_atomnr(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+                gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
+{
+    int  i;
+
+    out->nr = g->isize;
+    for (i = 0; i < g->isize; ++i)
+    {
+        out->u.i[i] = g->index[i] + 1;
+    }
+    return 0;
+}
+
+/*!
+ * See sel_updatefunc() for description of the parameters.
+ * \p data is not used.
+ *
+ * Returns the residue numbers for each atom in \p out->u.i.
+ */
+static int
+evaluate_resnr(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+               gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
+{
+    int  i;
+    int  resind;
+
+    out->nr = g->isize;
+    for (i = 0; i < g->isize; ++i)
+    {
+        resind = top->atoms.atom[g->index[i]].resind;
+        out->u.i[i] = top->atoms.resinfo[resind].nr;
+    }
+    return 0;
+}
+
+/*!
+ * See sel_updatefunc() for description of the parameters.
+ * \p data is not used.
+ *
+ * Returns the residue indices for each atom in \p out->u.i.
+ */
+static int
+evaluate_resindex(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+                  gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
+{
+    int  i;
+
+    out->nr = g->isize;
+    for (i = 0; i < g->isize; ++i)
+    {
+        out->u.i[i] = top->atoms.atom[g->index[i]].resind + 1;
+    }
+    return 0;
+}
+
+/*!
+ * \param[in] top  Topology structure.
+ * \param     npar Not used.
+ * \param     param Not used.
+ * \param     data Not used.
+ * \returns   0 if molecule info is present in the topology, -1 otherwise.
+ *
+ * If molecule information is not found, also prints an error message.
+ */
+static int
+check_molecules(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data)
+{
+    gmx_bool bOk;
+
+    bOk = (top != NULL && top->mols.nr > 0);
+    if (!bOk)
+    {
+        fprintf(stderr, "Molecule information not available in topology!\n");
+        return -1;
+    }
+    return 0;
+}
+
+/*!
+ * See sel_updatefunc() for description of the parameters.
+ * \p data is not used.
+ *
+ * Returns the molecule indices for each atom in \p out->u.i.
+ */
+static int
+evaluate_molindex(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+                  gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
+{
+    int  i, j;
+
+    out->nr = g->isize;
+    for (i = j = 0; i < g->isize; ++i)
+    {
+        while (top->mols.index[j + 1] <= g->index[i]) ++j;
+        out->u.i[i] = j + 1;
+    }
+    return 0;
+}
+
+/*!
+ * See sel_updatefunc() for description of the parameters.
+ * \p data is not used.
+ *
+ * Returns the atom name for each atom in \p out->u.s.
+ */
+static int
+evaluate_atomname(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+                  gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
+{
+    int  i;
+
+    out->nr = g->isize;
+    for (i = 0; i < g->isize; ++i)
+    {
+        out->u.s[i] = *top->atoms.atomname[g->index[i]];
+    }
+    return 0;
+}
+
+/*!
+ * \param[in] top  Topology structure.
+ * \param     npar Not used.
+ * \param     param Not used.
+ * \param     data Not used.
+ * \returns   0 if atom types are present in the topology, -1 otherwise.
+ *
+ * If the atom types are not found, also prints an error message.
+ */
+static int
+check_atomtype(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data)
+{
+    gmx_bool bOk;
+
+    bOk = (top != NULL && top->atoms.atomtype != NULL);
+    if (!bOk)
+    {
+        fprintf(stderr, "Atom types not available in topology!\n");
+        return -1;
+    }
+    return 0;
+}
+
+/*!
+ * See sel_updatefunc() for description of the parameters.
+ * \p data is not used.
+ *
+ * Returns the atom type for each atom in \p out->u.s.
+ * Segfaults if atom types are not found in the topology.
+ */
+static int
+evaluate_atomtype(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+                  gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
+{
+    int  i;
+
+    out->nr = g->isize;
+    for (i = 0; i < g->isize; ++i)
+    {
+        out->u.s[i] = *top->atoms.atomtype[g->index[i]];
+    }
+    return 0;
+}
+
+/*!
+ * See sel_updatefunc() for description of the parameters.
+ * \p data is not used.
+ *
+ * Returns the residue name for each atom in \p out->u.s.
+ */
+static int
+evaluate_resname(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+                 gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
+{
+    int  i;
+    int  resind;
+
+    out->nr = g->isize;
+    for (i = 0; i < g->isize; ++i)
+    {
+        resind = top->atoms.atom[g->index[i]].resind;
+        out->u.s[i] = *top->atoms.resinfo[resind].name;
+    }
+    return 0;
+}
+
+/*!
+ * See sel_updatefunc() for description of the parameters.
+ * \p data is not used.
+ *
+ * Returns the insertion code for each atom in \p out->u.s.
+ */
+static int
+evaluate_insertcode(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+                    gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
+{
+    int  i;
+    int  resind;
+
+    out->nr = g->isize;
+    for (i = 0; i < g->isize; ++i)
+    {
+        resind = top->atoms.atom[g->index[i]].resind;
+        out->u.s[i][0] = top->atoms.resinfo[resind].ic;
+    }
+    return 0;
+}
+
+/*!
+ * See sel_updatefunc() for description of the parameters.
+ * \p data is not used.
+ *
+ * Returns the chain for each atom in \p out->u.s.
+ */
+static int
+evaluate_chain(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+               gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
+{
+    int  i;
+    int  resind;
+
+    out->nr = g->isize;
+    for (i = 0; i < g->isize; ++i)
+    {
+        resind = top->atoms.atom[g->index[i]].resind;
+        out->u.s[i][0] = top->atoms.resinfo[resind].chainid;
+    }
+    return 0;
+}
+
+/*!
+ * See sel_updatefunc() for description of the parameters.
+ * \p data is not used.
+ *
+ * Returns the mass for each atom in \p out->u.r.
+ */
+static int
+evaluate_mass(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+              gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
+{
+    int  i;
+
+    out->nr = g->isize;
+    for (i = 0; i < g->isize; ++i)
+    {
+        out->u.r[i] = top->atoms.atom[g->index[i]].m;
+    }
+    return 0;
+}
+
+/*!
+ * See sel_updatefunc() for description of the parameters.
+ * \p data is not used.
+ *
+ * Returns the charge for each atom in \p out->u.r.
+ */
+static int
+evaluate_charge(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+                gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
+{
+    int  i;
+
+    out->nr = g->isize;
+    for (i = 0; i < g->isize; ++i)
+    {
+        out->u.r[i] = top->atoms.atom[g->index[i]].q;
+    }
+    return 0;
+}
+
+/*!
+ * \param[in] top  Topology structure.
+ * \param     npar Not used.
+ * \param     param Not used.
+ * \param     data Not used.
+ * \returns   0 if PDB info is present in the topology, -1 otherwise.
+ *
+ * If PDB info is not found, also prints an error message.
+ */
+static int
+check_pdbinfo(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data)
+{
+    gmx_bool bOk;
+
+    bOk = (top != NULL && top->atoms.pdbinfo != NULL);
+    if (!bOk)
+    {
+        fprintf(stderr, "PDB info not available in topology!\n");
+        return -1;
+    }
+    return 0;
+}
+
+/*!
+ * See sel_updatefunc() for description of the parameters.
+ * \p data is not used.
+ *
+ * Returns the alternate location identifier for each atom in \p out->u.s.
+ */
+static int
+evaluate_altloc(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+                gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
+{
+    int  i;
+
+    out->nr = g->isize;
+    for (i = 0; i < g->isize; ++i)
+    {
+        out->u.s[i][0] = top->atoms.pdbinfo[g->index[i]].altloc;
+    }
+    return 0;
+}
+
+/*!
+ * See sel_updatefunc() for description of the parameters.
+ * \p data is not used.
+ *
+ * Returns the occupancy numbers for each atom in \p out->u.r.
+ * Segfaults if PDB info is not found in the topology.
+ */
+static int
+evaluate_occupancy(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+                   gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
+{
+    int  i;
+
+    out->nr = g->isize;
+    for (i = 0; i < g->isize; ++i)
+    {
+        out->u.r[i] = top->atoms.pdbinfo[g->index[i]].occup;
+    }
+    return 0;
+}
+
+/*!
+ * See sel_updatefunc() for description of the parameters.
+ * \p data is not used.
+ *
+ * Returns the B-factors for each atom in \p out->u.r.
+ * Segfaults if PDB info is not found in the topology.
+ */
+static int
+evaluate_betafactor(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+                    gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
+{
+    int  i;
+
+    out->nr = g->isize;
+    for (i = 0; i < g->isize; ++i)
+    {
+        out->u.r[i] = top->atoms.pdbinfo[g->index[i]].bfac;
+    }
+    return 0;
+}
+
+/*! \brief
+ * Internal utility function for position keyword evaluation.
+ *
+ * \param[in]  fr   Current frame.
+ * \param[in]  g    Index group for which the coordinates should be evaluated.
+ * \param[out] out  Output array.
+ * \param[in]  pos  Position data to use instead of atomic coordinates
+ *   (can be NULL).
+ * \param[in]  d    Coordinate index to evaluate (\p XX, \p YY or \p ZZ).
+ *
+ * This function is used internally by evaluate_x(), evaluate_y() and
+ * evaluate_z() to do the actual evaluation.
+ */
+static void
+evaluate_coord(t_trxframe *fr, gmx_ana_index_t *g, real out[],
+               gmx_ana_pos_t *pos, int d)
+{
+    int  b, i;
+    real v;
+
+    if (pos)
+    {
+        for (b = 0; b < pos->nr; ++b)
+        {
+            v = pos->x[b][d];
+            for (i = pos->m.mapb.index[b]; i < pos->m.mapb.index[b+1]; ++i)
+            {
+                out[i] = v;
+            }
+        }
+    }
+    else
+    {
+        for (i = 0; i < g->isize; ++i)
+        {
+            out[i] = fr->x[g->index[i]][d];
+        }
+    }
+}
+
+/*!
+ * See sel_updatefunc_pos() for description of the parameters.
+ * \p data is not used.
+ *
+ * Returns the \p x coordinate for each atom in \p out->u.r.
+ */
+static int
+evaluate_x(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+           gmx_ana_pos_t *pos, gmx_ana_selvalue_t *out, void *data)
+{
+    out->nr = pos->g->isize;
+    evaluate_coord(fr, pos->g, out->u.r, pos, XX);
+    return 0;
+}
+
+/*!
+ * See sel_updatefunc() for description of the parameters.
+ * \p data is not used.
+ *
+ * Returns the \p y coordinate for each atom in \p out->u.r.
+ */
+static int
+evaluate_y(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+           gmx_ana_pos_t *pos, gmx_ana_selvalue_t *out, void *data)
+{
+    out->nr = pos->g->isize;
+    evaluate_coord(fr, pos->g, out->u.r, pos, YY);
+    return 0;
+}
+
+/*!
+ * See sel_updatefunc() for description of the parameters.
+ * \p data is not used.
+ *
+ * Returns the \p z coordinate for each atom in \p out->u.r.
+ */
+static int
+evaluate_z(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+           gmx_ana_pos_t *pos, gmx_ana_selvalue_t *out, void *data)
+{
+    out->nr = pos->g->isize;
+    evaluate_coord(fr, pos->g, out->u.r, pos, ZZ);
+    return 0;
+}
diff --git a/src/gromacs/selection/symrec.cpp b/src/gromacs/selection/symrec.cpp
new file mode 100644 (file)
index 0000000..a2376bf
--- /dev/null
@@ -0,0 +1,511 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * Implements functions in symrec.h.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_selection
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <macros.h>
+#include <smalloc.h>
+#include <string2.h>
+#include <typedefs.h>
+#include <gmx_fatal.h>
+
+#include "gromacs/selection/poscalc.h"
+
+#include "selelem.h"
+#include "symrec.h"
+
+/*! \internal \brief
+ * Symbol table for the selection parser.
+ */
+struct gmx_sel_symtab_t
+{
+    /** Pointer to the first symbol in the linked list of symbols. */
+    gmx_sel_symrec_t *first;
+};
+
+/*! \internal \brief
+ * Single symbol for the selection parser.
+ */
+struct gmx_sel_symrec_t
+{
+    /** Name of the symbol. */
+    char                           *name;
+    /** Type of the symbol. */
+    e_symbol_t                      type;
+    /** Value of the symbol. */
+    union {
+        /** Pointer to the method structure (\ref SYMBOL_METHOD). */
+        struct gmx_ana_selmethod_t *meth;
+        /** Pointer to the variable value (\ref SYMBOL_VARIABLE). */
+        struct t_selelem           *var;
+    }                               u;
+    /** Pointer to the next symbol. */
+    struct gmx_sel_symrec_t        *next;
+};
+
+/** List of reserved symbols to register in add_reserved_symbols(). */
+static const char *const sym_reserved[] = {
+    "group",
+    "to",
+    "not",
+    "and",
+    "or",
+    "xor",
+    "yes",
+    "no",
+    "on",
+    "off",
+    "help",
+};
+
+/*!
+ * \param[in] sym Symbol to query.
+ * \returns   The name of \p sym.
+ *
+ * The returned pointer should not be free'd.
+ */
+char *
+_gmx_sel_sym_name(gmx_sel_symrec_t *sym)
+{
+    return sym->name;
+}
+
+/*!
+ * \param[in] sym Symbol to query.
+ * \returns   The type of \p sym.
+ */
+e_symbol_t
+_gmx_sel_sym_type(gmx_sel_symrec_t *sym)
+{
+    return sym->type;
+}
+
+/*!
+ * \param[in] sym Symbol to query.
+ * \returns   The method associated with \p sym, or NULL if \p sym is not a
+ *   \ref SYMBOL_METHOD symbol.
+ */
+struct gmx_ana_selmethod_t *
+_gmx_sel_sym_value_method(gmx_sel_symrec_t *sym)
+{
+    if (sym->type != SYMBOL_METHOD)
+    {
+        gmx_call("symbol is not a method symbol");
+        return NULL;
+    }
+    return sym->u.meth;
+}
+
+/*!
+ * \param[in] sym Symbol to query.
+ * \returns   The variable expression associated with \p sym, or NULL if
+ *   \p sym is not a \ref SYMBOL_VARIABLE symbol.
+ */
+struct t_selelem *
+_gmx_sel_sym_value_var(gmx_sel_symrec_t *sym)
+{
+    if (sym->type != SYMBOL_VARIABLE)
+    {
+        gmx_call("symbol is not a variable symbol");
+        return NULL;
+    }
+    return sym->u.var;
+}
+
+/*! \brief
+ * Adds the reserved symbols to a symbol table.
+ * 
+ * \param[in,out] tab  Symbol table to which the symbols are added.
+ *
+ * Assumes that the symbol table is empty.
+ */
+static void
+add_reserved_symbols(gmx_sel_symtab_t *tab)
+{
+    gmx_sel_symrec_t *sym;
+    gmx_sel_symrec_t *last;
+    size_t            i;
+
+    last = NULL;
+    for (i = 0; i < asize(sym_reserved); ++i)
+    {
+        snew(sym, 1);
+        sym->name = strdup(sym_reserved[i]);
+        sym->type = SYMBOL_RESERVED;
+        sym->next = NULL;
+        if (last)
+        {
+            last->next = sym;
+        }
+        else
+        {
+            tab->first = sym;
+        }
+        last = sym;
+    }
+}
+
+/*! \brief
+ * Adds the position symbols to the symbol list.
+ * 
+ * \param[in,out] tab  Symbol table to which the symbols are added.
+ */
+static void
+add_position_symbols(gmx_sel_symtab_t *tab)
+{
+    const char       **postypes;
+    gmx_sel_symrec_t  *sym;
+    gmx_sel_symrec_t  *last;
+    int                i;
+
+    postypes = gmx_ana_poscalc_create_type_enum(TRUE);
+    last = tab->first;
+    while (last && last->next)
+    {
+        last = last->next;
+    }
+    for (i = 1; postypes[i] != NULL; ++i)
+    {
+        snew(sym, 1);
+        sym->name = strdup(postypes[i]);
+        sym->type = SYMBOL_POS;
+        sym->next = NULL;
+        if (last)
+        {
+            last->next = sym;
+        }
+        else
+        {
+            tab->first = sym;
+        }
+        last = sym;
+    }
+    sfree(postypes);
+}
+
+/*!
+ * \param[out] tabp Symbol table pointer to initialize.
+ *
+ * Reserved and position symbols are added to the created table.
+ */
+int
+_gmx_sel_symtab_create(gmx_sel_symtab_t **tabp)
+{
+    gmx_sel_symtab_t *tab;
+
+    snew(tab, 1);
+    add_reserved_symbols(tab);
+    add_position_symbols(tab);
+    *tabp = tab;
+    return 0;
+}
+
+/*!
+ * \param[in] tab Symbol table to free.
+ *
+ * The pointer \p tab is invalid after the call.
+ */
+void
+_gmx_sel_symtab_free(gmx_sel_symtab_t *tab)
+{
+    gmx_sel_symrec_t *sym;
+
+    while (tab->first)
+    {
+        sym = tab->first;
+        tab->first = sym->next;
+        if (sym->type == SYMBOL_VARIABLE)
+        {
+            _gmx_selelem_free(sym->u.var);
+        }
+        sfree(sym->name);
+        sfree(sym);
+    }
+    sfree(tab);
+}
+
+/*!
+ * \param[in] tab    Symbol table to search.
+ * \param[in] name   Symbol name to find.
+ * \param[in] bExact If FALSE, symbols that begin with \p name are also
+ *   considered.
+ * \returns   Pointer to the symbol with name \p name, or NULL if not found.
+ *
+ * If no exact match is found and \p bExact is FALSE, returns a symbol that
+ * begins with \p name if a unique matching symbol is found.
+ */
+gmx_sel_symrec_t *
+_gmx_sel_find_symbol(gmx_sel_symtab_t *tab, const char *name, gmx_bool bExact)
+{
+    return _gmx_sel_find_symbol_len(tab, name, strlen(name), bExact);
+}
+
+/*!
+ * \param[in] tab    Symbol table to search.
+ * \param[in] name   Symbol name to find.
+ * \param[in] len    Only consider the first \p len characters of \p name.
+ * \param[in] bExact If FALSE, symbols that begin with \p name are also
+ *   considered.
+ * \returns   Pointer to the symbol with name \p name, or NULL if not found.
+ *
+ * If no exact match is found and \p bExact is FALSE, returns a symbol that
+ * begins with \p name if a unique matching symbol is found.
+ *
+ * The parameter \p len is there to allow using this function from scanner.l
+ * without modifying the text to be scanned or copying it.
+ */
+gmx_sel_symrec_t *
+_gmx_sel_find_symbol_len(gmx_sel_symtab_t *tab, const char *name, size_t len,
+                         gmx_bool bExact)
+{
+    gmx_sel_symrec_t *sym;
+    gmx_sel_symrec_t *match;
+    gmx_bool              bUnique;
+    gmx_bool              bMatch;
+
+    match = NULL;
+    bUnique = TRUE;
+    bMatch  = FALSE;
+    sym = tab->first;
+    while (sym)
+    {
+        if (!strncmp(sym->name, name, len))
+        {
+            if (strlen(sym->name) == len)
+            {
+                return sym;
+            }
+            if (bMatch)
+            {
+                bUnique = FALSE;
+            }
+            bMatch = TRUE;
+            if (sym->type == SYMBOL_METHOD)
+            {
+                match = sym;
+            }
+        }
+        sym = sym->next;
+    }
+    if (bExact)
+    {
+        return NULL;
+    }
+
+    if (!bUnique)
+    {
+        fprintf(stderr, "parse error: ambiguous symbol\n");
+        return NULL;
+    }
+    return match;
+}
+
+/*!
+ * \param[in] tab   Symbol table to search.
+ * \param[in] type  Type of symbol to find.
+ * \returns   The first symbol in \p tab with type \p type,
+ *   or NULL if there are no such symbols.
+ */
+gmx_sel_symrec_t *
+_gmx_sel_first_symbol(gmx_sel_symtab_t *tab, e_symbol_t type)
+{
+    gmx_sel_symrec_t *sym;
+
+    sym = tab->first;
+    while (sym)
+    {
+        if (sym->type == type)
+        {
+            return sym;
+        }
+        sym = sym->next;
+    }
+    return NULL;
+}
+
+/*!
+ * \param[in] after Start the search after this symbol.
+ * \param[in] type  Type of symbol to find.
+ * \returns   The next symbol after \p after with type \p type,
+ *   or NULL if there are no more symbols.
+ */
+gmx_sel_symrec_t *
+_gmx_sel_next_symbol(gmx_sel_symrec_t *after, e_symbol_t type)
+{
+    gmx_sel_symrec_t *sym;
+
+    sym = after->next;
+    while (sym)
+    {
+        if (sym->type == type)
+        {
+            return sym;
+        }
+        sym = sym->next;
+    }
+    return NULL;
+}
+
+/*! \brief
+ * Internal utility function used in adding symbols to a symbol table.
+ *
+ * \param[in,out] tab   Symbol table to add the symbol to.
+ * \param[in]     name  Name of the symbol to add.
+ * \param[out]    ctype On error, the type of the conflicting symbol is
+ *   written to \p *ctype.
+ * \returns       Pointer to the new symbol record, or NULL if \p name
+ *   conflicts with an existing symbol.
+ */
+static gmx_sel_symrec_t *
+add_symbol(gmx_sel_symtab_t *tab, const char *name, e_symbol_t *ctype)
+{
+    gmx_sel_symrec_t *sym, *psym;
+    int               len;
+
+    /* Check if there is a conflicting symbol */
+    psym = NULL;
+    sym  = tab->first;
+    while (sym)
+    {
+        if (!gmx_strcasecmp(sym->name, name))
+        {
+            *ctype = sym->type;
+            return NULL;
+        }
+        psym = sym;
+        sym  = sym->next;
+    }
+
+    /* Create a new symbol record */
+    if (psym == NULL)
+    {
+        snew(tab->first, 1);
+        sym = tab->first;
+    }
+    else
+    {
+        snew(psym->next, 1);
+        sym = psym->next;
+    }
+    sym->name = strdup(name);
+    return sym;
+}
+
+/*!
+ * \param[in,out] tab    Symbol table to add the symbol to.
+ * \param[in]     name   Name of the new symbol.
+ * \param[in]     sel    Value of the variable.
+ * \returns       Pointer to the created symbol record, or NULL if there was a
+ *   symbol with the same name.
+ */
+gmx_sel_symrec_t *
+_gmx_sel_add_var_symbol(gmx_sel_symtab_t *tab, const char *name,
+                        struct t_selelem *sel)
+{
+    gmx_sel_symrec_t *sym;
+    e_symbol_t        ctype;
+
+    sym = add_symbol(tab, name, &ctype);
+    if (!sym)
+    {
+        fprintf(stderr, "parse error: ");
+        switch (ctype)
+        {
+            case SYMBOL_RESERVED:
+            case SYMBOL_POS:
+                fprintf(stderr, "variable name (%s) conflicts with a reserved keyword\n",
+                        name);
+                break;
+            case SYMBOL_VARIABLE:
+                fprintf(stderr, "duplicate variable name (%s)\n", name);
+                break;
+            case SYMBOL_METHOD:
+                fprintf(stderr, "variable name (%s) conflicts with a selection keyword\n",
+                        name);
+                break;
+        }
+        return NULL;
+    }
+
+    sym->type  = SYMBOL_VARIABLE;
+    sym->u.var = sel;
+    sel->refcount++;
+    return sym;
+}
+
+/*!
+ * \param[in,out] tab    Symbol table to add the symbol to.
+ * \param[in]     name   Name of the new symbol.
+ * \param[in]     method Method that this symbol represents.
+ * \returns       Pointer to the created symbol record, or NULL if there was a
+ *   symbol with the same name.
+ */
+gmx_sel_symrec_t *
+_gmx_sel_add_method_symbol(gmx_sel_symtab_t *tab, const char *name,
+                           struct gmx_ana_selmethod_t *method)
+{
+    gmx_sel_symrec_t *sym;
+    e_symbol_t        ctype;
+
+    sym = add_symbol(tab, name, &ctype);
+    if (!sym)
+    {
+        fprintf(stderr, "parse error: ");
+        switch (ctype)
+        {
+            case SYMBOL_RESERVED:
+            case SYMBOL_POS:
+                fprintf(stderr, "method name (%s) conflicts with a reserved keyword\n",
+                        name);
+                break;
+            case SYMBOL_VARIABLE:
+                fprintf(stderr, "method name (%s) conflicts with a variable name\n",
+                        name);
+                break;
+            case SYMBOL_METHOD:
+                fprintf(stderr, "duplicate method name (%s)\n", name);
+                break;
+        }
+        return NULL;
+    }
+
+    sym->type   = SYMBOL_METHOD;
+    sym->u.meth = method;
+    return sym;
+}
diff --git a/src/gromacs/selection/symrec.h b/src/gromacs/selection/symrec.h
new file mode 100644 (file)
index 0000000..bab9483
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief Handling of selection parser symbol table.
+ *
+ * This is an implementation header: there should be no need to use it outside
+ * this directory.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_selection
+ */
+#ifndef SELECTION_SYMREC_H
+#define SELECTION_SYMREC_H
+
+struct t_selelem;
+struct gmx_ana_selmethod_t;
+
+/** Defines the type of the symbol. */
+typedef enum
+{
+    SYMBOL_RESERVED,    /**< The symbol is a reserved keyword. */
+    SYMBOL_VARIABLE,    /**< The symbol is a variable. */
+    SYMBOL_METHOD,      /**< The symbol is a selection method. */
+    SYMBOL_POS          /**< The symbol is a position keyword. */
+} e_symbol_t;
+
+/** Symbol table for the selection parser. */
+typedef struct gmx_sel_symtab_t gmx_sel_symtab_t;
+/** Single symbol for the selection parser. */
+typedef struct gmx_sel_symrec_t gmx_sel_symrec_t;
+
+/** Returns the name of a symbol. */
+char *
+_gmx_sel_sym_name(gmx_sel_symrec_t *sym);
+/** Returns the type of a symbol. */
+e_symbol_t
+_gmx_sel_sym_type(gmx_sel_symrec_t *sym);
+/** Returns the method associated with a \ref SYMBOL_METHOD symbol. */
+struct gmx_ana_selmethod_t *
+_gmx_sel_sym_value_method(gmx_sel_symrec_t *sym);
+/** Returns the method associated with a \ref SYMBOL_VARIABLE symbol. */
+struct t_selelem *
+_gmx_sel_sym_value_var(gmx_sel_symrec_t *sym);
+
+/** Creates a new symbol table. */
+int
+_gmx_sel_symtab_create(gmx_sel_symtab_t **tabp);
+/** Frees all memory allocated for a symbol table. */
+void
+_gmx_sel_symtab_free(gmx_sel_symtab_t *tab);
+/** Finds a symbol by name. */
+gmx_sel_symrec_t *
+_gmx_sel_find_symbol(gmx_sel_symtab_t *tab, const char *name, gmx_bool bExact);
+/** Finds a symbol by name. */
+gmx_sel_symrec_t *
+_gmx_sel_find_symbol_len(gmx_sel_symtab_t *tab, const char *name, size_t len,
+                         gmx_bool bExact);
+/** Returns the first symbol of a given type. */
+gmx_sel_symrec_t *
+_gmx_sel_first_symbol(gmx_sel_symtab_t *tab, e_symbol_t type);
+/** Returns the next symbol of a given type. */
+gmx_sel_symrec_t *
+_gmx_sel_next_symbol(gmx_sel_symrec_t *after, e_symbol_t type);
+/** Adds a new variable symbol. */
+gmx_sel_symrec_t *
+_gmx_sel_add_var_symbol(gmx_sel_symtab_t *tab, const char *name,
+                        struct t_selelem *sel);
+/** Adds a new method symbol. */
+gmx_sel_symrec_t *
+_gmx_sel_add_method_symbol(gmx_sel_symtab_t *tab, const char *name,
+                           struct gmx_ana_selmethod_t *method);
+
+#endif
diff --git a/src/gromacs/selection/tests/CMakeLists.txt b/src/gromacs/selection/tests/CMakeLists.txt
new file mode 100644 (file)
index 0000000..6b02bba
--- /dev/null
@@ -0,0 +1,8 @@
+IF (GTEST_FOUND)
+    include_directories(${GTEST_INCLUDE_DIRS})
+    add_executable(selection-test
+                   selectioncollection.cpp selectionoption.cpp
+                   test_main.cpp)
+    target_link_libraries(selection-test libgromacs ${GTEST_LIBRARIES})
+    add_test(SelectionUnitTests selection-test)
+ENDIF (GTEST_FOUND)
diff --git a/src/gromacs/selection/tests/selectioncollection.cpp b/src/gromacs/selection/tests/selectioncollection.cpp
new file mode 100644 (file)
index 0000000..90e2ba1
--- /dev/null
@@ -0,0 +1,344 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * Tests selection parsing and compilation.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_selection
+ */
+#include <vector>
+
+#include <gtest/gtest.h>
+
+#include "smalloc.h"
+#include "statutil.h"
+#include "tpxio.h"
+#include "vec.h"
+
+#include "gromacs/errorreporting/emptyerrorreporter.h"
+#include "gromacs/selection/poscalc.h"
+#include "gromacs/selection/selectioncollection.h"
+#include "gromacs/selection/selection.h"
+
+namespace
+{
+
+/********************************************************************
+ * Test fixture for selection testing
+ */
+
+class SelectionCollectionTest : public ::testing::Test
+{
+    public:
+        SelectionCollectionTest();
+        ~SelectionCollectionTest();
+
+        void setAtomCount(int natoms)
+        {
+            _sc.setTopology(NULL, natoms);
+        }
+        void loadTopology(const char *filename);
+
+        gmx::SelectionCollection _sc;
+        gmx::EmptyErrorReporter  _errors;
+        t_topology              *_top;
+        t_trxframe              *_frame;
+};
+
+SelectionCollectionTest::SelectionCollectionTest()
+    : _sc(NULL), _top(NULL), _frame(NULL)
+{
+    _sc.init();
+    _sc.setReferencePosType("atom");
+    _sc.setOutputPosType("atom");
+}
+
+
+SelectionCollectionTest::~SelectionCollectionTest()
+{
+    if (_top != NULL)
+    {
+        done_top(_top);
+        sfree(_top);
+    }
+
+    if (_frame != NULL)
+    {
+        sfree(_frame->x);
+        sfree(_frame);
+    }
+}
+
+
+void
+SelectionCollectionTest::loadTopology(const char *filename)
+{
+    char    title[STRLEN];
+    int     ePBC;
+    rvec   *xtop;
+    matrix  box;
+
+    snew(_top, 1);
+    read_tps_conf(filename, title, _top, &ePBC, &xtop, NULL, box, FALSE);
+
+    snew(_frame, 1);
+    _frame->flags  = TRX_NEED_X;
+    _frame->natoms = _top->atoms.nr;
+    _frame->bX     = TRUE;
+    snew(_frame->x, _frame->natoms);
+    memcpy(_frame->x, xtop, sizeof(*_frame->x) * _frame->natoms);
+    _frame->bBox   = TRUE;
+    copy_mat(box, _frame->box);
+
+    ASSERT_EQ(0, _sc.setTopology(_top, -1));
+}
+
+
+/********************************************************************
+ * Tests for SelectionCollection functionality
+ */
+
+TEST_F(SelectionCollectionTest, HandlesNoSelections)
+{
+    EXPECT_FALSE(_sc.requiresTopology());
+    EXPECT_EQ(0, _sc.compile());
+}
+
+
+TEST_F(SelectionCollectionTest, HandlesSimpleSelections)
+{
+    std::vector<gmx::Selection *> sel;
+    EXPECT_EQ(0, _sc.parseFromString("atomnr 1 to 5", &_errors, &sel));
+    EXPECT_EQ(1U, sel.size());
+    EXPECT_EQ(0, _sc.parseFromString("atomnr 2 to 4", &_errors, &sel));
+    EXPECT_EQ(2U, sel.size());
+    setAtomCount(10);
+    EXPECT_EQ(0, _sc.compile());
+    ASSERT_EQ(2U, sel.size());
+    EXPECT_EQ(5, sel[0]->posCount());
+    EXPECT_EQ(3, sel[1]->posCount());
+}
+
+
+/********************************************************************
+ * Tests for selection syntax
+ */
+
+TEST_F(SelectionCollectionTest, HandlesConstantPositions)
+{
+    std::vector<gmx::Selection *> sel;
+    EXPECT_EQ(0, _sc.parseFromString("[1, -2, 3.5]", &_errors, &sel));
+    ASSERT_EQ(1U, sel.size());
+    EXPECT_FALSE(sel[0]->isDynamic());
+    setAtomCount(10);
+    EXPECT_EQ(0, _sc.compile());
+    EXPECT_EQ(1, sel[0]->posCount());
+}
+
+
+TEST_F(SelectionCollectionTest, HandlesStringMatching)
+{
+    std::vector<gmx::Selection *> sel;
+    EXPECT_EQ(0, _sc.parseFromString("resname RA RD", &_errors, &sel));
+    EXPECT_EQ(0, _sc.parseFromString("resname \"R[BD]\"", &_errors, &sel));
+    ASSERT_EQ(2U, sel.size());
+    EXPECT_FALSE(sel[0]->isDynamic());
+    EXPECT_FALSE(sel[1]->isDynamic());
+    loadTopology(SOURCE_DIR "/src/gromacs/selection/tests/simple.gro");
+    EXPECT_EQ(0, _sc.compile());
+    EXPECT_EQ(9, sel[0]->posCount());
+    EXPECT_EQ(6, sel[1]->posCount());
+}
+
+
+TEST_F(SelectionCollectionTest, HandlesComparison)
+{
+    std::vector<gmx::Selection *> sel;
+    EXPECT_EQ(0, _sc.parseFromString("atomnr <= 5", &_errors, &sel));
+    ASSERT_EQ(1U, sel.size());
+    EXPECT_FALSE(sel[0]->isDynamic());
+    setAtomCount(10);
+    EXPECT_EQ(0, _sc.compile());
+    EXPECT_EQ(5, sel[0]->posCount());
+}
+
+
+TEST_F(SelectionCollectionTest, HandlesBasicBoolean)
+{
+    std::vector<gmx::Selection *> sel;
+    EXPECT_EQ(0, _sc.parseFromString("atomnr 1 to 5 and atomnr 2 to 7", &_errors, &sel));
+    EXPECT_EQ(0, _sc.parseFromString("atomnr 1 to 5 or not atomnr 3 to 8", &_errors, &sel));
+    EXPECT_EQ(0, _sc.parseFromString("atomnr 1 to 5 and atomnr 2 to 6 and not not atomnr 3 to 7", &_errors, &sel));
+    ASSERT_EQ(3U, sel.size());
+    EXPECT_FALSE(sel[0]->isDynamic());
+    EXPECT_FALSE(sel[1]->isDynamic());
+    EXPECT_FALSE(sel[2]->isDynamic());
+    setAtomCount(10);
+    EXPECT_EQ(0, _sc.compile());
+    EXPECT_EQ(4, sel[0]->posCount());
+    EXPECT_EQ(7, sel[1]->posCount());
+    EXPECT_EQ(3, sel[2]->posCount());
+}
+
+
+TEST_F(SelectionCollectionTest, HandlesBooleanStaticAnalysis)
+{
+    std::vector<gmx::Selection *> sel;
+    EXPECT_EQ(0, _sc.parseFromString("atomnr 1 to 5 and atomnr 2 to 7 and x < 2", &_errors, &sel));
+    EXPECT_EQ(0, _sc.parseFromString("atomnr 1 to 5 and (atomnr 4 to 7 or x < 2)", &_errors, &sel));
+    EXPECT_EQ(0, _sc.parseFromString("atomnr 1 to 5 and y < 3 and (atomnr 4 to 7 or x < 2)", &_errors, &sel));
+    EXPECT_EQ(0, _sc.parseFromString("atomnr 1 to 5 and not (atomnr 4 to 7 or x < 2)", &_errors, &sel));
+    ASSERT_EQ(4U, sel.size());
+    EXPECT_TRUE(sel[0]->isDynamic());
+    EXPECT_TRUE(sel[1]->isDynamic());
+    EXPECT_TRUE(sel[2]->isDynamic());
+    EXPECT_TRUE(sel[3]->isDynamic());
+    setAtomCount(10);
+    EXPECT_EQ(0, _sc.compile());
+    EXPECT_EQ(4, sel[0]->posCount());
+    EXPECT_EQ(5, sel[1]->posCount());
+    EXPECT_EQ(5, sel[2]->posCount());
+    EXPECT_EQ(3, sel[3]->posCount());
+}
+
+
+TEST_F(SelectionCollectionTest, HandlesBooleanStaticAnalysisWithVariables)
+{
+    std::vector<gmx::Selection *> sel;
+    EXPECT_EQ(0, _sc.parseFromString("foo = atomnr 4 to 7 or x < 2", &_errors, &sel));
+    EXPECT_EQ(0, _sc.parseFromString("atomnr 1 to 4 and foo", &_errors, &sel));
+    EXPECT_EQ(0, _sc.parseFromString("atomnr 2 to 6 and y < 3 and foo", &_errors, &sel));
+    EXPECT_EQ(0, _sc.parseFromString("atomnr 6 to 10 and not foo", &_errors, &sel));
+    ASSERT_EQ(3U, sel.size());
+    EXPECT_TRUE(sel[0]->isDynamic());
+    EXPECT_TRUE(sel[1]->isDynamic());
+    EXPECT_TRUE(sel[2]->isDynamic());
+    setAtomCount(10);
+    EXPECT_EQ(0, _sc.compile());
+    EXPECT_EQ(4, sel[0]->posCount());
+    EXPECT_EQ(5, sel[1]->posCount());
+    EXPECT_EQ(3, sel[2]->posCount());
+}
+
+
+TEST_F(SelectionCollectionTest, HandlesBooleanStaticAnalysisWithMoreVariables)
+{
+    std::vector<gmx::Selection *> sel;
+    EXPECT_EQ(0, _sc.parseFromString("foo = atomnr 4 to 7", &_errors, &sel));
+    EXPECT_EQ(0, _sc.parseFromString("bar = foo and x < 2", &_errors, &sel));
+    EXPECT_EQ(0, _sc.parseFromString("bar2 = foo and y < 2", &_errors, &sel));
+    EXPECT_EQ(0, _sc.parseFromString("atomnr 1 to 4 and bar", &_errors, &sel));
+    EXPECT_EQ(0, _sc.parseFromString("atomnr 2 to 6 and y < 3 and bar2", &_errors, &sel));
+    EXPECT_EQ(0, _sc.parseFromString("atomnr 6 to 10 and not foo", &_errors, &sel));
+    ASSERT_EQ(3U, sel.size());
+    EXPECT_TRUE(sel[0]->isDynamic());
+    EXPECT_TRUE(sel[1]->isDynamic());
+    EXPECT_FALSE(sel[2]->isDynamic());
+    setAtomCount(10);
+    EXPECT_EQ(0, _sc.compile());
+    EXPECT_EQ(1, sel[0]->posCount());
+    EXPECT_EQ(3, sel[1]->posCount());
+    EXPECT_EQ(3, sel[2]->posCount());
+}
+
+
+TEST_F(SelectionCollectionTest, HandlesSameResidue)
+{
+    std::vector<gmx::Selection *> sel;
+    EXPECT_EQ(0, _sc.parseFromString("same residue as atomnr 1 4 12", &_errors, &sel));
+    ASSERT_EQ(1U, sel.size());
+    EXPECT_FALSE(sel[0]->isDynamic());
+    loadTopology(SOURCE_DIR "/src/gromacs/selection/tests/simple.gro");
+    EXPECT_EQ(0, _sc.compile());
+    EXPECT_EQ(9, sel[0]->posCount());
+}
+
+
+TEST_F(SelectionCollectionTest, HandlesSameResidueName)
+{
+    std::vector<gmx::Selection *> sel;
+    EXPECT_EQ(0, _sc.parseFromString("same resname as atomnr 1 14", &_errors, &sel));
+    ASSERT_EQ(1U, sel.size());
+    EXPECT_FALSE(sel[0]->isDynamic());
+    loadTopology(SOURCE_DIR "/src/gromacs/selection/tests/simple.gro");
+    EXPECT_EQ(0, _sc.compile());
+    EXPECT_EQ(9, sel[0]->posCount());
+}
+
+
+TEST_F(SelectionCollectionTest, HandlesArithmeticExpressions)
+{
+    std::vector<gmx::Selection *> sel;
+    EXPECT_EQ(0, _sc.parseFromString("x+1 > 3", &_errors, &sel));
+    EXPECT_EQ(0, _sc.parseFromString("(y-1)^2 <= 1", &_errors, &sel));
+    EXPECT_EQ(0, _sc.parseFromString("x+--1 > 3", &_errors, &sel));
+    EXPECT_EQ(0, _sc.parseFromString("-x+-1 < -3", &_errors, &sel));
+    ASSERT_EQ(4U, sel.size());
+    EXPECT_TRUE(sel[0]->isDynamic());
+    EXPECT_TRUE(sel[1]->isDynamic());
+    EXPECT_TRUE(sel[2]->isDynamic());
+    EXPECT_TRUE(sel[3]->isDynamic());
+    loadTopology(SOURCE_DIR "/src/gromacs/selection/tests/simple.gro");
+    EXPECT_EQ(0, _sc.compile());
+    EXPECT_EQ(15, sel[0]->posCount());
+    EXPECT_EQ(15, sel[1]->posCount());
+    EXPECT_EQ(15, sel[2]->posCount());
+    EXPECT_EQ(15, sel[3]->posCount());
+    EXPECT_EQ(0, _sc.evaluate(_frame, NULL));
+    EXPECT_EQ(7, sel[0]->posCount());
+    EXPECT_EQ(8, sel[1]->posCount());
+    EXPECT_EQ(7, sel[2]->posCount());
+    EXPECT_EQ(7, sel[3]->posCount());
+    EXPECT_EQ(0, _sc.evaluateFinal(1));
+    EXPECT_EQ(15, sel[0]->posCount());
+    EXPECT_EQ(15, sel[1]->posCount());
+    EXPECT_EQ(15, sel[2]->posCount());
+    EXPECT_EQ(15, sel[3]->posCount());
+}
+
+
+TEST_F(SelectionCollectionTest, HandlesWithinConstantPositions)
+{
+    std::vector<gmx::Selection *> sel;
+    EXPECT_EQ(0, _sc.parseFromString("within 1 of [2, 1, 0]", &_errors, &sel));
+    ASSERT_EQ(1U, sel.size());
+    EXPECT_TRUE(sel[0]->isDynamic());
+    loadTopology(SOURCE_DIR "/src/gromacs/selection/tests/simple.gro");
+    EXPECT_EQ(0, _sc.compile());
+    EXPECT_EQ(15, sel[0]->posCount());
+    EXPECT_EQ(0, _sc.evaluate(_frame, NULL));
+    EXPECT_EQ(4, sel[0]->posCount());
+    EXPECT_EQ(0, _sc.evaluateFinal(1));
+    EXPECT_EQ(15, sel[0]->posCount());
+}
+
+} // namespace
diff --git a/src/gromacs/selection/tests/selectionoption.cpp b/src/gromacs/selection/tests/selectionoption.cpp
new file mode 100644 (file)
index 0000000..c7b5dc1
--- /dev/null
@@ -0,0 +1,181 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * Tests selection parsing and compilation.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_selection
+ */
+#include <vector>
+
+#include <gtest/gtest.h>
+
+#include "gromacs/errorreporting/emptyerrorreporter.h"
+#include "gromacs/options/globalproperties.h"
+#include "gromacs/options/options.h"
+#include "gromacs/options/optionsassigner.h"
+#include "gromacs/selection/selection.h"
+#include "gromacs/selection/selectioncollection.h"
+#include "gromacs/selection/selectionoption.h"
+
+namespace
+{
+
+class SelectionOptionTest : public ::testing::Test
+{
+    public:
+        SelectionOptionTest();
+
+        gmx::SelectionCollection _sc;
+        gmx::Options             _options;
+};
+
+SelectionOptionTest::SelectionOptionTest()
+    : _sc(NULL), _options(NULL, NULL)
+{
+    _sc.init();
+    _sc.setReferencePosType("atom");
+    _sc.setOutputPosType("atom");
+    _options.globalProperties().setSelectionCollection(&_sc);
+}
+
+
+TEST_F(SelectionOptionTest, ParsesSimpleSelection)
+{
+    gmx::Selection *sel = NULL;
+    using gmx::SelectionOption;
+    _options.addOption(SelectionOption("sel").store(&sel));
+
+    gmx::EmptyErrorReporter errors;
+    gmx::OptionsAssigner assigner(&_options, &errors);
+    ASSERT_EQ(0, assigner.startOption("sel"));
+    EXPECT_EQ(0, assigner.appendValue("resname RA RB"));
+    EXPECT_EQ(0, assigner.finish());
+    EXPECT_EQ(0, _options.finish(&errors));
+    ASSERT_TRUE(sel != NULL);
+    ASSERT_FALSE(sel->isDynamic());
+}
+
+
+TEST_F(SelectionOptionTest, HandlesDynamicSelectionWhenStaticRequired)
+{
+    gmx::Selection *sel = NULL;
+    using gmx::SelectionOption;
+    _options.addOption(SelectionOption("sel").store(&sel).onlyStatic());
+
+    gmx::EmptyErrorReporter errors;
+    gmx::OptionsAssigner assigner(&_options, &errors);
+    ASSERT_EQ(0, assigner.startOption("sel"));
+    EXPECT_NE(0, assigner.appendValue("resname RA RB and x < 5"));
+    EXPECT_NE(0, assigner.finish());
+    EXPECT_EQ(0, _options.finish(&errors));
+}
+
+
+TEST_F(SelectionOptionTest, HandlesTooManySelections)
+{
+    gmx::Selection *sel = NULL;
+    using gmx::SelectionOption;
+    _options.addOption(SelectionOption("sel").store(&sel));
+
+    gmx::EmptyErrorReporter errors;
+    gmx::OptionsAssigner assigner(&_options, &errors);
+    ASSERT_EQ(0, assigner.startOption("sel"));
+    EXPECT_EQ(0, assigner.appendValue("resname RA RB"));
+    EXPECT_NE(0, assigner.appendValue("resname RB RC"));
+    EXPECT_NE(0, assigner.finish());
+    EXPECT_EQ(0, _options.finish(&errors));
+    ASSERT_TRUE(sel != NULL);
+}
+
+
+TEST_F(SelectionOptionTest, HandlesTooFewSelections)
+{
+    gmx::Selection *sel[2] = {NULL, NULL};
+    using gmx::SelectionOption;
+    _options.addOption(SelectionOption("sel").store(sel).valueCount(2));
+
+    gmx::EmptyErrorReporter errors;
+    gmx::OptionsAssigner assigner(&_options, &errors);
+    ASSERT_EQ(0, assigner.startOption("sel"));
+    EXPECT_EQ(0, assigner.appendValue("resname RA RB"));
+    EXPECT_NE(0, assigner.finish());
+    EXPECT_EQ(0, _options.finish(&errors));
+}
+
+
+TEST_F(SelectionOptionTest, HandlesDelayedRequiredSelection)
+{
+    gmx::Selection *sel = NULL;
+    using gmx::SelectionOption;
+    _options.addOption(SelectionOption("sel").store(&sel).required());
+
+    gmx::EmptyErrorReporter errors;
+    gmx::OptionsAssigner assigner(&_options, &errors);
+    EXPECT_EQ(0, assigner.finish());
+    EXPECT_EQ(0, _options.finish(&errors));
+    EXPECT_EQ(0, _sc.parseRequestedFromString("resname RA RB", &errors));
+    ASSERT_TRUE(sel != NULL);
+}
+
+
+TEST_F(SelectionOptionTest, HandlesTooFewDelayedRequiredSelections)
+{
+    gmx::Selection *sel[2] = {NULL, NULL};
+    using gmx::SelectionOption;
+    _options.addOption(SelectionOption("sel").store(sel).required()
+                           .valueCount(2));
+
+    gmx::EmptyErrorReporter errors;
+    gmx::OptionsAssigner assigner(&_options, &errors);
+    EXPECT_EQ(0, assigner.finish());
+    EXPECT_EQ(0, _options.finish(&errors));
+    EXPECT_NE(0, _sc.parseRequestedFromString("resname RA RB", &errors));
+}
+
+
+TEST_F(SelectionOptionTest, HandlesDelayedOptionalSelection)
+{
+    gmx::Selection *sel = NULL;
+    using gmx::SelectionOption;
+    _options.addOption(SelectionOption("sel").store(&sel));
+
+    gmx::EmptyErrorReporter errors;
+    gmx::OptionsAssigner assigner(&_options, &errors);
+    ASSERT_EQ(0, assigner.startOption("sel"));
+    EXPECT_EQ(0, assigner.finish());
+    EXPECT_EQ(0, _options.finish(&errors));
+    EXPECT_EQ(0, _sc.parseRequestedFromString("resname RA RB", &errors));
+    ASSERT_TRUE(sel != NULL);
+}
+
+} // namespace
diff --git a/src/gromacs/selection/tests/simple.gro b/src/gromacs/selection/tests/simple.gro
new file mode 100644 (file)
index 0000000..02690f9
--- /dev/null
@@ -0,0 +1,18 @@
+Test system
+ 15
+    1RA      CB    1   1.000   1.000   0.000
+    1RA      S1    2   1.000   2.000   0.000
+    1RA      S2    3   1.000   3.000   0.000
+    2RB      CB    4   1.000   4.000   0.000
+    2RB      S1    5   2.000   1.000   0.000
+    2RB      S2    6   2.000   2.000   0.000
+    3RA      CB    7   2.000   3.000   0.000
+    3RA      S1    8   2.000   4.000   0.000
+    3RA      S2    9   3.000   1.000   0.000
+    4RC      CB   10   3.000   2.000   0.000
+    4RC      S1   11   3.000   3.000   0.000
+    4RC      S2   12   3.000   4.000   0.000
+    5RD      CB   13   4.000   1.000   0.000
+    5RD      S1   14   4.000   2.000   0.000
+    5RD      S2   15   4.000   3.000   0.000
+  10.00000  10.00000  10.00000
diff --git a/src/gromacs/selection/tests/test_main.cpp b/src/gromacs/selection/tests/test_main.cpp
new file mode 100644 (file)
index 0000000..406a8ff
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * main() for unit tests that use Google C++ Testing Framework.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ */
+#include <gtest/gtest.h>
+
+#include "gromacs/fatalerror/fatalerror.h"
+
+/*! \brief
+ * Initializes unit testing with Google C++ Testing Framework.
+ */
+int main(int argc, char *argv[])
+{
+    ::testing::InitGoogleTest(&argc, argv);
+    ::gmx::setFatalErrorHandler(NULL);
+    return RUN_ALL_TESTS();
+}
diff --git a/src/gromacs/trajectoryanalysis/CMakeLists.txt b/src/gromacs/trajectoryanalysis/CMakeLists.txt
new file mode 100644 (file)
index 0000000..726ceb8
--- /dev/null
@@ -0,0 +1,14 @@
+file(GLOB TRAJECTORYANALYSIS_SOURCES *.cpp modules/*.cpp)
+set(LIBGROMACS_SOURCES ${LIBGROMACS_SOURCES} ${TRAJECTORYANALYSIS_SOURCES} PARENT_SCOPE)
+
+set(TRAJECTORYANALYSIS_PUBLIC_HEADERS
+    analysismodule.h
+    analysissettings.h
+    cmdlinerunner.h)
+install(FILES ${TRAJECTORYANALYSIS_PUBLIC_HEADERS}
+        DESTINATION ${INCL_INSTALL_DIR}/gromacs/trajectoryanalysis
+        COMPONENT development)
+
+if (BUILD_TESTING)
+    add_subdirectory(tests)
+endif (BUILD_TESTING)
diff --git a/src/gromacs/trajectoryanalysis/analysismodule-impl.h b/src/gromacs/trajectoryanalysis/analysismodule-impl.h
new file mode 100644 (file)
index 0000000..f87d457
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * Declares private implementation classes for gmx::TrajectoryAnalysisModule
+ * and gmx::TrajectoryAnalysisModuleData.
+ *
+ * \ingroup module_trajectoryanalysis
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ */
+#ifndef GMX_TRAJECTORYANALYSIS_ANALYSISMODULE_IMPL_H
+#define GMX_TRAJECTORYANALYSIS_ANALYSISMODULE_IMPL_H
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "analysismodule.h"
+
+namespace gmx
+{
+
+class AbstractAnalysisData;
+class AnalysisData;
+class AnalysisDataHandle;
+
+class TrajectoryAnalysisModuleData::Impl
+{
+    public:
+        typedef std::map<std::string, AnalysisDataHandle *> HandleContainer;
+
+        Impl() : _selections(NULL) {}
+        ~Impl();
+
+        int finishHandles();
+
+        HandleContainer         _handles;
+        const SelectionCollection *_selections;
+};
+
+class TrajectoryAnalysisModule::Impl
+{
+    public:
+        typedef std::map<std::string, AbstractAnalysisData *> DatasetContainer;
+        typedef std::map<std::string, AnalysisData *> AnalysisDatasetContainer;
+
+        std::vector<std::string>        _datasetNames;
+        DatasetContainer                _datasets;
+        AnalysisDatasetContainer        _analysisDatasets;
+};
+
+/*! \internal \brief
+ * Basic thread-local trajectory analysis data storage class.
+ *
+ * Most simple tools should only require data handles and selections to be
+ * thread-local, so this class implements just that.
+ */
+class TrajectoryAnalysisModuleDataBasic : public TrajectoryAnalysisModuleData
+{
+    public:
+        virtual int finish();
+};
+
+} // namespace gmx
+
+#endif
diff --git a/src/gromacs/trajectoryanalysis/analysismodule.cpp b/src/gromacs/trajectoryanalysis/analysismodule.cpp
new file mode 100644 (file)
index 0000000..027509f
--- /dev/null
@@ -0,0 +1,256 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * Implements classes in analysismodule.h
+ *
+ * \ingroup module_trajectoryanalysis
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ */
+#include "gromacs/trajectoryanalysis/analysismodule.h"
+
+#include <cassert>
+
+#include "gromacs/analysisdata/analysisdata.h"
+
+#include "analysismodule-impl.h"
+
+namespace gmx
+{
+
+/********************************************************************
+ * TrajectoryAnalysisModuleData::Impl
+ */
+
+TrajectoryAnalysisModuleData::Impl::~Impl()
+{
+    finishHandles();
+}
+
+
+int TrajectoryAnalysisModuleData::Impl::finishHandles()
+{
+    int rc = 0;
+    HandleContainer::const_iterator i;
+    for (i = _handles.begin(); i != _handles.end(); ++i)
+    {
+        int rc1 = i->second->finishData();
+        rc = (rc == 0 ? rc1 : rc);
+    }
+    _handles.clear();
+    return rc;
+}
+
+
+/********************************************************************
+ * TrajectoryAnalysisModuleData
+ */
+
+TrajectoryAnalysisModuleData::TrajectoryAnalysisModuleData()
+    : _impl(new Impl)
+{
+}
+
+
+TrajectoryAnalysisModuleData::~TrajectoryAnalysisModuleData()
+{
+    delete _impl;
+}
+
+
+int TrajectoryAnalysisModuleData::init(TrajectoryAnalysisModule *module,
+                                       AnalysisDataParallelOptions opt,
+                                       const SelectionCollection &selections)
+{
+    TrajectoryAnalysisModule::Impl::AnalysisDatasetContainer::const_iterator i;
+    for (i = module->_impl->_analysisDatasets.begin();
+         i != module->_impl->_analysisDatasets.end(); ++i)
+    {
+        AnalysisDataHandle *handle = NULL;
+        int rc = i->second->startData(&handle, opt);
+        if (rc != 0)
+        {
+            return rc;
+        }
+        _impl->_handles[i->first] = handle;
+    }
+    _impl->_selections = &selections;
+    return 0;
+}
+
+
+int TrajectoryAnalysisModuleData::finishDataHandles()
+{
+    return _impl->finishHandles();
+}
+
+
+AnalysisDataHandle *TrajectoryAnalysisModuleData::dataHandle(const char *name)
+{
+    Impl::HandleContainer::const_iterator i = _impl->_handles.find(name);
+    assert(i != _impl->_handles.end() || !"Data handle requested on unknown dataset");
+    return (i != _impl->_handles.end()) ? (*i).second : NULL;
+}
+
+
+Selection *TrajectoryAnalysisModuleData::parallelSelection(Selection *selection)
+{
+    // TODO: Implement properly.
+    return selection;
+}
+
+
+std::vector<Selection *>
+TrajectoryAnalysisModuleData::parallelSelections(const std::vector<Selection *> &selections)
+{
+    std::vector<Selection *> newSelections;
+    newSelections.reserve(selections.size());
+    std::vector<Selection *>::const_iterator i = selections.begin();
+    for ( ; i != selections.end(); ++i)
+    {
+        newSelections.push_back(parallelSelection(*i));
+    }
+    return newSelections;
+}
+
+
+/********************************************************************
+ * TrajectoryAnalysisModuleDataBasic
+ */
+
+int
+TrajectoryAnalysisModuleDataBasic::finish()
+{
+    return finishDataHandles();
+}
+
+
+/********************************************************************
+ * TrajectoryAnalysisModule
+ */
+
+TrajectoryAnalysisModule::TrajectoryAnalysisModule()
+    : _impl(new Impl)
+{
+}
+
+
+TrajectoryAnalysisModule::~TrajectoryAnalysisModule()
+{
+    delete _impl;
+}
+
+
+int TrajectoryAnalysisModule::initOptionsDone(TrajectoryAnalysisSettings * /*settings*/)
+{
+    return 0;
+}
+
+
+int TrajectoryAnalysisModule::initAfterFirstFrame(const t_trxframe &/*fr*/)
+{
+    return 0;
+}
+
+
+int TrajectoryAnalysisModule::startFrames(AnalysisDataParallelOptions opt,
+                                          const SelectionCollection &selections,
+                                          TrajectoryAnalysisModuleData **pdatap)
+{
+    TrajectoryAnalysisModuleDataBasic *pdata
+        = new TrajectoryAnalysisModuleDataBasic();
+    *pdatap = pdata;
+    int rc = pdata->init(this, opt, selections);
+    if (rc != 0)
+    {
+        delete pdata;
+        *pdatap = NULL;
+    }
+    return rc;
+}
+
+
+int TrajectoryAnalysisModule::finishFrames(TrajectoryAnalysisModuleData * /*pdata*/)
+{
+    return 0;
+}
+
+
+int TrajectoryAnalysisModule::datasetCount() const
+{
+    return _impl->_datasetNames.size();
+}
+
+
+const std::vector<std::string> &TrajectoryAnalysisModule::datasetNames() const
+{
+    return _impl->_datasetNames;
+}
+
+
+AbstractAnalysisData *TrajectoryAnalysisModule::datasetFromIndex(int index) const
+{
+    if (index < 0 || index >= datasetCount())
+    {
+        return NULL;
+    }
+    return _impl->_datasets[_impl->_datasetNames[index]];
+}
+
+
+AbstractAnalysisData *TrajectoryAnalysisModule::datasetFromName(const char *name) const
+{
+    Impl::DatasetContainer::const_iterator item = _impl->_datasets.find(name);
+    if (item == _impl->_datasets.end())
+    {
+        return NULL;
+    }
+    return item->second;
+}
+
+
+void TrajectoryAnalysisModule::registerBasicDataset(AbstractAnalysisData *data,
+                                                    const char *name)
+{
+    // TODO: Check for duplicates
+    _impl->_datasets[name] = data;
+    _impl->_datasetNames.push_back(name);
+}
+
+
+void TrajectoryAnalysisModule::registerAnalysisDataset(AnalysisData *data,
+                                                       const char *name)
+{
+    registerBasicDataset(data, name);
+    _impl->_analysisDatasets[name] = data;
+}
+
+} // namespace gmx
diff --git a/src/gromacs/trajectoryanalysis/analysismodule.h b/src/gromacs/trajectoryanalysis/analysismodule.h
new file mode 100644 (file)
index 0000000..8463922
--- /dev/null
@@ -0,0 +1,352 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \file
+ * \brief
+ * Declaration of TrajanaModule and integrally related classes.
+ */
+#ifndef GMX_TRAJECTORYANALYSIS_ANALYSISMODULE_H
+#define GMX_TRAJECTORYANALYSIS_ANALYSISMODULE_H
+
+#include <string>
+#include <vector>
+
+#include "../legacyheaders/typedefs.h"
+
+namespace gmx
+{
+
+class AbstractAnalysisData;
+class AnalysisData;
+class AnalysisDataHandle;
+class Options;
+class Selection;
+class SelectionCollection;
+class TopologyInformation;
+class TrajectoryAnalysisModule;
+class TrajectoryAnalysisSettings;
+
+/*! \brief
+ * Base class for thread-local data storage during trajectory analysis.
+ *
+ * Thread-local storage of data handles and selections is implemented in this
+ * class; TrajectoryAnalysisModule instances can access the thread-local values
+ * using dataHandle() and parallelSelection().
+ *
+ * \see TrajectoryAnalysisModule::startFrames()
+ */
+class TrajectoryAnalysisModuleData
+{
+    public:
+        virtual ~TrajectoryAnalysisModuleData();
+
+        /*! \brief
+         * Initializes thread-local storage for data handles and selections.
+         *
+         * \param[in] module     Analysis module to use for data objects.
+         * \param[in] opt        Data parallelization options.
+         * \param[in] selections Thread-local selection collection.
+         *
+         * Calls AnalysisData::startData() on all data objects registered with
+         * TrajectoryAnalysisModule::registerAnalysisDataset() in \p module.
+         * The handles are accessible through dataHandle().
+         */
+        int init(TrajectoryAnalysisModule *module, /*AnalysisDataParallelOptions*/ void* opt,
+                 const SelectionCollection &selections);
+
+        /*! \brief
+         * Performs any finishing actions after all frames have been processed.
+         *
+         * \returns  0 on success, a non-zero error code on error.
+         *
+         * This function is called immediately before the destructor.
+         * All implementations should call finishDataHandles().
+         */
+        virtual int finish() = 0;
+
+        /*! \brief
+         * Returns a data handle for a dataset with a given name.
+         *
+         * Allowed names are those that have been registered with
+         * TrajectoryAnalysisModule::registerAnalysisData().
+         */
+        AnalysisDataHandle *dataHandle(const char *name);
+        /*! \brief
+         * Returns a selection that corresponds to the given selection.
+         */
+        Selection *parallelSelection(Selection *selection);
+        /*! \brief
+         * Returns a set of selection that corresponds to the given selections.
+         */
+        std::vector<Selection *> parallelSelections(const std::vector<Selection *> &selections);
+
+    protected:
+        //! Initializes data.
+        TrajectoryAnalysisModuleData();
+
+        /*! \brief
+         * Calls finishData() on all data handles.
+         *
+         * \returns  0 on success, a non-zero error code on error.
+         *
+         * This function should be called from the implementation of finish()
+         * in all subclasses.
+         */
+        int finishDataHandles();
+
+    private:
+        class Impl;
+
+        Impl                   *_impl;
+
+        // Disallow copy and assign.
+        TrajectoryAnalysisModuleData(const TrajectoryAnalysisModuleData &);
+        void operator =(const TrajectoryAnalysisModuleData &);
+};
+
+
+/*! \brief
+ * Trajectory analysis method.
+ *
+ * For parallel analysis using threads, only a single object is constructed,
+ * but the methods startFrames(), analyzeFrame() and finishFrames() are
+ * called in each thread. Frame-local data should be initialized in
+ * startFrames() and stored in a class derived from
+ * TrajectoryAnalysisModuleData that is passed to the other methods.
+ */
+class TrajectoryAnalysisModule
+{
+    public:
+        virtual ~TrajectoryAnalysisModule();
+
+        /*! \brief
+         * Initializes parameters understood by the module.
+         *
+         * In addition to initializing the accepted parameters, this function
+         * should also set any required options using the options() object,
+         * see TrajanaOptions for more details.
+         * It can also customize the acceptable selections using selections(),
+         * see Selections.
+         *
+         * If option values depend on the parameter values provided by the
+         * user, see initParamsDone().
+         */
+        virtual Options *initOptions(TrajectoryAnalysisSettings *settings) = 0;
+        /*! \brief
+         * Called after all parameter values have been set.
+         *
+         * If the module needs to set options that affect topology loading or
+         * selection initialization based on parameters values, this function
+         * has to be overridden.
+         *
+         * The default implementation does nothing.
+         */
+        virtual int initOptionsDone(TrajectoryAnalysisSettings *settings);
+        /*! \brief
+         * Initializes the analysis.
+         *
+         * \returns  Zero on success, a non-zero error code on error.
+         *
+         * When this function is called, selections have been initialized based
+         * on user input, and a topology has been loaded if provided by the
+         * user. For dynamic selections, the selections have been evaluated to
+         * the largest possible selection, i.e., the selections passed to
+         * analyzeFrame() are always a subset of the selections provided here.
+         */
+        virtual int initAnalysis(const TopologyInformation &top) = 0;
+        /*! \brief
+         * Performs additional initialization after reading the first frame.
+         *
+         * \returns  Zero on success, a non-zero error code on error.
+         *
+         * When this function is called, selections are the same as in
+         * initAnalysis(), i.e., they have not been evaluated for the first
+         * frame.
+         *
+         * It is necessary to override this method only if the module needs to
+         * do initialization for which it requires data from the first frame.
+         *
+         * The default implementation does nothing.
+         */
+        virtual int initAfterFirstFrame(const t_trxframe &fr);
+
+        /*! \brief
+         * Starts the analysis of frames.
+         *
+         * \param[in]  opt
+         * \param[in]  selections  Frame-local selection object.
+         * \param[out] pdatap  Data structure for thread-local data.
+         *
+         * This function is necessary only for threaded parallelization.
+         * It is called once for each thread and should initialize a class that
+         * contains any required frame-local data in \p *pdatap.
+         * The default implementation creates a basic data structure that holds
+         * thread-local data handles for all data objects registered with
+         * registerAnalysisDataset(), as well as the thread-local selection
+         * collection.  These can be accessed in analyzeFrame() using the
+         * methods in TrajectoryAnalysisModuleData.
+         * If other thread-local data is needed, this function should be
+         * overridden and it should create an instance of a class derived from
+         * TrajectoryAnalysisModuleData.
+         *
+         * \see TrajectoryAnalysisModuleData
+         */
+        virtual int startFrames(/*AnalysisDataParallelOptions*/ void* opt,
+                                const SelectionCollection &selections,
+                                TrajectoryAnalysisModuleData **pdatap);
+        /*! \brief
+         * Analyzes a single frame.
+         *
+         * \param[in]     frnr   Frame number, a zero-based index that
+         *      uniquely identifies the frame.
+         * \param[in]     fr     Current frame.
+         * \param[in]     pbc    Periodic boundary conditions for \p fr.
+         * \param[in,out] pdata  Data structure for frame-local data.
+         * \return  0 on success, a non-zero error code or error.
+         *
+         * This function is called once for each frame to be analyzed,
+         * and should analyze the positions provided in \p sel.
+         *
+         * For threaded analysis, this function is called asynchronously in
+         * different threads to analyze different frames. The \p pdata
+         * structure is one of the structures created with startFrames(),
+         * but no assumptions should be made about which of these data
+         * structures is used. It is guaranteed that two instances of
+         * analyzeFrame() are not running concurrently with the same \p pdata
+         * data structure.
+         * Any access to data structures not stored in \p pdata should be
+         * designed to be thread-safe.
+         */
+        virtual int analyzeFrame(int frnr, const t_trxframe &fr, t_pbc *pbc,
+                                 TrajectoryAnalysisModuleData *pdata) = 0;
+        /*! \brief
+         * Finishes the analysis of frames.
+         *
+         * \param[in]  pdata    Data structure for thread-local data.
+         *
+         * This function is called once for each call of startFrames(),
+         * with the data structure returned by the corresponding startFrames().
+         * The \p pdata object should be destroyed by the caller after this
+         * function has been called.
+         *
+         * You only need to override this method if you need custom
+         * operations to combine data from the frame-local data structures
+         * to get the final result. In such cases, the data should be
+         * aggregated in this function and stored in a member attribute.
+         *
+         * The default implementation does nothing.
+         *
+         * \see startFrames()
+         */
+        virtual int finishFrames(TrajectoryAnalysisModuleData *pdata);
+
+        /*! \brief
+         * Postprocesses data after frames have been read.
+         *
+         * This function is called after all finishFrames() calls have been
+         * called.
+         */
+        virtual int finishAnalysis(int nframes) = 0;
+        /*! \brief
+         * Writes output into files and/or standard output/error.
+         *
+         * All output from the module, excluding data written out for each
+         * frame during analyzeFrame(), should be confined into this function.
+         * This function is guaranteed to be called only after
+         * finishAnalysis().
+         */
+        virtual int writeOutput() = 0;
+
+        /*! \brief
+         * Returns the number of datasets provided by the module.
+         */
+        int datasetCount() const;
+        /*! \brief
+         * Returns a vector with the names of the datasets.
+         */
+        const std::vector<std::string> &datasetNames() const;
+        /*! \brief
+         * Returns a pointer to the data set \p index.
+         *
+         * \param[in] index  Data set to query for.
+         * \returns   A pointer to the data set, or NULL if \p index is not
+         *      valid.
+         *
+         * The return value is not const to allow callers to add modules to the
+         * data sets. However, the AbstractAnalysisData interface does not
+         * provide any means to alter the data, so the module does not need to
+         * care about external modifications.
+         */
+        AbstractAnalysisData *datasetFromIndex(int index) const;
+        /*! \brief
+         * Returns a pointer to the data set with name \p name
+         *
+         * \param[in] name  Data set to query for.
+         * \returns   A pointer to the data set, or NULL if \p name is not
+         *      recognized.
+         *
+         * The return value is not const to allow callers to add modules to the
+         * data sets. However, the AbstractAnalysisData interface does not
+         * provide any means to alter the data, so the module does not need to
+         * care about external modifications.
+         */
+        AbstractAnalysisData *datasetFromName(const char *name) const;
+
+    protected:
+        //! Initializes the dataset registration mechanism.
+        TrajectoryAnalysisModule();
+
+        /*! \brief
+         * Registers a dataset that exports data.
+         */
+        void registerBasicDataset(AbstractAnalysisData *data, const char *name);
+        /*! \brief
+         * Registers a parallelized dataset that exports data.
+         */
+        void registerAnalysisDataset(AnalysisData *data, const char *name);
+
+    private:
+        class Impl;
+
+        Impl                   *_impl;
+
+        /*! \brief
+         * Needed to access the registered analysis data sets.
+         */
+        friend class TrajectoryAnalysisModuleData;
+
+        // Disallow copy and assign.
+        TrajectoryAnalysisModule(const TrajectoryAnalysisModule &);
+        void operator =(const TrajectoryAnalysisModule &);
+};
+
+} // namespace gmx
+
+#endif
diff --git a/src/gromacs/trajectoryanalysis/analysissettings-impl.h b/src/gromacs/trajectoryanalysis/analysissettings-impl.h
new file mode 100644 (file)
index 0000000..5c9cfad
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * Declaration of TrajanaModule and integrally related classes.
+ */
+#ifndef GMX_TRAJECTORYANALYSIS_ANALYSISSETTINGS_IMPL_H
+#define GMX_TRAJECTORYANALYSIS_ANALYSISSETTINGS_IMPL_H
+
+#include "analysissettings.h"
+
+namespace gmx
+{
+
+class TrajectoryAnalysisSettings::Impl
+{
+    public:
+        Impl() : flags(0), frflags(0), bRmPBC(true), bPBC(true) {}
+
+        unsigned long        flags;
+        int                  frflags;
+
+        bool                 bRmPBC;
+        bool                 bPBC;
+};
+
+} // namespace gmx
+
+#endif
diff --git a/src/gromacs/trajectoryanalysis/analysissettings.cpp b/src/gromacs/trajectoryanalysis/analysissettings.cpp
new file mode 100644 (file)
index 0000000..953c4ec
--- /dev/null
@@ -0,0 +1,194 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * Implements TrajectoryAnalysisSettings..
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <smalloc.h>
+#include <statutil.h>
+#include <vec.h>
+
+#include "gromacs/fatalerror/fatalerror.h"
+#include "gromacs/trajectoryanalysis/analysissettings.h"
+
+#include "analysissettings-impl.h"
+
+namespace gmx
+{
+
+
+/********************************************************************
+ * TrajectoryAnalysisSettings
+ */
+
+TrajectoryAnalysisSettings::TrajectoryAnalysisSettings()
+    : _impl(new Impl)
+{
+    _impl->frflags |= TRX_NEED_X;
+}
+
+
+TrajectoryAnalysisSettings::~TrajectoryAnalysisSettings()
+{
+    delete _impl;
+}
+
+
+unsigned long
+TrajectoryAnalysisSettings::flags() const
+{
+    return _impl->flags;
+}
+
+
+bool
+TrajectoryAnalysisSettings::hasFlag(unsigned long flag) const
+{
+    return _impl->flags & flag;
+}
+
+
+bool
+TrajectoryAnalysisSettings::hasPBC() const
+{
+    return _impl->bPBC;
+}
+
+
+bool
+TrajectoryAnalysisSettings::hasRmPBC() const
+{
+    return _impl->bRmPBC;
+}
+
+
+int
+TrajectoryAnalysisSettings::frflags() const
+{
+    return _impl->frflags;
+}
+
+
+int
+TrajectoryAnalysisSettings::setFlags(unsigned long flags)
+{
+    _impl->flags = flags;
+    return 0;
+}
+
+
+int
+TrajectoryAnalysisSettings::setFlag(unsigned long flag, bool bSet)
+{
+    if (bSet)
+    {
+        _impl->flags |= flag;
+    }
+    else
+    {
+        _impl->flags &= ~flag;
+    }
+    return 0;
+}
+
+
+int
+TrajectoryAnalysisSettings::setPBC(bool bPBC)
+{
+    _impl->bPBC = bPBC;
+    return 0;
+}
+
+
+int
+TrajectoryAnalysisSettings::setRmPBC(bool bRmPBC)
+{
+    _impl->bRmPBC = bRmPBC;
+    return 0;
+}
+
+
+int
+TrajectoryAnalysisSettings::setFrameFlags(int frflags)
+{
+    _impl->frflags = frflags;
+    return 0;
+}
+
+
+/********************************************************************
+ * TopologyInformation
+ */
+
+TopologyInformation::TopologyInformation()
+    : _top(NULL), _bTop(false), _xtop(NULL), _ePBC(-1)
+{
+    clear_mat(_boxtop);
+}
+
+TopologyInformation::~TopologyInformation()
+{
+    if (_top)
+    {
+        done_top(_top);
+        sfree(_top);
+    }
+    sfree(_xtop);
+}
+
+int
+TopologyInformation::getTopologyConf(rvec **x, matrix box) const
+{
+    if (box)
+    {
+        copy_mat(const_cast<rvec *>(_boxtop), box);
+    }
+    if (x)
+    {
+        if (!_xtop)
+        {
+            *x = NULL;
+            GMX_ERROR(eeInvalidValue,
+                      "Topology coordinates requested without setting efUseTopX");
+            return -1;
+        }
+        *x = _xtop;
+    }
+    return 0;
+}
+
+} // namespace gmx
diff --git a/src/gromacs/trajectoryanalysis/analysissettings.h b/src/gromacs/trajectoryanalysis/analysissettings.h
new file mode 100644 (file)
index 0000000..97c6c2d
--- /dev/null
@@ -0,0 +1,263 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \file
+ * \brief
+ * Declaration of TrajanaModule and integrally related classes.
+ */
+#ifndef GMX_TRAJECTORYANALYSIS_ANALYSISSETTINGS_H
+#define GMX_TRAJECTORYANALYSIS_ANALYSISSETTINGS_H
+
+#include "../legacyheaders/typedefs.h"
+
+namespace gmx
+{
+
+class Options;
+class TrajectoryAnalysisRunnerCommon;
+
+/*! \brief
+ * Trajectory analysis module configuration object.
+ *
+ * This class is used by trajectory analysis modules to inform the caller
+ * about the requirements they have on the input (e.g., whether a topology is
+ * required, or whether PBC removal makes sense). It is also used to pass
+ * similar information back to the analysis module after parsing user input.
+ *
+ * Having this functionality as a separate class makes the TrajanaModule
+ * interface much cleaner, and also reduces the need to change existing code
+ * when new options are added.
+ *
+ * The class name is not the best possible, as the class is also used to pass
+ * topology information into trajectory analysis modules.
+ */
+class TrajectoryAnalysisSettings
+{
+    public:
+        //! Recognized flags.
+        enum {
+            /*! \brief
+             * Forces loading of a topology file.
+             *
+             * If this flag is not specified, the topology file is loaded only
+             * if it is provided on the command line explicitly.
+             *
+             * \see topology(), hasFullTopology()
+             */
+            efRequireTop     = 1<<0,
+            /*! \brief
+             * Requests topology coordinates.
+             *
+             * If this flag is specified, the coordinates loaded from the
+             * topology can be accessed with getTopologyConf().
+             *
+             * \see getTopologyConf()
+             */
+            efUseTopX        = 1<<1,
+            /*! \brief
+             * Disallows the user from changing PBC handling.
+             *
+             * If this option is not specified, the analysis module (see
+             * TrajanaModule::analyzeFrame()) may be passed a NULL PBC
+             * structure, and it should be able to handle such a situation.
+             */
+            efNoUserPBC      = 1<<4,
+            /*! \brief
+             * Disallows the user from changing PBC removal.
+             */
+            efNoUserRmPBC    = 1<<5,
+            /*! \brief
+             * Requests dumps of parsed and compiled selection trees.
+             *
+             * This flag is used by internal debugging tools to request
+             * the selection trees dumping to stderr.
+             */
+            efDebugSelection = 1<<16,
+        };
+
+        TrajectoryAnalysisSettings();
+        ~TrajectoryAnalysisSettings();
+
+        //! Returns the currently set flags.
+        unsigned long flags() const;
+        bool hasFlag(unsigned long flag) const;
+        /*! \brief
+         * Returns whether PBC should be used.
+         *
+         * Returns the value set with setPBC(). TrajanaModule subcalees can
+         * access the user-provided value TrajanaModule::initParamsDone() (or
+         * at any point after that), as long as the value has not been replaced
+         * with another call to setPBC().
+         */
+        bool hasPBC() const;
+        /*! \brief
+         * Returns whether molecules should be made whole.
+         *
+         * See hasPBC() for information on accessing or overriding the
+         * user-provided value.
+         */
+        bool hasRmPBC() const;
+        //! Returns the currently set frame flags.
+        int frflags() const;
+
+        /*! \brief
+         * Sets flags.
+         *
+         * Overrides any earlier set flags.
+         * By default, no flags are set.
+         */
+        int setFlags(unsigned long flags);
+        //! Sets or clears an individual flag.
+        int setFlag(unsigned long flag, bool bSet = true);
+        /*! \brief
+         * Sets whether PBC are used.
+         *
+         * \param[in]  bPBC   TRUE if PBC should be used.
+         * \returns    0 on success.
+         *
+         * If called in TrajanaModule::initParams(), this function sets the
+         * default for whether PBC are used in the analysis.
+         * If \ref efNoUserPBC is not set, a command-line option is provided
+         * for the user to override the default value.
+         * If called later, it overrides the setting provided by the user or an
+         * earlier call.
+         *
+         * If this function is not called, the default is to use PBC.
+         *
+         * If PBC are not used, the \p pbc pointer passed to
+         * TrajanaModule::analyzeFrame() is NULL.
+         * The value of the flag can also be accessed with hasPBC().
+         *
+         * \see \ref efNoUserPBC
+         */
+        int setPBC(bool bPBC);
+        /*! \brief
+         * Sets whether molecules are made whole.
+         *
+         * \param[in]     bRmPBC TRUE if molecules should be made whole.
+         * \returns       0 on success.
+         *
+         * If called in TrajanaModule::initParams(), this function sets the
+         * default for whether molecules are made whole.
+         * If \ref efNoUserRmPBC is not set, a command-line option is provided
+         * for the user to override the default value.
+         * If called later, it overrides the setting provided by the user or an
+         * earlier call.
+         *
+         * If this function is not called, the default is to make molecules
+         * whole.
+         *
+         * The main use of this function is to call it with \c false if your
+         * analysis program does not require whole molecules as this can
+         * increase the performance.
+         * In such a case, you can also specify \ref efNoUserRmPBC to not to
+         * confuse the user with an option that would only slow the program
+         * down.
+         *
+         * \see \ref efNoUserRmPBC
+         */
+        int setRmPBC(bool bRmPBC);
+        /*! \brief
+         * Sets flags that determine what to read from the trajectory.
+         *
+         * \param[in]     frflags Flags for what to read from the trajectory file.
+         * \returns       0 on success, an error code on error.
+         *
+         * If this function is not called, the flags default to TRX_NEED_X.
+         * If the analysis module needs some other information (velocities,
+         * forces), it can call this function to load additional information
+         * from the trajectory.
+         */
+        int setFrameFlags(int frflags);
+
+    private:
+        class Impl;
+
+        Impl                   *_impl;
+
+        // Disallow copy and assign.
+        TrajectoryAnalysisSettings(const TrajectoryAnalysisSettings &);
+        void operator =(const TrajectoryAnalysisSettings &);
+
+        friend class TrajectoryAnalysisRunnerCommon;
+};
+
+class TopologyInformation
+{
+    public:
+        //! Returns true if a topology file was loaded.
+        bool hasTopology() const { return _top != NULL; }
+        //! Returns true if a full topology file was loaded.
+        bool hasFullTopology() const { return _bTop; }
+        //! Returns the loaded topology, or NULL if not loaded.
+        t_topology *topology() const { return _top; }
+        //! Returns the ePBC field from the topology.
+        int ePBC() const { return _ePBC; }
+        /*! \brief
+         * Gets the configuration from the topology.
+         *
+         * \param[out] x     Topology coordinate pointer to initialize.
+         *      (can be NULL, in which case it is not used).
+         * \param[out] box   Box size from the topology file
+         *      (can be NULL, in which case it is not used).
+         * \returns    0 on success, a non-zero error code on error.
+         *
+         * If \ref efUseTopX has not been specified, the \p x parameter should
+         * be NULL.
+         *
+         * The pointer returned in \p *x should not be freed.
+         */
+        int getTopologyConf(rvec **x, matrix box) const;
+
+    private:
+        TopologyInformation();
+        ~TopologyInformation();
+
+        //! The topology structure, or \p NULL if no topology loaded.
+        t_topology          *_top;
+        //! TRUE if full tpx file was loaded, FALSE otherwise.
+        bool                 _bTop;
+        //! Coordinates from the topology (can be NULL).
+        rvec                *_xtop;
+        //! The box loaded from the topology file.
+        matrix               _boxtop;
+        //! The ePBC field loaded from the topology file.
+        int                  _ePBC;
+
+        // Disallow copy and assign.
+        TopologyInformation(const TopologyInformation &);
+        void operator =(const TopologyInformation &);
+
+        friend class TrajectoryAnalysisRunnerCommon;
+};
+
+} // namespace gmx
+
+#endif
diff --git a/src/gromacs/trajectoryanalysis/cmdlinerunner.cpp b/src/gromacs/trajectoryanalysis/cmdlinerunner.cpp
new file mode 100644 (file)
index 0000000..cacb423
--- /dev/null
@@ -0,0 +1,351 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * Implements gmx::TrajectoryAnalysisCommandLineRunner.
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <copyrite.h>
+#include <pbc.h>
+#include <rmpbc.h>
+#include <statutil.h>
+
+#include "gromacs/errorreporting/standarderrorreporter.h"
+#include "gromacs/fatalerror/fatalerror.h"
+#include "gromacs/options/asciihelpwriter.h"
+#include "gromacs/options/cmdlineparser.h"
+#include "gromacs/options/globalproperties.h"
+#include "gromacs/options/options.h"
+#include "gromacs/selection/selectioncollection.h"
+#include "gromacs/trajectoryanalysis/analysismodule.h"
+#include "gromacs/trajectoryanalysis/analysissettings.h"
+#include "gromacs/trajectoryanalysis/cmdlinerunner.h"
+#include "gromacs/trajectoryanalysis/runnercommon.h"
+
+namespace gmx
+{
+
+/********************************************************************
+ * TrajectoryAnalysisCommandLineRunner::Impl
+ */
+
+class TrajectoryAnalysisCommandLineRunner::Impl
+{
+    public:
+        Impl(TrajectoryAnalysisModule *module);
+        ~Impl();
+
+        void printHelp(const Options &options,
+                       const TrajectoryAnalysisRunnerCommon &common);
+        int parseOptions(TrajectoryAnalysisSettings *settings,
+                         TrajectoryAnalysisRunnerCommon *common,
+                         SelectionCollection *selections,
+                         Options *options,
+                         int *argc, char *argv[]);
+
+        TrajectoryAnalysisModule *_module;
+        int                     _debugLevel;
+};
+
+
+TrajectoryAnalysisCommandLineRunner::Impl::Impl(
+        TrajectoryAnalysisModule *module)
+    : _module(module), _debugLevel(0)
+{
+}
+
+
+TrajectoryAnalysisCommandLineRunner::Impl::~Impl()
+{
+    delete _module;
+}
+
+
+void
+TrajectoryAnalysisCommandLineRunner::Impl::printHelp(
+        const Options &options,
+        const TrajectoryAnalysisRunnerCommon &common)
+{
+    TrajectoryAnalysisRunnerCommon::HelpFlags flags = common.helpFlags();
+    if (flags != 0)
+    {
+        AsciiHelpWriter(options)
+            .setShowDescriptions(flags & TrajectoryAnalysisRunnerCommon::efHelpShowDescriptions)
+            .setShowHidden(flags & TrajectoryAnalysisRunnerCommon::efHelpShowHidden)
+            .writeHelp(stderr);
+    }
+}
+
+
+int
+TrajectoryAnalysisCommandLineRunner::Impl::parseOptions(
+        TrajectoryAnalysisSettings *settings,
+        TrajectoryAnalysisRunnerCommon *common,
+        SelectionCollection *selections,
+        Options *options,
+        int *argc, char *argv[])
+{
+    StandardErrorReporter  errors;
+    int rc;
+
+    Options *moduleOptions = _module->initOptions(settings);
+    if (moduleOptions == NULL)
+    {
+        GMX_ERROR(eeOutOfMemory,
+                  "Could not allocate memory for option storage");
+    }
+
+    Options *commonOptions = common->initOptions();
+    if (moduleOptions == NULL)
+    {
+        GMX_ERROR(eeOutOfMemory,
+                  "Could not allocate memory for option storage");
+    }
+
+    Options *selectionOptions = selections->initOptions();
+    if (selectionOptions == NULL)
+    {
+        GMX_ERROR(eeOutOfMemory,
+                  "Could not allocate memory for option storage");
+    }
+
+    options->addSubSection(commonOptions);
+    options->addSubSection(selectionOptions);
+    options->addSubSection(moduleOptions);
+
+    options->globalProperties().setSelectionCollection(selections);
+    commonOptions->addDefaultOptions();
+
+    {
+        CommandLineParser  parser(options, &errors);
+        rc = parser.parse(argc, argv);
+        printHelp(*options, *common);
+        if (rc != 0)
+        {
+            GMX_ERROR(rc, "Command-line option parsing failed, "
+                          "see higher up for detailed error messages");
+        }
+        rc = options->finish(&errors);
+        if (rc != 0)
+        {
+            GMX_ERROR(rc, "Command-line option parsing failed, "
+                          "see higher up for detailed error messages");
+        }
+    }
+
+    rc = common->initOptionsDone();
+    if (rc != 0)
+    {
+        return rc;
+    }
+    rc = _module->initOptionsDone(settings);
+    if (rc != 0)
+    {
+        return rc;
+    }
+
+    rc = common->initIndexGroups(selections);
+    if (rc != 0)
+    {
+        return rc;
+    }
+
+    // TODO: Check whether the input is a pipe.
+    bool bInteractive = true;
+    rc = selections->parseRequestedFromStdin(bInteractive, &errors);
+    common->doneIndexGroups(selections);
+    return rc;
+}
+
+
+/********************************************************************
+ * TrajectoryAnalysisCommandLineRunner
+ */
+
+TrajectoryAnalysisCommandLineRunner::TrajectoryAnalysisCommandLineRunner(
+        TrajectoryAnalysisModule *module)
+    : _impl(new Impl(module))
+{
+}
+
+
+TrajectoryAnalysisCommandLineRunner::~TrajectoryAnalysisCommandLineRunner()
+{
+    delete _impl;
+}
+
+
+void
+TrajectoryAnalysisCommandLineRunner::setSelectionDebugLevel(int debuglevel)
+{
+    _impl->_debugLevel = 1;
+}
+
+
+int
+TrajectoryAnalysisCommandLineRunner::run(int argc, char *argv[])
+{
+    TrajectoryAnalysisModule *module = _impl->_module;
+    int                       rc;
+
+    CopyRight(stderr, argv[0]);
+
+    SelectionCollection  selections(NULL);
+    rc = selections.init();
+    if (rc != 0)
+    {
+        return rc;
+    }
+    selections.setDebugLevel(_impl->_debugLevel);
+
+    TrajectoryAnalysisSettings  settings;
+    TrajectoryAnalysisRunnerCommon  common(&settings);
+
+    Options  options(NULL, NULL);
+    rc = _impl->parseOptions(&settings, &common, &selections, &options,
+                             &argc, argv);
+    if (rc != 0)
+    {
+        return rc;
+    }
+
+    rc = common.initTopology(&selections);
+    if (rc != 0)
+    {
+        return rc;
+    }
+    rc = selections.compile();
+    if (rc != 0)
+    {
+        return rc;
+    }
+
+    const TopologyInformation &topology = common.topologyInformation();
+    rc = module->initAnalysis(topology);
+    if (rc != 0)
+    {
+        return rc;
+    }
+
+    // Load first frame.
+    rc = common.initFirstFrame();
+    if (rc != 0)
+    {
+        return rc;
+    }
+    rc = module->initAfterFirstFrame(common.frame());
+    if (rc != 0)
+    {
+        return rc;
+    }
+
+    t_pbc  pbc;
+    t_pbc *ppbc = settings.hasPBC() ? &pbc : 0;
+
+    int nframes = 0;
+    TrajectoryAnalysisModuleData *pdata = NULL;
+    rc = module->startFrames(NULL, selections, &pdata);
+    if (rc != 0)
+    {
+        return rc;
+    }
+    do
+    {
+        rc = common.initFrame();
+        if (rc != 0)
+        {
+            return rc;
+        }
+        t_trxframe &frame = common.frame();
+        if (ppbc)
+        {
+            set_pbc(ppbc, topology.ePBC(), frame.box);
+        }
+
+        rc = selections.evaluate(&frame, ppbc);
+        if (rc != 0)
+        {
+            return rc;
+        }
+        rc = module->analyzeFrame(nframes, frame, ppbc, pdata);
+        if (rc != 0)
+        {
+            return rc;
+        }
+
+        nframes++;
+    }
+    while (common.readNextFrame());
+    rc = module->finishFrames(pdata);
+    if (rc != 0)
+    {
+        return rc;
+    }
+    if (pdata)
+    {
+        rc = pdata->finish();
+        delete pdata;
+        if (rc != 0)
+        {
+            return rc;
+        }
+    }
+
+    if (common.hasTrajectory())
+    {
+        fprintf(stderr, "Analyzed %d frames, last time %.3f\n",
+                nframes, common.frame().time);
+    }
+    else
+    {
+        fprintf(stderr, "Analyzed topology coordinates\n");
+    }
+
+    // Restore the maximal groups for dynamic selections.
+    rc = selections.evaluateFinal(nframes);
+    if (rc != 0)
+    {
+        return rc;
+    }
+
+    rc = module->finishAnalysis(nframes);
+    if (rc == 0)
+    {
+        rc = module->writeOutput();
+    }
+
+    return rc;
+}
+
+} // namespace gmx
diff --git a/src/gromacs/trajectoryanalysis/cmdlinerunner.h b/src/gromacs/trajectoryanalysis/cmdlinerunner.h
new file mode 100644 (file)
index 0000000..add7b09
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \file
+ * \brief
+ * Declares gmx::TrajectoryAnalysisCommandLineRunner.
+ */
+#ifndef GMX_TRAJECTORYANALYSIS_CMDLINERUNNER_H
+#define GMX_TRAJECTORYANALYSIS_CMDLINERUNNER_H
+
+namespace gmx
+{
+
+class TrajectoryAnalysisModule;
+
+/*! \brief
+ * Implementation class for cmd-line analysis tools.
+ *
+ * This class implements a command-line analysis program, given a
+ * TrajectoryAnalysisModule object. It takes care of converting cmd-line
+ * parameters to a form understood by the module, as well as parsing common
+ * options, initializing and evaluating selections, and looping over trajectory
+ * frames.
+ */
+class TrajectoryAnalysisCommandLineRunner
+{
+    public:
+        TrajectoryAnalysisCommandLineRunner(TrajectoryAnalysisModule *module);
+        ~TrajectoryAnalysisCommandLineRunner();
+
+        void setSelectionDebugLevel(int debuglevel);
+        int run(int argc, char *argv[]);
+
+    private:
+        class Impl;
+
+        Impl                *_impl;
+
+        // Disallow copy and assign.
+        TrajectoryAnalysisCommandLineRunner(const TrajectoryAnalysisCommandLineRunner &);
+        void operator =(const TrajectoryAnalysisCommandLineRunner &);
+};
+
+} // namespace gmx
+
+#endif
diff --git a/src/gromacs/trajectoryanalysis/modules.cpp b/src/gromacs/trajectoryanalysis/modules.cpp
new file mode 100644 (file)
index 0000000..bf04029
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * Implements gmx::createTrajectoryAnalysisModule().
+ *
+ * \ingroup module_trajectoryanalysis
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ */
+#include "gromacs/trajectoryanalysis/modules.h"
+
+#include <string2.h>
+
+#include "modules/distance.h"
+#include "modules/select.h"
+
+namespace
+{
+
+using namespace gmx::analysismodules;
+
+struct module_map_t
+{
+    const char                         *name;
+    gmx::TrajectoryAnalysisModule      *(*creator)(void);
+};
+
+const module_map_t modules[] =
+{
+    {gmx::analysismodules::distance, Distance::create},
+    {gmx::analysismodules::select,   Select::create},
+    {NULL,                           NULL},
+};
+
+} // namespace
+
+namespace gmx
+{
+
+TrajectoryAnalysisModule *createTrajectoryAnalysisModule(const char *name)
+{
+    size_t len = strlen(name);
+    int match_i = -1;
+
+    for (int i = 0; modules[i].name != NULL; ++i)
+    {
+        if (strncasecmp(name, modules[i].name, len) == 0)
+        {
+            if (strlen(modules[i].name) == len)
+            {
+                match_i = i;
+                break;
+            }
+            else if (match_i == -1)
+            {
+                match_i = i;
+            }
+            else
+            {
+                return NULL;
+            }
+        }
+    }
+    if (match_i != -1)
+    {
+        return modules[match_i].creator();
+    }
+    return NULL;
+}
+
+} // namespace gmx
diff --git a/src/gromacs/trajectoryanalysis/modules.h b/src/gromacs/trajectoryanalysis/modules.h
new file mode 100644 (file)
index 0000000..10786d2
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \file
+ * \brief
+ * Generic interface for creation of trajectory analysis modules.
+ *
+ * \inpublicapi
+ * \ingroup module_trajectoryanalysis
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ */
+#ifndef GMX_TRAJECTORYANALYSIS_MODULES_H
+#define GMX_TRAJECTORYANALYSIS_MODULES_H
+
+namespace gmx
+{
+
+class TrajectoryAnalysisModule;
+
+/*! \brief
+ * Creates a TrajectoryAnalysisModule object corresponding to a name.
+ *
+ * \param[in]  name  Name of the module to create (recognized names are
+ *      defined in modules.h).
+ * \returns  An allocated TrajectoryAnalysisModule object, or NULL if \p name
+ *      is not valid.
+ *
+ * In addition to recognizing exact matches on \p name, the function also
+ * identifies cases where \p name is a prefix of exactly one recognized name
+ * (exact matches always take precedence).
+ */
+TrajectoryAnalysisModule *createTrajectoryAnalysisModule(const char *name);
+
+namespace analysismodules
+{
+
+static const char * const distance = "distance";
+static const char * const select   = "select";
+
+} // namespace modules
+
+} // namespace gmx
+
+#endif
diff --git a/src/gromacs/trajectoryanalysis/modules/distance.cpp b/src/gromacs/trajectoryanalysis/modules/distance.cpp
new file mode 100644 (file)
index 0000000..e536625
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+#include "distance.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <pbc.h>
+#include <vec.h>
+
+#include "gromacs/analysisdata/analysisdata.h"
+#include "gromacs/analysisdata/modules/average.h"
+#include "gromacs/analysisdata/modules/plot.h"
+#include "gromacs/fatalerror/fatalerror.h"
+#include "gromacs/options/basicoptions.h"
+#include "gromacs/options/options.h"
+#include "gromacs/selection/selection.h"
+#include "gromacs/selection/selectionoption.h"
+
+namespace gmx
+{
+
+namespace analysismodules
+{
+
+Distance::Distance()
+    : _options("distance", "Distance calculation")
+{
+    _sel[0] = _sel[1] = NULL;
+}
+
+
+Distance::~Distance()
+{
+}
+
+
+Options *
+Distance::initOptions(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.",
+        NULL
+    };
+
+    _options.setDescription(desc);
+
+    _options.addOption(FileNameOption("o").filetype(eftPlot).writeOnly()
+                           .store(&_fnDist).defaultValue("dist"));
+    _options.addOption(SelectionOption("select").required().valueCount(2)
+                           .store(_sel));
+    return &_options;
+}
+
+
+int
+Distance::initAnalysis(const TopologyInformation & /*top*/)
+{
+    if (_sel[0]->posCount() != 1)
+    {
+        GMX_ERROR(eeInvalidInput,
+                  "The first selection does not define a single position");
+    }
+    if (_sel[1]->posCount() != 1)
+    {
+        GMX_ERROR(eeInvalidInput,
+                  "The second selection does not define a single position");
+    }
+    _data.setColumns(4);
+    registerAnalysisDataset(&_data, "distance");
+
+    _avem = new AnalysisDataAverageModule();
+    _data.addModule(_avem);
+
+    _plotm = new AnalysisDataPlotModule(_options);
+    _plotm->setFileName(_fnDist);
+    _plotm->setTitle("Distance");
+    _plotm->setXLabel("Time [ps]");
+    _plotm->setYLabel("Distance [nm]");
+    _data.addModule(_plotm);
+
+    return 0;
+}
+
+
+int
+Distance::analyzeFrame(int frnr, const t_trxframe &fr, t_pbc *pbc,
+                       TrajectoryAnalysisModuleData *pdata)
+{
+    AnalysisDataHandle *dh = pdata->dataHandle("distance");
+    Selection          *sel1 = pdata->parallelSelection(_sel[0]);
+    Selection          *sel2 = pdata->parallelSelection(_sel[1]);
+    rvec                dx;
+    real                r;
+
+    if (pbc != NULL)
+    {
+        pbc_dx(pbc, sel1->x(0), sel2->x(0), dx);
+    }
+    else
+    {
+        rvec_sub(sel1->x(0), sel2->x(0), dx);
+    }
+    r = norm(dx);
+    dh->startFrame(frnr, fr.time);
+    dh->addPoint(0, r);
+    dh->addPoints(1, 3, dx);
+    dh->finishFrame();
+    return 0;
+}
+
+
+int
+Distance::finishAnalysis(int /*nframes*/)
+{
+    return 0;
+}
+
+
+int
+Distance::writeOutput()
+{
+    const real *ave;
+
+    _avem->getData(0, NULL, &ave, NULL);
+    fprintf(stderr, "Average distance: %f\n", ave[0]);
+    fprintf(stderr, "Std. deviation:   %f\n", ave[1]);
+    return 0;
+}
+
+
+TrajectoryAnalysisModule *
+Distance::create()
+{
+    return new Distance();
+}
+
+} // namespace analysismodules
+
+} // namespace gmx
diff --git a/src/gromacs/trajectoryanalysis/modules/distance.h b/src/gromacs/trajectoryanalysis/modules/distance.h
new file mode 100644 (file)
index 0000000..689d73b
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+#ifndef GMX_TRAJANA_MODULES_DISTANCE_HPP
+#define GMX_TRAJANA_MODULES_DISTANCE_HPP
+
+#include <string>
+#include <vector>
+
+#include "../analysismodule.h"
+#include "gromacs/analysisdata/analysisdata.h"
+#include "gromacs/options/options.h"
+
+namespace gmx
+{
+
+class AnalysisDataAverageModule;
+class AnalysisDataPlotModule;
+class Selection;
+
+namespace analysismodules
+{
+
+class Distance : public TrajectoryAnalysisModule
+{
+    public:
+        Distance();
+        virtual ~Distance();
+
+        static TrajectoryAnalysisModule *create();
+
+        virtual Options *initOptions(TrajectoryAnalysisSettings *settings);
+        virtual int initAnalysis(const TopologyInformation &top);
+
+        virtual int analyzeFrame(int frnr, const t_trxframe &fr, t_pbc *pbc,
+                                 TrajectoryAnalysisModuleData *pdata);
+
+        virtual int finishAnalysis(int nframes);
+        virtual int writeOutput();
+
+    private:
+        Options                         _options;
+        std::string                     _fnDist;
+        Selection                      *_sel[2];
+        AnalysisData                    _data;
+        AnalysisDataAverageModule      *_avem;
+        AnalysisDataPlotModule         *_plotm;
+
+        // Copy and assign disallowed by base.
+};
+
+} // namespace analysismodules
+
+} // namespace gmx
+
+#endif
diff --git a/src/gromacs/trajectoryanalysis/modules/select.cpp b/src/gromacs/trajectoryanalysis/modules/select.cpp
new file mode 100644 (file)
index 0000000..2908ef7
--- /dev/null
@@ -0,0 +1,374 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+#include "select.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <index.h>
+#include <smalloc.h>
+#include <string2.h>
+
+#include "gromacs/analysisdata/analysisdata.h"
+#include "gromacs/analysisdata/modules/plot.h"
+#include "gromacs/fatalerror/fatalerror.h"
+#include "gromacs/options/basicoptions.h"
+#include "gromacs/options/options.h"
+#include "gromacs/selection/selection.h"
+#include "gromacs/selection/selectionoption.h"
+#include "gromacs/trajectoryanalysis/analysissettings.h"
+
+namespace gmx
+{
+
+namespace analysismodules
+{
+
+class Select::ModuleData : public TrajectoryAnalysisModuleData
+{
+    public:
+        ModuleData() : _mmap(NULL)
+        {
+        }
+
+        virtual ~ModuleData()
+        {
+            if (_mmap)
+            {
+                gmx_ana_indexmap_deinit(_mmap);
+                sfree(_mmap);
+            }
+        }
+
+        virtual int finish()
+        {
+            return finishDataHandles();
+        }
+
+        gmx_ana_indexmap_t  *_mmap;
+};
+
+
+Select::Select()
+    : _options("select", "Selection information"),
+      _bTotNorm(false), _bFracNorm(false), _bResInd(false),
+      _block(NULL), _gnames(NULL)
+{
+}
+
+
+Select::~Select()
+{
+    if (_block != NULL)
+    {
+        done_blocka(_block);
+        sfree(_block);
+    }
+}
+
+
+Options *
+Select::initOptions(TrajectoryAnalysisSettings *settings)
+{
+    static const char *const desc[] = {
+        "g_select",
+        NULL
+    };
+
+    _options.setDescription(desc);
+
+    _options.addOption(FileNameOption("os").filetype(eftPlot).writeOnly()
+                           .store(&_fnSize).defaultValue("size"));
+    _options.addOption(FileNameOption("oc").filetype(eftPlot).writeOnly()
+                           .store(&_fnFrac).defaultValue("frac"));
+    _options.addOption(FileNameOption("oi").filetype(eftPlot).writeOnly()
+                           .store(&_fnIndex).defaultValue("index"));
+    _options.addOption(FileNameOption("on").filetype(eftIndex).writeOnly()
+                           .store(&_fnNdx).defaultValue("index"));
+    _options.addOption(FileNameOption("om").filetype(eftPlot).writeOnly()
+                           .store(&_fnMask).defaultValue("mask"));
+
+    _options.addOption(SelectionOption("select").required().multiValue()
+                           .storeVector(&_sel));
+
+    _options.addOption(BooleanOption("norm").store(&_bTotNorm)
+        .description("Normalize by total number of positions with -os"));
+    _options.addOption(BooleanOption("cfnorm").store(&_bFracNorm)
+        .description("Normalize by covered fraction with -os"));
+    _options.addOption(BooleanOption("resind").store(&_bResInd)
+        .description("Write unique residue index instead of residue number"));
+
+    return &_options;
+}
+
+
+int
+Select::initAnalysis(const TopologyInformation &top)
+{
+    for (std::vector<Selection *>::const_iterator i = _sel.begin(); i != _sel.end(); ++i)
+    {
+        (*i)->initCoveredFraction(CFRAC_SOLIDANGLE);
+    }
+
+    _sdata.setColumns(_sel.size());
+    registerAnalysisDataset(&_sdata, "size");
+    snew(_totsize, _sel.size());
+    for (size_t g = 0; g < _sel.size(); ++g)
+    {
+        _totsize[g] = _bTotNorm ? _sel[g]->posCount() : 1;
+    }
+    if (!_fnSize.empty())
+    {
+        AnalysisDataPlotModule *plot = new AnalysisDataPlotModule(_options);
+        plot->setFileName(_fnSize);
+        plot->setTitle("Selection size");
+        plot->setXLabel("Time [ps]");
+        plot->setYLabel("Number");
+        _sdata.addModule(plot);
+    }
+
+    _cdata.setColumns(_sel.size());
+    registerAnalysisDataset(&_cdata, "cfrac");
+    if (!_fnFrac.empty())
+    {
+        AnalysisDataPlotModule *plot = new AnalysisDataPlotModule(_options);
+        plot->setFileName(_fnFrac);
+        plot->setTitle("Covered fraction");
+        plot->setXLabel("Time [ps]");
+        plot->setYLabel("Fraction");
+        plot->setYFormat(6, 4);
+        _cdata.addModule(plot);
+    }
+
+    _idata.setColumns(2, true);
+    registerAnalysisDataset(&_idata, "index");
+    if (!_fnIndex.empty())
+    {
+        AnalysisDataPlotModule *plot = new AnalysisDataPlotModule(_options);
+        plot->setFileName(_fnIndex);
+        plot->setPlainOutput(true);
+        plot->setYFormat(4, 0);
+        _idata.addModule(plot);
+    }
+
+    if (!_fnNdx.empty())
+    {
+        _block = new_blocka();
+        _gnames = NULL;
+        _modnames.reserve(_sel.size());
+        for (size_t g = 0; g < _sel.size(); ++g)
+        {
+            _modnames.push_back(_sel[g]->name());
+            size_t pos;
+            while ((pos = _modnames[g].find(' ')) != std::string::npos)
+            {
+                _modnames[g][pos] = '_';
+            }
+
+            if (!_sel[g]->isDynamic())
+            {
+                add_grp(_block, &_gnames, _sel[g]->posCount(),
+                        _sel[g]->mapIds(), _modnames[g].c_str());
+                _modnames[g].clear();
+            }
+        }
+    }
+
+    _mdata.setColumns(_sel[0]->posCount());
+    registerAnalysisDataset(&_mdata, "mask");
+    if (!_fnMask.empty())
+    {
+        if (_sel.size() > 1U)
+        {
+            fprintf(stderr, "WARNING: the mask (-om) will only be written for the first group\n");
+        }
+        if (!_sel[0]->isDynamic())
+        {
+            fprintf(stderr, "WARNING: will not write the mask (-om) for a static selection\n");
+        }
+        else
+        {
+            AnalysisDataPlotModule *plot = new AnalysisDataPlotModule(_options);
+            plot->setFileName(_fnMask);
+            plot->setTitle("Selection mask");
+            plot->setXLabel("Time [ps]");
+            plot->setYLabel("Occupancy");
+            plot->setYFormat(1, 0);
+            _mdata.addModule(plot);
+        }
+    }
+
+    _top = top.topology();
+
+    return 0;
+}
+
+
+int
+Select::startFrames(AnalysisDataParallelOptions opt,
+                    const SelectionCollection &selections,
+                    TrajectoryAnalysisModuleData **pdatap)
+{
+    ModuleData *pdata = new ModuleData();
+
+    *pdatap = pdata;
+    int rc = pdata->init(this, opt, selections);
+    if (rc != 0)
+    {
+        delete pdata;
+        *pdatap = NULL;
+        return rc;
+    }
+    snew(pdata->_mmap, 1);
+    gmx_ana_indexmap_init(pdata->_mmap, pdata->parallelSelection(_sel[0])->indexGroup(),
+                          _top, _sel[0]->type());
+    return 0;
+}
+
+
+int
+Select::analyzeFrame(int frnr, const t_trxframe &fr, t_pbc *pbc,
+                     TrajectoryAnalysisModuleData *pdata)
+{
+    ModuleData *d = static_cast<ModuleData *>(pdata);
+    AnalysisDataHandle *sdh = pdata->dataHandle("size");
+    AnalysisDataHandle *cdh = pdata->dataHandle("cfrac");
+    AnalysisDataHandle *idh = pdata->dataHandle("index");
+    AnalysisDataHandle *mdh = pdata->dataHandle("mask");
+    std::vector<Selection *> sel(pdata->parallelSelections(_sel));
+
+    if (sdh != NULL)
+    {
+        sdh->startFrame(frnr, fr.time);
+        for (size_t g = 0; g < sel.size(); ++g)
+        {
+            real normfac = _bFracNorm ? 1.0 / sel[g]->cfrac() : 1.0;
+            normfac /= _totsize[g];
+            sdh->addPoint(g, sel[g]->posCount() * normfac);
+        }
+        sdh->finishFrame();
+    }
+
+    if (cdh != NULL)
+    {
+        cdh->startFrame(frnr, fr.time);
+        for (size_t g = 0; g < sel.size(); ++g)
+        {
+            cdh->addPoint(g, sel[g]->cfrac());
+        }
+        cdh->finishFrame();
+    }
+
+    if (idh != NULL)
+    {
+        idh->startFrame(frnr, fr.time);
+        for (size_t g = 0; g < sel.size(); ++g)
+        {
+            idh->addPoint(0, sel[g]->posCount());
+            for (int i = 0; i < sel[g]->posCount(); ++i)
+            {
+                if (sel[g]->type() == INDEX_RES && !_bResInd)
+                {
+                    idh->addPoint(1, _top->atoms.resinfo[sel[g]->mapId(i)].nr);
+                }
+                else
+                {
+                    idh->addPoint(1, sel[g]->mapId(i) + 1);
+                }
+            }
+        }
+        idh->finishFrame();
+    }
+
+    /** TODO: This is not thread-safe */
+    if (_block != NULL)
+    {
+        for (size_t g = 0; g < sel.size(); ++g)
+        {
+            if (sel[g]->isDynamic())
+            {
+                char tbuf[50];
+                char *buf;
+
+                sprintf(tbuf, "_%.3f", fr.time);
+                snew(buf, _modnames[g].size() + strlen(tbuf) + 1);
+                strcpy(buf, _modnames[g].c_str());
+                strcat(buf, tbuf);
+                add_grp(_block, &_gnames, sel[g]->posCount(),
+                        sel[g]->mapIds(), buf);
+                sfree(buf);
+            }
+        }
+    }
+
+    if (mdh != NULL)
+    {
+        gmx_ana_indexmap_update(d->_mmap, sel[0]->indexGroup(), TRUE);
+        mdh->startFrame(frnr, fr.time);
+        for (int b = 0; b < d->_mmap->nr; ++b)
+        {
+            mdh->addPoint(b, d->_mmap->refid[b] == -1 ? 0 : 1);
+        }
+        mdh->finishFrame();
+    }
+    return 0;
+}
+
+
+int
+Select::finishAnalysis(int /*nframes*/)
+{
+    return 0;
+}
+
+
+int
+Select::writeOutput()
+{
+    if (!_fnNdx.empty())
+    {
+        write_index(_fnNdx.c_str(), _block, _gnames);
+    }
+
+    return 0;
+}
+
+
+TrajectoryAnalysisModule *
+Select::create()
+{
+    return new Select();
+}
+
+} // namespace analysismodules
+
+} // namespace gmx
diff --git a/src/gromacs/trajectoryanalysis/modules/select.h b/src/gromacs/trajectoryanalysis/modules/select.h
new file mode 100644 (file)
index 0000000..828847a
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+#ifndef GMX_TRAJECTORYANALYSIS_MODULES_SELECT_H
+#define GMX_TRAJECTORYANALYSIS_MODULES_SELECT_H
+
+#include <string>
+#include <vector>
+
+#include "../analysismodule.h"
+#include "gromacs/analysisdata/analysisdata.h"
+#include "gromacs/options/options.h"
+
+namespace gmx
+{
+
+class AnalysisDataPlotModule;
+class Selection;
+
+namespace analysismodules
+{
+
+class Select : public TrajectoryAnalysisModule
+{
+    public:
+        Select();
+        virtual ~Select();
+
+        static TrajectoryAnalysisModule *create();
+
+        virtual Options *initOptions(TrajectoryAnalysisSettings *settings);
+        virtual int initAnalysis(const TopologyInformation &top);
+
+        virtual int startFrames(AnalysisDataParallelOptions opt,
+                                const SelectionCollection &selections,
+                                TrajectoryAnalysisModuleData **pdatap);
+        virtual int analyzeFrame(int frnr, const t_trxframe &fr, t_pbc *pbc,
+                                 TrajectoryAnalysisModuleData *pdata);
+
+        virtual int finishAnalysis(int nframes);
+        virtual int writeOutput();
+
+    private:
+        class ModuleData;
+
+        Options                  _options;
+        std::vector<Selection *> _sel;
+
+        std::string              _fnSize;
+        std::string              _fnFrac;
+        std::string              _fnIndex;
+        std::string              _fnNdx;
+        std::string              _fnMask;
+        bool                     _bTotNorm;
+        bool                     _bFracNorm;
+        bool                     _bResInd;
+
+        t_topology              *_top;
+        int                     *_totsize;
+        AnalysisData             _sdata;
+        AnalysisData             _cdata;
+        AnalysisData             _idata;
+        AnalysisData             _mdata;
+        std::vector<std::string> _modnames;
+        t_blocka                *_block;
+        char                   **_gnames;
+};
+
+} // namespace analysismodules
+
+} // namespace gmx
+
+#endif
diff --git a/src/gromacs/trajectoryanalysis/runnercommon.cpp b/src/gromacs/trajectoryanalysis/runnercommon.cpp
new file mode 100644 (file)
index 0000000..038424e
--- /dev/null
@@ -0,0 +1,479 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * Implements gmx::TrajectoryAnalysisRunnerCommon.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <cassert>
+#include <string.h>
+
+#include <rmpbc.h>
+#include <smalloc.h>
+#include <statutil.h>
+#include <tpxio.h>
+#include <vec.h>
+
+#include "gromacs/fatalerror/fatalerror.h"
+#include "gromacs/options/basicoptions.h"
+#include "gromacs/options/globalproperties.h"
+#include "gromacs/options/options.h"
+#include "gromacs/selection/indexutil.h"
+#include "gromacs/selection/selectioncollection.h"
+#include "gromacs/trajectoryanalysis/analysissettings.h"
+#include "gromacs/trajectoryanalysis/runnercommon.h"
+
+#include "analysissettings-impl.h"
+
+namespace gmx
+{
+
+class TrajectoryAnalysisRunnerCommon::Impl
+{
+    public:
+        Impl(TrajectoryAnalysisSettings *settings);
+        ~Impl();
+
+        void finishTrajectory();
+
+        TrajectoryAnalysisSettings &_settings;
+        Options                 _options;
+        TopologyInformation     _topInfo;
+
+        bool                    _bHelp;
+        bool                    _bShowHidden;
+        bool                    _bQuiet;
+        //! Name of the trajectory file (empty if not provided).
+        std::string             _trjfile;
+        //! Name of the topology file (empty if no topology provided).
+        std::string             _topfile;
+        //! Name of the index file (empty if no index file provided).
+        std::string             _ndxfile;
+        double                  _startTime;
+        double                  _endTime;
+        double                  _deltaTime;
+
+        gmx_ana_indexgrps_t    *_grps;
+        bool                    _bTrajOpen;
+        //! The current frame, or \p NULL if no frame loaded yet.
+        t_trxframe          *fr;
+        gmx_rmpbc_t             _gpbc;
+        //! Used to store the status variable from read_first_frame().
+        t_trxstatus            *_status;
+        output_env_t            _oenv;
+};
+
+
+TrajectoryAnalysisRunnerCommon::Impl::Impl(TrajectoryAnalysisSettings *settings)
+    : _settings(*settings), _options("common", "Common analysis control"),
+      _bHelp(false), _bShowHidden(false), _bQuiet(false),
+      _startTime(0.0), _endTime(0.0), _deltaTime(0.0),
+      _grps(NULL),
+      _bTrajOpen(false), fr(NULL), _gpbc(NULL), _status(NULL), _oenv(NULL)
+{
+}
+
+
+TrajectoryAnalysisRunnerCommon::Impl::~Impl()
+{
+    if (_grps != NULL)
+    {
+        gmx_ana_indexgrps_free(_grps);
+    }
+    finishTrajectory();
+    if (fr)
+    {
+        // There doesn't seem to be a function for freeing frame data
+        sfree(fr->x);
+        sfree(fr->v);
+        sfree(fr->f);
+        sfree(fr);
+    }
+}
+
+
+void
+TrajectoryAnalysisRunnerCommon::Impl::finishTrajectory()
+{
+    if (_bTrajOpen)
+    {
+        close_trx(_status);
+        _bTrajOpen = false;
+    }
+    if (_gpbc != NULL)
+    {
+        gmx_rmpbc_done(_gpbc);
+        _gpbc = NULL;
+    }
+}
+
+/*********************************************************************
+ * TrajectoryAnalysisRunnerCommon
+ */
+
+TrajectoryAnalysisRunnerCommon::TrajectoryAnalysisRunnerCommon(
+        TrajectoryAnalysisSettings *settings)
+    : _impl(new Impl(settings))
+{
+}
+
+
+TrajectoryAnalysisRunnerCommon::~TrajectoryAnalysisRunnerCommon()
+{
+    delete _impl;
+}
+
+
+Options *
+TrajectoryAnalysisRunnerCommon::initOptions()
+{
+    TrajectoryAnalysisSettings &settings = _impl->_settings;
+    Options &options = _impl->_options;
+
+    // Add options for help.
+    options.addOption(BooleanOption("h").store(&_impl->_bHelp)
+                          .description("Print help and quit"));
+    options.addOption(BooleanOption("hidden").store(&_impl->_bShowHidden)
+                          .hidden()
+                          .description("Show hidden options"));
+    options.addOption(BooleanOption("quiet").store(&_impl->_bQuiet)
+                          .hidden()
+                          .description("Hide options in normal run"));
+
+    // Add common file name arguments.
+    options.addOption(FileNameOption("f")
+                          .filetype(eftTrajectory).readOnly()
+                          .store(&_impl->_trjfile)
+                          .description("Input trajectory"));
+    options.addOption(FileNameOption("s")
+                          .filetype(eftTopology).readOnly()
+                          .store(&_impl->_topfile)
+                          .description("Input topology"));
+    options.addOption(FileNameOption("n")
+                          .filetype(eftIndex).readOnly()
+                          .store(&_impl->_ndxfile)
+                          .description("Extra index groups"));
+
+    // Add options for trajectory time control.
+    options.addOption(DoubleOption("b").store(&_impl->_startTime).timeValue()
+                          .description("First frame (%t) to read from trajectory"));
+    options.addOption(DoubleOption("e").store(&_impl->_endTime).timeValue()
+                          .description("Last frame (%t) to read from trajectory"));
+    options.addOption(DoubleOption("dt").store(&_impl->_deltaTime).timeValue()
+                          .description("Only use frame if t MOD dt == first time (%t)"));
+
+    // Add common options for trajectory processing.
+    if (!settings.hasFlag(TrajectoryAnalysisSettings::efNoUserRmPBC))
+    {
+        options.addOption(BooleanOption("rmpbc").store(&settings._impl->bRmPBC)
+                              .description("Make molecules whole for each frame"));
+    }
+    if (!settings.hasFlag(TrajectoryAnalysisSettings::efNoUserPBC))
+    {
+        options.addOption(BooleanOption("pbc").store(&settings._impl->bPBC)
+                              .description("Use periodic boundary conditions for distance calculation"));
+    }
+
+    return &_impl->_options;
+}
+
+
+int
+TrajectoryAnalysisRunnerCommon::initOptionsDone()
+{
+    if (_impl->_bHelp)
+    {
+        // TODO: Proper error code for graceful exit
+        return -1;
+    }
+
+    if (_impl->_trjfile.empty() && _impl->_topfile.empty())
+    {
+        GMX_ERROR(eeInconsistentInput,
+                  "No trajectory or topology provided, nothing to do!");
+    }
+
+    if (_impl->_options.isSet("b"))
+        setTimeValue(TBEGIN, _impl->_startTime);
+    if (_impl->_options.isSet("e"))
+        setTimeValue(TEND, _impl->_endTime);
+    if (_impl->_options.isSet("dt"))
+        setTimeValue(TDELTA, _impl->_deltaTime);
+
+    return 0;
+}
+
+
+int
+TrajectoryAnalysisRunnerCommon::initIndexGroups(SelectionCollection *selections)
+{
+    int rc = 0;
+
+    if (_impl->_ndxfile.empty())
+    {
+        // TODO: Initialize default selections
+        selections->setIndexGroups(NULL);
+    }
+    else
+    {
+        gmx_ana_indexgrps_init(&_impl->_grps, NULL, _impl->_ndxfile.c_str());
+        rc = selections->setIndexGroups(_impl->_grps);
+    }
+    return rc;
+}
+
+
+void
+TrajectoryAnalysisRunnerCommon::doneIndexGroups(SelectionCollection *selections)
+{
+    if (_impl->_grps != NULL)
+    {
+        selections->setIndexGroups(NULL);
+        gmx_ana_indexgrps_free(_impl->_grps);
+        _impl->_grps = NULL;
+    }
+}
+
+
+int
+TrajectoryAnalysisRunnerCommon::initTopology(SelectionCollection *selections)
+{
+    const TrajectoryAnalysisSettings &settings = _impl->_settings;
+    bool bRequireTop
+        = settings.hasFlag(TrajectoryAnalysisSettings::efRequireTop)
+          || selections->requiresTopology();
+    if (bRequireTop && _impl->_topfile.empty())
+    {
+        GMX_ERROR(eeInconsistentInput,
+                  "No topology provided, but one is required for analysis");
+    }
+
+    // Load the topology if requested.
+    if (!_impl->_topfile.empty())
+    {
+        char  title[STRLEN];
+
+        snew(_impl->_topInfo._top, 1);
+        _impl->_topInfo._bTop = read_tps_conf(_impl->_topfile.c_str(), title,
+                _impl->_topInfo._top, &_impl->_topInfo._ePBC,
+                &_impl->_topInfo._xtop, NULL, _impl->_topInfo._boxtop, TRUE);
+        if (hasTrajectory()
+            && !settings.hasFlag(TrajectoryAnalysisSettings::efUseTopX))
+        {
+            sfree(_impl->_topInfo._xtop);
+            _impl->_topInfo._xtop = NULL;
+        }
+    }
+
+    // Read the first frame if we don't know the maximum number of atoms
+    // otherwise.
+    int  natoms = -1;
+    if (!_impl->_topInfo.hasTopology())
+    {
+        int rc = initFirstFrame();
+        if (rc != 0)
+        {
+            return rc;
+        }
+        natoms = _impl->fr->natoms;
+    }
+    int rc = selections->setTopology(_impl->_topInfo.topology(), natoms);
+    if (rc != 0)
+    {
+        return rc;
+    }
+
+    /*
+    if (_impl->bSelDump)
+    {
+        gmx_ana_poscalc_coll_print_tree(stderr, _impl->pcc);
+        fprintf(stderr, "\n");
+    }
+    */
+
+    return 0;
+}
+
+
+int
+TrajectoryAnalysisRunnerCommon::initFirstFrame()
+{
+    // Return if we have already initialized the trajectory.
+    if (_impl->fr)
+    {
+        return 0;
+    }
+    _impl->_oenv = _impl->_options.globalProperties().output_env();
+
+    int frflags = _impl->_settings.frflags();
+    frflags |= TRX_NEED_X;
+
+    snew(_impl->fr, 1);
+
+    const TopologyInformation &top = _impl->_topInfo;
+    if (hasTrajectory())
+    {
+        if (!read_first_frame(_impl->_oenv, &_impl->_status,
+                              _impl->_trjfile.c_str(), _impl->fr, frflags))
+        {
+            GMX_ERROR(eeFileNotFound,
+                      "Could not read coordinates from trajectory");
+        }
+        _impl->_bTrajOpen = true;
+
+        if (top.hasTopology() && _impl->fr->natoms > top.topology()->atoms.nr)
+        {
+            fatalErrorFormatted(eeInconsistentInput, GMX_ERRORLOC,
+                "Trajectory (%d atoms) does not match topology (%d atoms)",
+                _impl->fr->natoms, top.topology()->atoms.nr);
+            return eeInconsistentInput;
+        }
+        // Check index groups if they have been initialized based on the topology.
+        /*
+        if (top)
+        {
+            for (int i = 0; i < _impl->sel->nr(); ++i)
+            {
+                gmx_ana_index_check(_impl->sel->sel(i)->indexGroup(),
+                                    _impl->fr->natoms);
+            }
+        }
+        */
+    }
+    else
+    {
+        // Prepare a frame from topology information.
+        // TODO: Initialize more of the fields.
+        if (frflags & (TRX_NEED_V))
+        {
+            GMX_ERROR(eeNotImplemented,
+                      "Velocity reading from a topology not implemented");
+        }
+        if (frflags & (TRX_NEED_F))
+        {
+            GMX_ERROR(eeInvalidInput,
+                      "Forces cannot be read from a topology");
+        }
+        _impl->fr->flags  = frflags;
+        _impl->fr->natoms = top.topology()->atoms.nr;
+        _impl->fr->bX     = TRUE;
+        snew(_impl->fr->x, _impl->fr->natoms);
+        memcpy(_impl->fr->x, top._xtop,
+               sizeof(*_impl->fr->x) * _impl->fr->natoms);
+        _impl->fr->bBox   = TRUE;
+        copy_mat(const_cast<rvec *>(top._boxtop), _impl->fr->box);
+    }
+
+    set_trxframe_ePBC(_impl->fr, top.ePBC());
+    if (top.hasTopology() && _impl->_settings.hasRmPBC())
+    {
+        _impl->_gpbc = gmx_rmpbc_init(&top.topology()->idef, top.ePBC(),
+                                      _impl->fr->natoms, _impl->fr->box);
+    }
+
+    return 0;
+}
+
+
+bool
+TrajectoryAnalysisRunnerCommon::readNextFrame()
+{
+    bool bContinue = FALSE;
+    if (hasTrajectory())
+    {
+        bContinue = read_next_frame(_impl->_oenv, _impl->_status, _impl->fr);
+    }
+    if (!bContinue)
+    {
+        _impl->finishTrajectory();
+    }
+    return bContinue;
+}
+
+
+int
+TrajectoryAnalysisRunnerCommon::initFrame()
+{
+    if (_impl->_gpbc != NULL)
+    {
+        gmx_rmpbc_trxfr(_impl->_gpbc, _impl->fr);
+    }
+    return 0;
+}
+
+
+TrajectoryAnalysisRunnerCommon::HelpFlags
+TrajectoryAnalysisRunnerCommon::helpFlags() const
+{
+    HelpFlags flags = 0;
+
+    if (!_impl->_bQuiet)
+    {
+        flags |= efHelpShowOptions;
+        if (_impl->_bHelp)
+        {
+            flags |= efHelpShowDescriptions;
+        }
+        if (_impl->_bShowHidden)
+        {
+            flags |= efHelpShowHidden;
+        }
+    }
+    return flags;
+}
+
+bool
+TrajectoryAnalysisRunnerCommon::hasTrajectory() const
+{
+    return !_impl->_trjfile.empty();
+}
+
+
+const TopologyInformation &
+TrajectoryAnalysisRunnerCommon::topologyInformation() const
+{
+    return _impl->_topInfo;
+}
+
+
+t_trxframe &
+TrajectoryAnalysisRunnerCommon::frame() const
+{
+    assert(_impl->fr != NULL);
+    return *_impl->fr;
+}
+
+} // namespace gmx
diff --git a/src/gromacs/trajectoryanalysis/runnercommon.h b/src/gromacs/trajectoryanalysis/runnercommon.h
new file mode 100644 (file)
index 0000000..ca85654
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \file
+ * \brief
+ * Declaration of TrajanaModule and integrally related classes.
+ */
+#ifndef GMX_TRAJECTORYANALYSIS_RUNNERCOMMON_H
+#define GMX_TRAJECTORYANALYSIS_RUNNERCOMMON_H
+
+#include <typedefs.h>
+
+namespace gmx
+{
+
+class Options;
+class SelectionCollection;
+class TopologyInformation;
+class TrajectoryAnalysisSettings;
+
+class TrajectoryAnalysisRunnerCommon
+{
+    public:
+        enum HelpFlag
+        {
+            efHelpShowOptions           = 1<<0,
+            efHelpShowHidden            = 1<<1,
+            efHelpShowDescriptions      = 1<<2,
+        };
+        //! Combination of ::HelpFlag values.
+        typedef unsigned long HelpFlags;
+
+        explicit TrajectoryAnalysisRunnerCommon(TrajectoryAnalysisSettings *settings);
+        ~TrajectoryAnalysisRunnerCommon();
+
+        Options *initOptions();
+        int initOptionsDone();
+        int initIndexGroups(SelectionCollection *selections);
+        void doneIndexGroups(SelectionCollection *selections);
+        int initTopology(SelectionCollection *selections);
+        int initFirstFrame();
+        bool readNextFrame();
+        int initFrame();
+
+        //! Returns flags for help printing.
+        HelpFlags helpFlags() const;
+        //! Returns true if input data comes from a trajectory.
+        bool hasTrajectory() const;
+        const TopologyInformation &topologyInformation() const;
+        //! Returns the currently loaded frame.
+        t_trxframe &frame() const;
+
+    private:
+        class Impl;
+
+        Impl                *_impl;
+
+        // Disallow copy and assign.
+        TrajectoryAnalysisRunnerCommon(const TrajectoryAnalysisRunnerCommon &);
+        void operator =(const TrajectoryAnalysisRunnerCommon &);
+};
+
+} // namespace gmx
+
+#endif
diff --git a/src/gromacs/trajectoryanalysis/tests/CMakeLists.txt b/src/gromacs/trajectoryanalysis/tests/CMakeLists.txt
new file mode 100644 (file)
index 0000000..6e6a858
--- /dev/null
@@ -0,0 +1,2 @@
+add_executable(test_selection test_selection.cpp)
+target_link_libraries(test_selection libgromacs)
diff --git a/src/gromacs/trajectoryanalysis/tests/test_selection.cpp b/src/gromacs/trajectoryanalysis/tests/test_selection.cpp
new file mode 100644 (file)
index 0000000..143edd2
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief Testing/debugging tool for the selection engine.
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <vector>
+
+#include <gromacs/options/basicoptions.h>
+#include <gromacs/options/options.h>
+#include <gromacs/selection/selection.h>
+#include <gromacs/selection/selectionoption.h>
+#include <gromacs/trajectoryanalysis/analysismodule.h>
+#include <gromacs/trajectoryanalysis/analysissettings.h>
+#include <gromacs/trajectoryanalysis/cmdlinerunner.h>
+
+namespace gmx
+{
+
+class SelectionTester : public TrajectoryAnalysisModule
+{
+    public:
+        SelectionTester();
+        ~SelectionTester();
+
+        Options *initOptions(TrajectoryAnalysisSettings *settings);
+        int initAnalysis(const TopologyInformation &top);
+
+        int analyzeFrame(int frnr, const t_trxframe &fr, t_pbc *pbc,
+                         TrajectoryAnalysisModuleData *pdata);
+
+        int finishAnalysis(int nframes);
+        int writeOutput();
+
+    private:
+        void printSelections();
+
+        Options                  _options;
+        std::vector<Selection *> _selections;
+        int                      _nmaxind;
+};
+
+SelectionTester::SelectionTester()
+    : _options("testing", "Selection testing and debugging"),
+      _nmaxind(20)
+{
+}
+
+SelectionTester::~SelectionTester()
+{
+}
+
+void
+SelectionTester::printSelections()
+{
+    fprintf(stderr, "\nSelections:\n");
+    for (size_t g = 0; g < _selections.size(); ++g)
+    {
+        _selections[g]->printDebugInfo(_nmaxind);
+    }
+    fprintf(stderr, "\n");
+}
+
+Options *
+SelectionTester::initOptions(TrajectoryAnalysisSettings * /*settings*/)
+{
+    static const char *const desc[] = {
+        "This is a test program for selections.",
+        NULL
+    };
+
+    _options.setDescription(desc);
+
+    _options.addOption(SelectionOption("select").storeVector(&_selections)
+                           .required().multiValue().allowMultiple()
+                           .description("Selections to test"));
+    _options.addOption(IntegerOption("pmax").store(&_nmaxind)
+                           .description("Maximum number of indices to print in lists (-1 = print all)"));
+
+    return &_options;
+}
+
+int
+SelectionTester::initAnalysis(const TopologyInformation &/*top*/)
+{
+    printSelections();
+    return 0;
+}
+
+int
+SelectionTester::analyzeFrame(int /*frnr*/, const t_trxframe &/*fr*/, t_pbc * /*pbc*/,
+                              TrajectoryAnalysisModuleData * /*pdata*/)
+{
+    int                 g, i, n;
+
+    fprintf(stderr, "\n");
+    for (size_t g = 0; g < _selections.size(); ++g)
+    {
+        const Selection *sel = _selections[g];
+
+        gmx_ana_index_dump(sel->indexGroup(), g, _nmaxind);
+        fprintf(stderr, "  Positions (%d pcs):\n", sel->posCount());
+        n = sel->posCount();
+        if (_nmaxind >= 0 && n > _nmaxind)
+        {
+            n = _nmaxind;
+        }
+        for (i = 0; i < n; ++i)
+        {
+            fprintf(stderr, "    (%.2f,%.2f,%.2f) r=%d, m=%d, n=%d\n",
+                    sel->x(i)[XX], sel->x(i)[YY], sel->x(i)[ZZ],
+                    sel->refId(i), sel->mapId(i),
+                    sel->atomCount(i));
+        }
+        if (n < sel->posCount())
+        {
+            fprintf(stderr, "    ...\n");
+        }
+    }
+    fprintf(stderr, "\n");
+    return 0;
+}
+
+int
+SelectionTester::finishAnalysis(int /*nframes*/)
+{
+    printSelections();
+    return 0;
+}
+
+int
+SelectionTester::writeOutput()
+{
+    return 0;
+}
+
+}
+
+int
+main(int argc, char *argv[])
+{
+    gmx::TrajectoryAnalysisCommandLineRunner runner(new gmx::SelectionTester());
+    runner.setSelectionDebugLevel(1);
+    return runner.run(argc, argv);
+}
diff --git a/src/gromacs/utility/CMakeLists.txt b/src/gromacs/utility/CMakeLists.txt
new file mode 100644 (file)
index 0000000..530d78b
--- /dev/null
@@ -0,0 +1,5 @@
+set(UTILITY_PUBLIC_HEADERS
+    flags.h)
+install(FILES ${UTILITY_PUBLIC_HEADERS}
+        DESTINATION ${INCL_INSTALL_DIR}/gromacs/utility
+        COMPONENT development)
diff --git a/src/gromacs/utility/flags.h b/src/gromacs/utility/flags.h
new file mode 100644 (file)
index 0000000..33c6b4b
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \libinternal \file
+ * \brief
+ * Declares gmx::FlagsTemplate.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \inlibraryapi
+ */
+#ifndef GMX_UTILITY_FLAGS_H
+#define GMX_UTILITY_FLAGS_H
+
+namespace gmx
+{
+
+/*! \libinternal \brief
+ * Template class for typesafe handling of combination of flags.
+ *
+ * \tparam T An enumerated type that holds the possible single flags.
+ *
+ * \inlibraryapi
+ */
+template <typename T>
+class FlagsTemplate
+{
+    public:
+        //! Creates a flags object with no flags set.
+        FlagsTemplate() : _flags(0) {}
+        //! Creates a flags object from a single flag.
+        FlagsTemplate(T flag) : _flags(flag) {}
+
+        //! Returns true if the given flag is set.
+        bool test(T flag) const { return _flags & flag; }
+        //! Clears all flags.
+        void clearAll() { _flags = 0; }
+        //! Sets the given flag.
+        void set(T flag) { _flags |= flag; }
+        //! Clears the given flag.
+        void clear(T flag) { _flags &= ~flag; }
+        //! Sets or clears the given flag.
+        void set(T flag, bool bSet)
+        {
+            if (bSet)
+            {
+                set(flag);
+            }
+            else
+            {
+                clear(flag);
+            }
+        }
+
+        //! Combines flags from two flags objects.
+        FlagsTemplate<T> operator |(const FlagsTemplate<T> &other) const
+        {
+            return FlagsTemplate<T>(_flags | other._flags);
+        }
+        //! Combines flags from another flag object.
+        FlagsTemplate<T> &operator |=(const FlagsTemplate<T> &other)
+        {
+            _flags |= other._flags;
+            return *this;
+        }
+
+    private:
+        //! Creates a flags object with the given flags.
+        explicit FlagsTemplate(unsigned long flags) : _flags(flags) {}
+
+        unsigned long           _flags;
+};
+
+} // namespace gmx
+
+#endif
diff --git a/src/gromacs/version.c.cmakein b/src/gromacs/version.c.cmakein
new file mode 100644 (file)
index 0000000..c59f8b0
--- /dev/null
@@ -0,0 +1,4 @@
+#include "gromacs/gmxlib/version.h"
+const char _gmx_ver_string[] = "VERSION @GMX_PROJECT_VERSION_STR@";
+const char _gmx_full_git_hash[] = "@GMX_GIT_HEAD_HASH@";
+const char _gmx_central_base_hash[] = "@GMX_GIT_REMOTE_HASH@";
diff --git a/src/kernel/.cvsignore b/src/kernel/.cvsignore
deleted file mode 100644 (file)
index eccc86b..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-Makefile
-Makefile.in
-.deps
-.libs
\ No newline at end of file
index c8b084350e7b3971e61645f3434f15451f5b00e0..69ef8e7681b1890045a4939df9b74d75b5e3b735 100644 (file)
@@ -1,2 +1,11 @@
 .deps
 .libs
+g_luck
+g_protonate
+g_x2top
+gmxcheck
+gmxdump
+grompp
+mdrun
+pdb2gmx
+tpbconv
index 1e6cf9656bd92aeb85994c8feb53e0c1981721ec..e224d7f9e95490cf79a0f3870d0b28fa54f0fd34 100644 (file)
@@ -16,6 +16,7 @@ set(GMXPREPROCESS_SOURCES
     pgutil.c        
     readir.c        
     readpull.c      
+    readrot.c
     resall.c        
     sorting.c       
     specbond.c      
@@ -35,10 +36,11 @@ set(GMXPREPROCESS_SOURCES
 set(MDRUN_SOURCES 
     gctio.c    ionize.c runner.c
     do_gct.c     repl_ex.c  xutils.c
-    md.c         mdrun.c    genalg.c md_openmm.c)
+    md.c         mdrun.c    genalg.c membed.c
+    md_openmm.c)
 
 add_library(gmxpreprocess ${GMXPREPROCESS_SOURCES})
-target_link_libraries(gmxpreprocess md)
+target_link_libraries(gmxpreprocess libgromacs)
 set_target_properties(gmxpreprocess PROPERTIES OUTPUT_NAME "gmxpreprocess${GMX_LIBS_SUFFIX}" SOVERSION ${SOVERSION} INSTALL_NAME_DIR "${LIB_INSTALL_DIR}")
 
 
@@ -59,7 +61,7 @@ if(GMX_FAHCORE)
   add_library(fahcore ${MDRUN_SOURCES})
 else(GMX_FAHCORE)
 
-list(APPEND GMX_EXTRA_LIBRARIES gmxpreprocess md)
+list(APPEND GMX_EXTRA_LIBRARIES gmxpreprocess libgromacs)
 
 add_executable(grompp grompp.c)
 target_link_libraries(grompp ${GMX_EXTRA_LIBRARIES})
index 06bff7a2a68991d53c5f91ef9c6f3b881e40c3ab..7033012def36dd735e99f1b187239af567fc4087 100644 (file)
@@ -34,7 +34,7 @@ hizzie.c      hizzie.h        \
 pdb2top.c      \
 pgutil.c       pgutil.h        \
 readir.c       readir.h        \
-readpull.c     \
+readpull.c     readrot.c       \
 resall.c       \
 sorting.c      sorting.h       \
 specbond.c     specbond.h      \
@@ -58,7 +58,7 @@ bin_PROGRAMS = \
 g_x2top_SOURCES = g_x2top.c nm2type.c g_x2top.h
 
 mdrun_SOURCES = \
-       gctio.c         \
+       gctio.c         membed.c        membed.h    \
        ionize.c        ionize.h        xmdrun.h        \
        do_gct.c        repl_ex.c       repl_ex.h       \
        xutils.c        runner.c        md.c            mdrun.c         \
index 926614efb8ffd9fee2600019d21afb42357a0fca..17772bc9a9b9474871b45791c10a424724f2bfda 100644 (file)
@@ -1247,7 +1247,8 @@ int main (int argc, char *argv[])
     { efTOP, "-pp", "processed", ffOPTWR },
     { efTPX, "-o",  NULL,        ffWRITE },
     { efTRN, "-t",  NULL,        ffOPTRD },
-    { efEDR, "-e",  NULL,        ffOPTRD }
+    { efEDR, "-e",  NULL,        ffOPTRD },
+    { efTRN, "-ref","rotref",    ffOPTRW }
   };
 #define NFILE asize(fnm)
 
@@ -1526,6 +1527,13 @@ int main (int argc, char *argv[])
 
   if (ir->ePull != epullNO)
     set_pull_init(ir,sys,state.x,state.box,oenv,opts->pull_start);
+  
+  if (ir->bRot)
+  {
+      set_reference_positions(ir->rot,sys,state.x,state.box,
+                              opt2fn("-ref",NFILE,fnm),opt2bSet("-ref",NFILE,fnm),
+                              wi);
+  }
 
   /*  reset_multinr(sys); */
   
index 5a73798199d6a15e65ecb890565d4bba71106db5..b0a1e5a218edf68dde5f3909e6e3daddc48a8edf 100644 (file)
@@ -89,6 +89,7 @@
 #include "checkpoint.h"
 #include "mtop_util.h"
 #include "sighandler.h"
+#include "membed.h"
 
 #ifdef GMX_LIB_MPI
 #include <mpi.h>
@@ -1071,7 +1072,7 @@ double do_md(FILE *fplog,t_commrec *cr,int nfile,const t_filenm fnm[],
              t_mdatoms *mdatoms,
              t_nrnb *nrnb,gmx_wallcycle_t wcycle,
              gmx_edsam_t ed,t_forcerec *fr,
-             int repl_ex_nst,int repl_ex_seed,
+             int repl_ex_nst,int repl_ex_seed,gmx_membed_t *membed,
              real cpt_period,real max_hours,
              const char *deviceOptions,
              unsigned long Flags,
@@ -2719,6 +2720,9 @@ double do_md(FILE *fplog,t_commrec *cr,int nfile,const t_filenm fnm[],
         }
         
         /* #######  END SET VARIABLES FOR NEXT ITERATION ###### */
+
+        if ( (membed!=NULL) && (!bLastStep) )
+            rescale_membed(step_rel,membed,state_global->x);
         
         if (bRerunMD) 
         {
index 908fd03ff061c93aed2683e9052dc611a5746450..6043d8feba0d6958fac3e3be92ca948ff9c967b9 100644 (file)
@@ -90,6 +90,7 @@
 #include "genborn.h"
 #include "string2.h"
 #include "copyrite.h"
+#include "membed.h"
 
 #ifdef GMX_THREADS
 #include "tmpi.h"
@@ -209,6 +210,7 @@ double do_md_openmm(FILE *fplog,t_commrec *cr,int nfile,const t_filenm fnm[],
                     t_nrnb *nrnb,gmx_wallcycle_t wcycle,
                     gmx_edsam_t ed,t_forcerec *fr,
                     int repl_ex_nst,int repl_ex_seed,
+                    gmx_membed_t *membed,
                     real cpt_period,real max_hours,
                     const char *deviceOptions,
                     unsigned long Flags,
index b697c0f7acb3fc206d55d8121af0642cd6cc7cb2..60fc5ffeb1cfa45aeccf8c79ea5cd613d8b59c25 100644 (file)
@@ -47,6 +47,7 @@ double do_md_openmm(FILE *fplog,t_commrec *cr,int nfile,const t_filenm fnm[],
              t_nrnb *nrnb,gmx_wallcycle_t wcycle,
              gmx_edsam_t ed,t_forcerec *fr,
              int repl_ex_nst,int repl_ex_seed,
+             gmx_membed_t *membed,
              real cpt_period,real max_hours,
              const char *deviceOptions,
              unsigned long Flags,
index 895d03419ad40180c0bf0bda3461bc6e37f1f730..ed6db41ded10ef3fd1efc8b05b102283a7f6655e 100644 (file)
@@ -283,6 +283,11 @@ int main(int argc,char *argv[])
     "appropriate options have been given. Currently under",
     "investigation are: polarizability, and X-Ray bombardments.",
     "[PAR]",
+    "The option [TT]-membed[dd] does what used to be g_membed, i.e. embed",
+    "a protein into a membrane. The data file should contain the options",
+    "that where passed to g_membed before. The [TT]-mn[tt] and [TT]-mp[tt]",
+    "both apply to this as well.",
+    "[PAR]",
     "The option [TT]-pforce[tt] is useful when you suspect a simulation",
     "crashes due to too large forces. With this option coordinates and",
     "forces of atoms with a force larger than a certain value will",
@@ -370,8 +375,15 @@ int main(int argc,char *argv[])
     { 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 }
+    { efNDX, "-dn",     "dipole",   ffOPTWR },
+    { efDAT, "-membed", "membed",   ffOPTRD },
+    { efTOP, "-mp",     "membed",   ffOPTRD },
+    { efNDX, "-mn",     "membed",   ffOPTRD }
   };
 #define NFILE asize(fnm)
 
diff --git a/src/kernel/membed.c b/src/kernel/membed.c
new file mode 100644 (file)
index 0000000..039fabf
--- /dev/null
@@ -0,0 +1,1162 @@
+/*
+ * $Id: mdrun.c,v 1.139.2.9 2009/05/04 16:13:29 hess Exp $
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ *                        VERSION 3.2.0
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * 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.
+
+ * 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
+ */
+#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 "macros.h"
+#include "copyrite.h"
+#include "main.h"
+#include "futil.h"
+#include "edsam.h"
+#include "index.h"
+#include "physics.h"
+#include "names.h"
+#include "mtop_util.h"
+#include "tpxio.h"
+#include "string2.h"
+#include "membed.h"
+#include "pbc.h"
+#include "readinp.h"
+
+typedef struct {
+       int             id;
+       char    *name;
+       int     nr;
+       int     natoms;     /*nr of atoms per lipid*/
+       int     mol1;       /*id of the first lipid molecule*/
+       real    area;
+} lip_t;
+
+typedef struct {
+       char    *name;
+       t_block mem_at;
+       int             *mol_id;
+       int             nmol;
+       real    lip_area;
+       real    zmin;
+       real    zmax;
+       real    zmed;
+} mem_t;
+
+typedef struct {
+       int             *mol;
+       int             *block;
+       int     nr;
+} rm_t;
+
+int search_string(char *s,int ng,char ***gn)
+{
+       int i;
+
+       for(i=0; (i<ng); i++)
+               if (gmx_strcasecmp(s,*gn[i]) == 0)
+                       return i;
+
+       gmx_fatal(FARGS,"Group %s not found in indexfile.\nMaybe you have non-default groups in your mdp file, while not using the '-n' option of grompp.\nIn that case use the '-n' option.\n",s);
+
+       return -1;
+}
+
+int get_mol_id(int at,int nmblock,gmx_molblock_t *mblock, int *type, int *block)
+{
+       int mol_id=0;
+       int i;
+
+       for(i=0;i<nmblock;i++)
+       {
+               if(at<(mblock[i].nmol*mblock[i].natoms_mol))
+               {
+                       mol_id+=at/mblock[i].natoms_mol;
+                       *type = mblock[i].type;
+                       *block = i;
+                       return mol_id;
+               } else {
+                       at-= mblock[i].nmol*mblock[i].natoms_mol;
+                       mol_id+=mblock[i].nmol;
+               }
+       }
+
+       gmx_fatal(FARGS,"Something is wrong in mol ids, at %d, mol_id %d",at,mol_id);
+
+       return -1;
+}
+
+int get_block(int mol_id,int nmblock,gmx_molblock_t *mblock)
+{
+       int i;
+       int nmol=0;
+
+       for(i=0;i<nmblock;i++)
+       {
+               nmol+=mblock[i].nmol;
+               if(mol_id<nmol)
+                       return i;
+       }
+
+       gmx_fatal(FARGS,"mol_id %d larger than total number of molecules %d.\n",mol_id,nmol);
+
+       return -1;
+}
+
+int get_tpr_version(const char *infile)
+{
+       char    buf[STRLEN];
+       gmx_bool        bDouble;
+       int     precision,fver;
+        t_fileio *fio;
+
+       fio = open_tpx(infile,"r");
+       gmx_fio_checktype(fio);
+
+       precision = sizeof(real);
+
+       gmx_fio_do_string(fio,buf);
+       if (strncmp(buf,"VERSION",7))
+               gmx_fatal(FARGS,"Can not read file %s,\n"
+                               "             this file is from a Gromacs version which is older than 2.0\n"
+                               "             Make a new one with grompp or use a gro or pdb file, if possible",
+                               gmx_fio_getname(fio));
+       gmx_fio_do_int(fio,precision);
+       bDouble = (precision == sizeof(double));
+       if ((precision != sizeof(float)) && !bDouble)
+               gmx_fatal(FARGS,"Unknown precision in file %s: real is %d bytes "
+                               "instead of %d or %d",
+                               gmx_fio_getname(fio),precision,sizeof(float),sizeof(double));
+       gmx_fio_setprecision(fio,bDouble);
+       fprintf(stderr,"Reading file %s, %s (%s precision)\n",
+                       gmx_fio_getname(fio),buf,bDouble ? "double" : "single");
+
+       gmx_fio_do_int(fio,fver);
+
+       close_tpx(fio);
+
+       return fver;
+}
+
+int get_mtype_list(t_block *at, gmx_mtop_t *mtop, t_block *tlist)
+{
+       int i,j,nr,mol_id;
+        int type=0,block=0;
+       gmx_bool bNEW;
+
+       nr=0;
+       snew(tlist->index,at->nr);
+       for (i=0;i<at->nr;i++)
+       {
+               bNEW=TRUE;
+               mol_id = get_mol_id(at->index[i],mtop->nmolblock,mtop->molblock,&type,&block);
+               for(j=0;j<nr;j++)
+               {
+                       if(tlist->index[j]==type)
+                               bNEW=FALSE;
+               }
+               if(bNEW==TRUE)
+               {
+                       tlist->index[nr]=type;
+                       nr++;
+               }
+       }
+
+       srenew(tlist->index,nr);
+       return nr;
+}
+
+void check_types(t_block *ins_at,t_block *rest_at,gmx_mtop_t *mtop)
+{
+       t_block         *ins_mtype,*rest_mtype;
+       int                     i,j;
+
+       snew(ins_mtype,1);
+       snew(rest_mtype,1);
+    ins_mtype->nr  = get_mtype_list(ins_at , mtop, ins_mtype );
+    rest_mtype->nr = get_mtype_list(rest_at, mtop, rest_mtype);
+
+    for(i=0;i<ins_mtype->nr;i++)
+    {
+       for(j=0;j<rest_mtype->nr;j++)
+       {
+               if(ins_mtype->index[i]==rest_mtype->index[j])
+                       gmx_fatal(FARGS,"Moleculetype %s is found both in the group to insert and the rest of the system.\n"
+                                       "1. Your *.ndx and *.top do not match\n"
+                                       "2. You are inserting some molecules of type %s (for example xray-solvent), while\n"
+                                       "the same moleculetype is also used in the rest of the system (solvent box). Because\n"
+                                       "we need to exclude all interactions between the atoms in the group to\n"
+                                       "insert, the same moleculetype can not be used in both groups. Change the\n"
+                                       "moleculetype of the molecules %s in the inserted group. Do not forget to provide\n"
+                                       "an appropriate *.itp file",*(mtop->moltype[rest_mtype->index[j]].name),
+                                       *(mtop->moltype[rest_mtype->index[j]].name),*(mtop->moltype[rest_mtype->index[j]].name));
+       }
+    }
+
+    sfree(ins_mtype->index);
+    sfree(rest_mtype->index);
+    sfree(ins_mtype);
+    sfree(rest_mtype);
+}
+
+void get_input(const char *membed_input, real *xy_fac, real *xy_max, real *z_fac, real *z_max,
+               int *it_xy, int *it_z, real *probe_rad, int *low_up_rm, int *maxwarn, 
+               int *pieces, gmx_bool *bALLOW_ASYMMETRY)
+{
+    warninp_t wi;
+    t_inpfile *inp;
+    int       ninp;
+
+    wi = init_warning(TRUE,0);
+    
+    inp = read_inpfile(membed_input, &ninp, NULL, wi);
+    ITYPE ("nxy", *it_xy, 1000);
+    ITYPE ("nz", *it_z, 0);
+    RTYPE ("xyinit", *xy_fac, 0.5);
+    RTYPE ("xyend", *xy_max, 1.0);
+    RTYPE ("zinit", *z_fac, 1.0);
+    RTYPE ("zend", *z_max, 1.0);
+    RTYPE ("rad", *probe_rad, 0.22);
+    ITYPE ("ndiff", *low_up_rm, 0);
+    ITYPE ("maxwarn", *maxwarn, 0);
+    ITYPE ("pieces", *pieces, 1);
+    EETYPE("asymmetry", *bALLOW_ASYMMETRY, yesno_names);
+    write_inpfile(membed_input,ninp,inp,FALSE,wi);
+}
+
+int init_ins_at(t_block *ins_at,t_block *rest_at,t_state *state, pos_ins_t *pos_ins,gmx_groups_t *groups,int ins_grp_id, real xy_max)
+{
+       int i,gid,c=0;
+       real x,xmin,xmax,y,ymin,ymax,z,zmin,zmax;
+
+       snew(rest_at->index,state->natoms);
+
+       xmin=xmax=state->x[ins_at->index[0]][XX];
+       ymin=ymax=state->x[ins_at->index[0]][YY];
+       zmin=zmax=state->x[ins_at->index[0]][ZZ];
+
+       for(i=0;i<state->natoms;i++)
+       {
+               gid = groups->grpnr[egcFREEZE][i];
+               if(groups->grps[egcFREEZE].nm_ind[gid]==ins_grp_id)
+               {
+                       x=state->x[i][XX];
+                       if (x<xmin)                     xmin=x;
+                       if (x>xmax)                     xmax=x;
+                       y=state->x[i][YY];
+                       if (y<ymin)                             ymin=y;
+                       if (y>ymax)                             ymax=y;
+                       z=state->x[i][ZZ];
+                       if (z<zmin)                             zmin=z;
+                       if (z>zmax)                             zmax=z;
+               } else {
+                       rest_at->index[c]=i;
+                       c++;
+               }
+       }
+
+       rest_at->nr=c;
+       srenew(rest_at->index,c);
+
+       if(xy_max>1.000001)
+       {
+               pos_ins->xmin[XX]=xmin-((xmax-xmin)*xy_max-(xmax-xmin))/2;
+               pos_ins->xmin[YY]=ymin-((ymax-ymin)*xy_max-(ymax-ymin))/2;
+
+               pos_ins->xmax[XX]=xmax+((xmax-xmin)*xy_max-(xmax-xmin))/2;
+               pos_ins->xmax[YY]=ymax+((ymax-ymin)*xy_max-(ymax-ymin))/2;
+       } else {
+               pos_ins->xmin[XX]=xmin;
+               pos_ins->xmin[YY]=ymin;
+
+               pos_ins->xmax[XX]=xmax;
+               pos_ins->xmax[YY]=ymax;
+       }
+
+       /* 6.0 is estimated thickness of bilayer */
+       if( (zmax-zmin) < 6.0 )
+       {
+               pos_ins->xmin[ZZ]=zmin+(zmax-zmin)/2.0-3.0;
+               pos_ins->xmax[ZZ]=zmin+(zmax-zmin)/2.0+3.0;
+       } else {
+               pos_ins->xmin[ZZ]=zmin;
+               pos_ins->xmax[ZZ]=zmax;
+       }
+
+       return c;
+}
+
+real est_prot_area(pos_ins_t *pos_ins,rvec *r,t_block *ins_at, mem_t *mem_p)
+{
+       real x,y,dx=0.15,dy=0.15,area=0.0;
+       real add;
+       int c,at;
+
+       for(x=pos_ins->xmin[XX];x<pos_ins->xmax[XX];x+=dx)
+       {
+               for(y=pos_ins->xmin[YY];y<pos_ins->xmax[YY];y+=dy)
+               {
+                       c=0;
+                       add=0.0;
+                       do
+                       {
+                               at=ins_at->index[c];
+                               if ( (r[at][XX]>=x) && (r[at][XX]<x+dx) &&
+                                               (r[at][YY]>=y) && (r[at][YY]<y+dy) &&
+                                               (r[at][ZZ]>mem_p->zmin+1.0) && (r[at][ZZ]<mem_p->zmax-1.0) )
+                                       add=1.0;
+                               c++;
+                       } while ( (c<ins_at->nr) && (add<0.5) );
+                       area+=add;
+               }
+       }
+       area=area*dx*dy;
+
+       return area;
+}
+
+void init_lip(matrix box, gmx_mtop_t *mtop, lip_t *lip)
+{
+       int i;
+       real mem_area;
+       int mol1=0;
+
+       mem_area = box[XX][XX]*box[YY][YY]-box[XX][YY]*box[YY][XX];
+       for(i=0;i<mtop->nmolblock;i++)
+       {
+               if(mtop->molblock[i].type == lip->id)
+               {
+                       lip->nr=mtop->molblock[i].nmol;
+                       lip->natoms=mtop->molblock[i].natoms_mol;
+               }
+       }
+       lip->area=2.0*mem_area/(double)lip->nr;
+
+       for (i=0;i<lip->id;i++)
+               mol1+=mtop->molblock[i].nmol;
+       lip->mol1=mol1;
+}
+
+int init_mem_at(mem_t *mem_p, gmx_mtop_t *mtop, rvec *r, matrix box, pos_ins_t *pos_ins)
+{
+       int i,j,at,mol,nmol,nmolbox,count;
+       t_block *mem_a;
+       real z,zmin,zmax,mem_area;
+       gmx_bool bNew;
+       atom_id *mol_id;
+       int type=0,block=0;
+
+       nmol=count=0;
+       mem_a=&(mem_p->mem_at);
+       snew(mol_id,mem_a->nr);
+/*     snew(index,mem_a->nr); */
+       zmin=pos_ins->xmax[ZZ];
+       zmax=pos_ins->xmin[ZZ];
+       for(i=0;i<mem_a->nr;i++)
+       {
+               at=mem_a->index[i];
+               if(     (r[at][XX]>pos_ins->xmin[XX]) && (r[at][XX]<pos_ins->xmax[XX]) &&
+                       (r[at][YY]>pos_ins->xmin[YY]) && (r[at][YY]<pos_ins->xmax[YY]) &&
+                       (r[at][ZZ]>pos_ins->xmin[ZZ]) && (r[at][ZZ]<pos_ins->xmax[ZZ]) )
+               {
+                       mol = get_mol_id(at,mtop->nmolblock,mtop->molblock,&type,&block);
+
+                       bNew=TRUE;
+                       for(j=0;j<nmol;j++)
+                               if(mol == mol_id[j])
+                                       bNew=FALSE;
+
+                       if(bNew)
+                       {
+                               mol_id[nmol]=mol;
+                               nmol++;
+                       }
+
+                       z=r[at][ZZ];
+                       if(z<zmin)                                      zmin=z;
+                       if(z>zmax)                                      zmax=z;
+
+/*                     index[count]=at;*/
+                       count++;
+               }
+       }
+
+       mem_p->nmol=nmol;
+       srenew(mol_id,nmol);
+       mem_p->mol_id=mol_id;
+/*     srenew(index,count);*/
+/*     mem_p->mem_at.nr=count;*/
+/*     sfree(mem_p->mem_at.index);*/
+/*     mem_p->mem_at.index=index;*/
+
+       if((zmax-zmin)>(box[ZZ][ZZ]-0.5))
+               gmx_fatal(FARGS,"Something is wrong with your membrane. Max and min z values are %f and %f.\n"
+                               "Maybe your membrane is not centered in the box, but located at the box edge in the z-direction,\n"
+                               "so that one membrane is distributed over two periodic box images. Another possibility is that\n"
+                               "your water layer is not thick enough.\n",zmax,zmin);
+       mem_p->zmin=zmin;
+       mem_p->zmax=zmax;
+       mem_p->zmed=(zmax-zmin)/2+zmin;
+
+       /*number of membrane molecules in protein box*/
+       nmolbox = count/mtop->molblock[block].natoms_mol;
+       /*mem_area = box[XX][XX]*box[YY][YY]-box[XX][YY]*box[YY][XX];
+       mem_p->lip_area = 2.0*mem_area/(double)mem_p->nmol;*/
+       mem_area = (pos_ins->xmax[XX]-pos_ins->xmin[XX])*(pos_ins->xmax[YY]-pos_ins->xmin[YY]);
+       mem_p->lip_area = 2.0*mem_area/(double)nmolbox;
+
+       return mem_p->mem_at.nr;
+}
+
+void init_resize(t_block *ins_at,rvec *r_ins,pos_ins_t *pos_ins,mem_t *mem_p,rvec *r, gmx_bool bALLOW_ASYMMETRY)
+{
+       int i,j,at,c,outsidesum,gctr=0;
+    int idxsum=0;
+
+    /*sanity check*/
+    for (i=0;i<pos_ins->pieces;i++)
+          idxsum+=pos_ins->nidx[i];
+    if (idxsum!=ins_at->nr)
+          gmx_fatal(FARGS,"Piecewise sum of inserted atoms not same as size of group selected to insert.");
+
+    snew(pos_ins->geom_cent,pos_ins->pieces);
+    for (i=0;i<pos_ins->pieces;i++)
+    {
+       c=0;
+       outsidesum=0;
+       for(j=0;j<DIM;j++)
+               pos_ins->geom_cent[i][j]=0;
+
+       for(j=0;j<DIM;j++)
+               pos_ins->geom_cent[i][j]=0;
+       for (j=0;j<pos_ins->nidx[i];j++)
+       {
+               at=pos_ins->subindex[i][j];
+               copy_rvec(r[at],r_ins[gctr]);
+               if( (r_ins[gctr][ZZ]<mem_p->zmax) && (r_ins[gctr][ZZ]>mem_p->zmin) )
+               {
+                       rvec_inc(pos_ins->geom_cent[i],r_ins[gctr]);
+                       c++;
+               }
+               else
+                       outsidesum++;
+               gctr++;
+       }
+       if (c>0)
+               svmul(1/(double)c,pos_ins->geom_cent[i],pos_ins->geom_cent[i]);
+       if (!bALLOW_ASYMMETRY)
+               pos_ins->geom_cent[i][ZZ]=mem_p->zmed;
+
+       fprintf(stderr,"Embedding piece %d with center of geometry: %f %f %f\n",i,pos_ins->geom_cent[i][XX],pos_ins->geom_cent[i][YY],pos_ins->geom_cent[i][ZZ]);
+    }
+    fprintf(stderr,"\n");
+}
+
+void resize(rvec *r_ins, rvec *r, pos_ins_t *pos_ins,rvec fac)
+{
+       int i,j,k,at,c=0;
+       for (k=0;k<pos_ins->pieces;k++)
+               for(i=0;i<pos_ins->nidx[k];i++)
+               {
+                       at=pos_ins->subindex[k][i];
+                       for(j=0;j<DIM;j++)
+                               r[at][j]=pos_ins->geom_cent[k][j]+fac[j]*(r_ins[c][j]-pos_ins->geom_cent[k][j]);
+                       c++;
+               }
+}
+
+int gen_rm_list(rm_t *rm_p,t_block *ins_at,t_block *rest_at,t_pbc *pbc, gmx_mtop_t *mtop,
+               rvec *r, rvec *r_ins, mem_t *mem_p, pos_ins_t *pos_ins, real probe_rad, int low_up_rm, gmx_bool bALLOW_ASYMMETRY)
+{
+       int i,j,k,l,at,at2,mol_id;
+        int type=0,block=0;
+       int nrm,nupper,nlower;
+       real r_min_rad,z_lip,min_norm;
+       gmx_bool bRM;
+       rvec dr,dr_tmp;
+       real *dist;
+       int *order;
+
+       r_min_rad=probe_rad*probe_rad;
+       snew(rm_p->mol,mtop->mols.nr);
+       snew(rm_p->block,mtop->mols.nr);
+       nrm=nupper=0;
+       nlower=low_up_rm;
+       for(i=0;i<ins_at->nr;i++)
+       {
+               at=ins_at->index[i];
+               for(j=0;j<rest_at->nr;j++)
+               {
+                       at2=rest_at->index[j];
+                       pbc_dx(pbc,r[at],r[at2],dr);
+
+                       if(norm2(dr)<r_min_rad)
+                       {
+                               mol_id = get_mol_id(at2,mtop->nmolblock,mtop->molblock,&type,&block);
+                               bRM=TRUE;
+                               for(l=0;l<nrm;l++)
+                                       if(rm_p->mol[l]==mol_id)
+                                               bRM=FALSE;
+                               if(bRM)
+                               {
+                                       /*fprintf(stderr,"%d wordt toegevoegd\n",mol_id);*/
+                                       rm_p->mol[nrm]=mol_id;
+                                       rm_p->block[nrm]=block;
+                                       nrm++;
+                                       z_lip=0.0;
+                                       for(l=0;l<mem_p->nmol;l++)
+                                       {
+                                               if(mol_id==mem_p->mol_id[l])
+                                               {
+                                                       for(k=mtop->mols.index[mol_id];k<mtop->mols.index[mol_id+1];k++)
+                                                               z_lip+=r[k][ZZ];
+                                                       z_lip/=mtop->molblock[block].natoms_mol;
+                                                       if(z_lip<mem_p->zmed)
+                                                               nlower++;
+                                                       else
+                                                               nupper++;
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+
+       /*make sure equal number of lipids from upper and lower layer are removed */
+       if( (nupper!=nlower) && (!bALLOW_ASYMMETRY) )
+       {
+               snew(dist,mem_p->nmol);
+               snew(order,mem_p->nmol);
+               for(i=0;i<mem_p->nmol;i++)
+               {
+                       at = mtop->mols.index[mem_p->mol_id[i]];
+                       pbc_dx(pbc,r[at],pos_ins->geom_cent[0],dr);
+                       if (pos_ins->pieces>1)
+                       {
+                               /*minimum dr value*/
+                               min_norm=norm2(dr);
+                               for (k=1;k<pos_ins->pieces;k++)
+                               {
+                                       pbc_dx(pbc,r[at],pos_ins->geom_cent[k],dr_tmp);
+                                       if (norm2(dr_tmp) < min_norm)
+                                       {
+                                               min_norm=norm2(dr_tmp);
+                                               copy_rvec(dr_tmp,dr);
+                                       }
+                               }
+                       }
+                       dist[i]=dr[XX]*dr[XX]+dr[YY]*dr[YY];
+                       j=i-1;
+                       while (j>=0 && dist[i]<dist[order[j]])
+                       {
+                               order[j+1]=order[j];
+                               j--;
+                       }
+                       order[j+1]=i;
+               }
+
+               i=0;
+               while(nupper!=nlower)
+               {
+                       mol_id=mem_p->mol_id[order[i]];
+                       block=get_block(mol_id,mtop->nmolblock,mtop->molblock);
+
+                       bRM=TRUE;
+                       for(l=0;l<nrm;l++)
+                               if(rm_p->mol[l]==mol_id)
+                                       bRM=FALSE;
+                       if(bRM)
+                       {
+                               z_lip=0;
+                               for(k=mtop->mols.index[mol_id];k<mtop->mols.index[mol_id+1];k++)
+                                       z_lip+=r[k][ZZ];
+                               z_lip/=mtop->molblock[block].natoms_mol;
+                               if(nupper>nlower && z_lip<mem_p->zmed)
+                               {
+                                       rm_p->mol[nrm]=mol_id;
+                                       rm_p->block[nrm]=block;
+                                       nrm++;
+                                       nlower++;
+                               }
+                               else if (nupper<nlower && z_lip>mem_p->zmed)
+                               {
+                                       rm_p->mol[nrm]=mol_id;
+                                       rm_p->block[nrm]=block;
+                                       nrm++;
+                                       nupper++;
+                               }
+                       }
+                       i++;
+
+                       if(i>mem_p->nmol)
+                               gmx_fatal(FARGS,"Trying to remove more lipid molecules than there are in the membrane");
+               }
+               sfree(dist);
+               sfree(order);
+       }
+
+       rm_p->nr=nrm;
+       srenew(rm_p->mol,nrm);
+       srenew(rm_p->block,nrm);
+
+       return nupper+nlower;
+}
+
+void rm_group(t_inputrec *ir, gmx_groups_t *groups, gmx_mtop_t *mtop, rm_t *rm_p, t_state *state, t_block *ins_at, pos_ins_t *pos_ins)
+{
+       int i,j,k,n,rm,mol_id,at,block;
+       rvec *x_tmp,*v_tmp;
+       atom_id *list,*new_mols;
+       unsigned char  *new_egrp[egcNR];
+       gmx_bool bRM;
+
+       snew(list,state->natoms);
+       n=0;
+       for(i=0;i<rm_p->nr;i++)
+       {
+               mol_id=rm_p->mol[i];
+               at=mtop->mols.index[mol_id];
+               block =rm_p->block[i];
+               mtop->molblock[block].nmol--;
+               for(j=0;j<mtop->molblock[block].natoms_mol;j++)
+               {
+                       list[n]=at+j;
+                       n++;
+               }
+
+               mtop->mols.index[mol_id]=-1;
+       }
+
+       mtop->mols.nr-=rm_p->nr;
+       mtop->mols.nalloc_index-=rm_p->nr;
+       snew(new_mols,mtop->mols.nr);
+       for(i=0;i<mtop->mols.nr+rm_p->nr;i++)
+       {
+               j=0;
+               if(mtop->mols.index[i]!=-1)
+               {
+                       new_mols[j]=mtop->mols.index[i];
+                       j++;
+               }
+       }
+       sfree(mtop->mols.index);
+       mtop->mols.index=new_mols;
+
+
+       mtop->natoms-=n;
+       state->natoms-=n;
+       state->nalloc=state->natoms;
+       snew(x_tmp,state->nalloc);
+       snew(v_tmp,state->nalloc);
+
+       for(i=0;i<egcNR;i++)
+       {
+               if(groups->grpnr[i]!=NULL)
+               {
+                       groups->ngrpnr[i]=state->natoms;
+                       snew(new_egrp[i],state->natoms);
+               }
+       }
+
+       rm=0;
+       for (i=0;i<state->natoms+n;i++)
+       {
+               bRM=FALSE;
+               for(j=0;j<n;j++)
+               {
+                       if(i==list[j])
+                       {
+                               bRM=TRUE;
+                               rm++;
+                       }
+               }
+
+               if(!bRM)
+               {
+                       for(j=0;j<egcNR;j++)
+                       {
+                               if(groups->grpnr[j]!=NULL)
+                               {
+                                       new_egrp[j][i-rm]=groups->grpnr[j][i];
+                               }
+                       }
+                       copy_rvec(state->x[i],x_tmp[i-rm]);
+                       copy_rvec(state->v[i],v_tmp[i-rm]);
+                       for(j=0;j<ins_at->nr;j++)
+                       {
+                               if (i==ins_at->index[j])
+                                       ins_at->index[j]=i-rm;
+                       }
+                       for(j=0;j<pos_ins->pieces;j++)
+                       {
+                               for(k=0;k<pos_ins->nidx[j];k++)
+                               {
+                                       if (i==pos_ins->subindex[j][k])
+                                               pos_ins->subindex[j][k]=i-rm;
+                               }
+                       }
+               }
+       }
+       sfree(state->x);
+       state->x=x_tmp;
+       sfree(state->v);
+       state->v=v_tmp;
+
+       for(i=0;i<egcNR;i++)
+       {
+               if(groups->grpnr[i]!=NULL)
+               {
+                       sfree(groups->grpnr[i]);
+                       groups->grpnr[i]=new_egrp[i];
+               }
+       }
+}
+
+int rm_bonded(t_block *ins_at, gmx_mtop_t *mtop)
+{
+       int i,j,m;
+       int type,natom,nmol,at,atom1=0,rm_at=0;
+       gmx_bool *bRM,bINS;
+       /*this routine lives dangerously by assuming that all molecules of a given type are in order in the structure*/
+       /*this routine does not live as dangerously as it seems. There is namely a check in mdrunner_membed to make
+         *sure that g_membed exits with a warning when there are molecules of the same type not in the 
+        *ins_at index group. MGWolf 050710 */
+
+
+       snew(bRM,mtop->nmoltype);
+       for (i=0;i<mtop->nmoltype;i++)
+       {
+               bRM[i]=TRUE;
+       }
+
+       for (i=0;i<mtop->nmolblock;i++) 
+       {
+           /*loop over molecule blocks*/
+               type        =mtop->molblock[i].type;
+               natom       =mtop->molblock[i].natoms_mol;
+               nmol            =mtop->molblock[i].nmol;
+
+               for(j=0;j<natom*nmol && bRM[type]==TRUE;j++) 
+               {
+                   /*loop over atoms in the block*/
+                       at=j+atom1; /*atom index = block index + offset*/
+                       bINS=FALSE;
+
+                       for (m=0;(m<ins_at->nr) && (bINS==FALSE);m++)
+                       {
+                           /*loop over atoms in insertion index group to determine if we're inserting one*/
+                               if(at==ins_at->index[m])
+                               {
+                                       bINS=TRUE;
+                               }
+                       }
+                       bRM[type]=bINS;
+               }
+               atom1+=natom*nmol; /*update offset*/
+               if(bRM[type])
+               {
+                       rm_at+=natom*nmol; /*increment bonded removal counter by # atoms in block*/
+               }
+       }
+
+       for(i=0;i<mtop->nmoltype;i++)
+       {
+               if(bRM[i])
+               {
+                       for(j=0;j<F_LJ;j++)
+                       {
+                               mtop->moltype[i].ilist[j].nr=0;
+                       }
+                       for(j=F_POSRES;j<=F_VSITEN;j++)
+                       {
+                               mtop->moltype[i].ilist[j].nr=0;
+                       }
+               }
+       }
+       sfree(bRM);
+
+       return rm_at;
+}
+
+void top_update(const char *topfile, char *ins, rm_t *rm_p, gmx_mtop_t *mtop)
+{
+#define TEMP_FILENM "temp.top"
+       int     bMolecules=0;
+       FILE    *fpin,*fpout;
+       char    buf[STRLEN],buf2[STRLEN],*temp;
+       int             i,*nmol_rm,nmol,line;
+
+       fpin  = ffopen(topfile,"r");
+       fpout = ffopen(TEMP_FILENM,"w");
+
+       snew(nmol_rm,mtop->nmoltype);
+       for(i=0;i<rm_p->nr;i++)
+               nmol_rm[rm_p->block[i]]++;
+
+       line=0;
+       while(fgets(buf,STRLEN,fpin))
+       {
+               line++;
+               if(buf[0]!=';')
+               {
+                       strcpy(buf2,buf);
+                       if ((temp=strchr(buf2,'\n')) != NULL)
+                               temp[0]='\0';
+                       ltrim(buf2);
+
+                       if (buf2[0]=='[')
+                       {
+                               buf2[0]=' ';
+                               if ((temp=strchr(buf2,'\n')) != NULL)
+                                       temp[0]='\0';
+                               rtrim(buf2);
+                               if (buf2[strlen(buf2)-1]==']')
+                               {
+                                       buf2[strlen(buf2)-1]='\0';
+                                       ltrim(buf2);
+                                       rtrim(buf2);
+                                       if (gmx_strcasecmp(buf2,"molecules")==0)
+                                               bMolecules=1;
+                               }
+                               fprintf(fpout,"%s",buf);
+                       } else if (bMolecules==1)
+                       {
+                               for(i=0;i<mtop->nmolblock;i++)
+                               {
+                                       nmol=mtop->molblock[i].nmol;
+                                       sprintf(buf,"%-15s %5d\n",*(mtop->moltype[mtop->molblock[i].type].name),nmol);
+                                       fprintf(fpout,"%s",buf);
+                               }
+                               bMolecules=2;
+                       } else if (bMolecules==2)
+                       {
+                               /* print nothing */
+                       } else 
+                       {
+                               fprintf(fpout,"%s",buf);
+                       }
+               } else 
+               {
+                       fprintf(fpout,"%s",buf);
+               }
+       }
+
+       fclose(fpout);
+       /* use ffopen to generate backup of topinout */
+       fpout=ffopen(topfile,"w");
+       fclose(fpout);
+       rename(TEMP_FILENM,topfile);
+#undef TEMP_FILENM
+}
+
+void rescale_membed(int step_rel, gmx_membed_t *membed, rvec *x)
+{
+       /* Set new positions for the group to embed */
+       if(step_rel<=membed->it_xy)
+       {
+               membed->fac[0]+=membed->xy_step;
+               membed->fac[1]+=membed->xy_step;
+       } else if (step_rel<=(membed->it_xy+membed->it_z))
+       {
+               membed->fac[2]+=membed->z_step;
+       }
+       resize(membed->r_ins,x,membed->pos_ins,membed->fac);
+}
+
+void init_membed(FILE *fplog, gmx_membed_t *membed, int nfile, const t_filenm fnm[], gmx_mtop_t *mtop, t_inputrec *inputrec, t_state *state, t_commrec *cr,real *cpt)
+{
+        char                    *ins;
+        int                     i,rm_bonded_at,fr_id,fr_i=0,tmp_id,warn=0;
+        int                     ng,j,max_lip_rm,ins_grp_id,ins_nat,mem_nat,ntype,lip_rm,tpr_version;
+        real                    prot_area;
+        rvec                    *r_ins=NULL;
+        t_block                 *ins_at,*rest_at;
+        pos_ins_t               *pos_ins;
+        mem_t                   *mem_p;
+        rm_t                    *rm_p;
+        gmx_groups_t            *groups;
+        gmx_bool                    bExcl=FALSE;
+        t_atoms                 atoms;
+        t_pbc                   *pbc;
+        char                    **piecename=NULL;
+    
+        /* input variables */
+       const char *membed_input;
+        real xy_fac = 0.5;
+        real xy_max = 1.0;
+        real z_fac = 1.0;
+        real z_max = 1.0;
+        int it_xy = 1000;
+        int it_z = 0;
+        real probe_rad = 0.22;
+        int low_up_rm = 0;
+        int maxwarn=0;
+        int pieces=1;
+        gmx_bool bALLOW_ASYMMETRY=FALSE;
+
+       snew(ins_at,1);
+       snew(pos_ins,1);
+
+       if(MASTER(cr))
+       {
+                /* get input data out membed file */
+               membed_input = opt2fn("-membed",nfile,fnm);
+               get_input(membed_input,&xy_fac,&xy_max,&z_fac,&z_max,&it_xy,&it_z,&probe_rad,&low_up_rm,&maxwarn,&pieces,&bALLOW_ASYMMETRY);
+
+               tpr_version = get_tpr_version(ftp2fn(efTPX,nfile,fnm));
+               if (tpr_version<58)
+                       gmx_fatal(FARGS,"Version of *.tpr file to old (%d). Rerun grompp with gromacs VERSION 4.0.3 or newer.\n",tpr_version);
+
+               if( !EI_DYNAMICS(inputrec->eI) )
+                       gmx_input("Change integrator to a dynamics integrator in mdp file (e.g. md or sd).");
+
+               if(PAR(cr))
+                       gmx_input("Sorry, parallel g_membed is not yet fully functional.");
+     
+#ifdef GMX_OPENMM
+                       gmx_input("Sorry, g_membed does not work with openmm.");
+#endif
+
+               if(*cpt>=0)
+               {
+                       fprintf(stderr,"\nSetting -cpt to -1, because embedding cannot be restarted from cpt-files.\n");
+                       *cpt=-1;
+               }
+               groups=&(mtop->groups);
+
+               atoms=gmx_mtop_global_atoms(mtop);
+               snew(mem_p,1);
+               fprintf(stderr,"\nSelect a group to embed in the membrane:\n");
+               get_index(&atoms,opt2fn_null("-mn",nfile,fnm),1,&(ins_at->nr),&(ins_at->index),&ins);
+               ins_grp_id = search_string(ins,groups->ngrpname,(groups->grpname));
+               fprintf(stderr,"\nSelect a group to embed %s into (e.g. the membrane):\n",ins);
+               get_index(&atoms,opt2fn_null("-mn",nfile,fnm),1,&(mem_p->mem_at.nr),&(mem_p->mem_at.index),&(mem_p->name));
+
+               pos_ins->pieces=pieces;
+               snew(pos_ins->nidx,pieces);
+               snew(pos_ins->subindex,pieces);
+               snew(piecename,pieces); 
+               if (pieces>1)
+               {
+                       fprintf(stderr,"\nSelect pieces to embed:\n");
+                       get_index(&atoms,opt2fn_null("-mn",nfile,fnm),pieces,pos_ins->nidx,pos_ins->subindex,piecename);
+               }
+               else
+               {       
+                       /*use whole embedded group*/
+                       snew(pos_ins->nidx,1);
+                       snew(pos_ins->subindex,1);
+                       pos_ins->nidx[0]=ins_at->nr;
+                       pos_ins->subindex[0]=ins_at->index;
+               }
+
+               if(probe_rad<0.2199999)
+               {
+                       warn++;
+                       fprintf(stderr,"\nWarning %d:\nA probe radius (-rad) smaller than 0.2 can result in overlap between waters "
+                                       "and the group to embed, which will result in Lincs errors etc.\nIf you are sure, you can increase maxwarn.\n\n",warn);
+               }
+
+               if(xy_fac<0.09999999)
+               {
+                       warn++;
+                       fprintf(stderr,"\nWarning %d:\nThe initial size of %s is probably too smal.\n"
+                                       "If you are sure, you can increase maxwarn.\n\n",warn,ins);
+               }
+
+               if(it_xy<1000)
+               {
+                       warn++;
+                       fprintf(stderr,"\nWarning %d;\nThe number of steps used to grow the xy-coordinates of %s (%d) is probably too small.\n"
+                                       "Increase -nxy or, if you are sure, you can increase maxwarn.\n\n",warn,ins,it_xy);
+               }
+
+               if( (it_z<100) && ( z_fac<0.99999999 || z_fac>1.0000001) )
+                {
+                        warn++;
+                        fprintf(stderr,"\nWarning %d;\nThe number of steps used to grow the z-coordinate of %s (%d) is probably too small.\n"
+                                       "Increase -nz or, if you are sure, you can increase maxwarn.\n\n",warn,ins,it_z);
+                }
+
+               if(it_xy+it_z>inputrec->nsteps)
+               {
+                       warn++;
+                       fprintf(stderr,"\nWarning %d:\nThe number of growth steps (-nxy + -nz) is larger than the number of steps in the tpr.\n"
+                                       "If you are sure, you can increase maxwarn.\n\n",warn);
+               }
+
+               fr_id=-1;
+               if( inputrec->opts.ngfrz==1)
+                       gmx_fatal(FARGS,"You did not specify \"%s\" as a freezegroup.",ins);
+               for(i=0;i<inputrec->opts.ngfrz;i++)
+               {
+                       tmp_id = mtop->groups.grps[egcFREEZE].nm_ind[i];
+                       if(ins_grp_id==tmp_id)
+                       {
+                               fr_id=tmp_id;
+                               fr_i=i;
+                       }
+               }
+               if (fr_id == -1 )
+                       gmx_fatal(FARGS,"\"%s\" not as freezegroup defined in the mdp-file.",ins);
+
+               for(i=0;i<DIM;i++)
+                       if( inputrec->opts.nFreeze[fr_i][i] != 1)
+                               gmx_fatal(FARGS,"freeze dimensions for %s are not Y Y Y\n",ins);
+
+               ng = groups->grps[egcENER].nr;
+               if (ng == 1)
+                       gmx_input("No energy groups defined. This is necessary for energy exclusion in the freeze group");
+
+               for(i=0;i<ng;i++)
+               {
+                       for(j=0;j<ng;j++)
+                       {
+                               if (inputrec->opts.egp_flags[ng*i+j] == EGP_EXCL)
+                               {
+                                       bExcl = TRUE;
+                                       if ( (groups->grps[egcENER].nm_ind[i] != ins_grp_id) || (groups->grps[egcENER].nm_ind[j] != ins_grp_id) )
+                                               gmx_fatal(FARGS,"Energy exclusions \"%s\" and  \"%s\" do not match the group to embed \"%s\"",
+                                                               *groups->grpname[groups->grps[egcENER].nm_ind[i]],
+                                                               *groups->grpname[groups->grps[egcENER].nm_ind[j]],ins);
+                               }
+                       }
+               }
+               if (!bExcl)
+                       gmx_input("No energy exclusion groups defined. This is necessary for energy exclusion in the freeze group");
+
+               /* Guess the area the protein will occupy in the membrane plane  Calculate area per lipid*/
+               snew(rest_at,1);
+               ins_nat = init_ins_at(ins_at,rest_at,state,pos_ins,groups,ins_grp_id,xy_max);
+               /* Check moleculetypes in insertion group */
+               check_types(ins_at,rest_at,mtop);
+
+               mem_nat = init_mem_at(mem_p,mtop,state->x,state->box,pos_ins);
+
+               prot_area = est_prot_area(pos_ins,state->x,ins_at,mem_p);
+               if ( (prot_area>7.5) && ( (state->box[XX][XX]*state->box[YY][YY]-state->box[XX][YY]*state->box[YY][XX])<50) )
+               {
+                       warn++;
+                       fprintf(stderr,"\nWarning %d:\nThe xy-area is very small compared to the area of the protein.\n"
+                                       "This might cause pressure problems during the growth phase. Just try with\n"
+                                       "current setup (-maxwarn + 1), but if pressure problems occur, lower the\n"
+                                       "compressibility in the mdp-file or use no pressure coupling at all.\n\n",warn);
+               }
+               if(warn>maxwarn)
+                                       gmx_fatal(FARGS,"Too many warnings.\n");
+
+               printf("The estimated area of the protein in the membrane is %.3f nm^2\n",prot_area);
+               printf("\nThere are %d lipids in the membrane part that overlaps the protein.\nThe area per lipid is %.4f nm^2.\n",mem_p->nmol,mem_p->lip_area);
+
+               /* Maximum number of lipids to be removed*/
+               max_lip_rm=(int)(2*prot_area/mem_p->lip_area);
+               printf("Maximum number of lipids that will be removed is %d.\n",max_lip_rm);
+
+               printf("\nWill resize the protein by a factor of %.3f in the xy plane and %.3f in the z direction.\n"
+                               "This resizing will be done with respect to the geometrical center of all protein atoms\n"
+                               "that span the membrane region, i.e. z between %.3f and %.3f\n\n",xy_fac,z_fac,mem_p->zmin,mem_p->zmax);
+
+               /* resize the protein by xy and by z if necessary*/
+               snew(r_ins,ins_at->nr);
+               init_resize(ins_at,r_ins,pos_ins,mem_p,state->x,bALLOW_ASYMMETRY);
+               membed->fac[0]=membed->fac[1]=xy_fac;
+               membed->fac[2]=z_fac;
+
+               membed->xy_step =(xy_max-xy_fac)/(double)(it_xy);
+               membed->z_step  =(z_max-z_fac)/(double)(it_z-1);
+
+               resize(r_ins,state->x,pos_ins,membed->fac);
+
+               /* remove overlapping lipids and water from the membrane box*/
+               /*mark molecules to be removed*/
+               snew(pbc,1);
+               set_pbc(pbc,inputrec->ePBC,state->box);
+
+               snew(rm_p,1);
+               lip_rm = gen_rm_list(rm_p,ins_at,rest_at,pbc,mtop,state->x, r_ins, mem_p,pos_ins,probe_rad,low_up_rm,bALLOW_ASYMMETRY);
+               lip_rm -= low_up_rm;
+
+               if(fplog)
+                       for(i=0;i<rm_p->nr;i++)
+                               fprintf(fplog,"rm mol %d\n",rm_p->mol[i]);
+
+               for(i=0;i<mtop->nmolblock;i++)
+               {
+                       ntype=0;
+                       for(j=0;j<rm_p->nr;j++)
+                               if(rm_p->block[j]==i)
+                                       ntype++;
+                       printf("Will remove %d %s molecules\n",ntype,*(mtop->moltype[mtop->molblock[i].type].name));
+               }
+
+               if(lip_rm>max_lip_rm)
+               {
+                       warn++;
+                       fprintf(stderr,"\nWarning %d:\nTrying to remove a larger lipid area than the estimated protein area\n"
+                                       "Try making the -xyinit resize factor smaller.\n\n",warn);
+               }
+
+               /*remove all lipids and waters overlapping and update all important structures*/
+               rm_group(inputrec,groups,mtop,rm_p,state,ins_at,pos_ins);
+
+               rm_bonded_at = rm_bonded(ins_at,mtop);
+               if (rm_bonded_at != ins_at->nr)
+               {
+                       fprintf(stderr,"Warning: The number of atoms for which the bonded interactions are removed is %d, "
+                                       "while %d atoms are embedded. Make sure that the atoms to be embedded are not in the same"
+                                       "molecule type as atoms that are not to be embedded.\n",rm_bonded_at,ins_at->nr);
+               }
+
+               if(warn>maxwarn)
+                       gmx_fatal(FARGS,"Too many warnings.\nIf you are sure these warnings are harmless, you can increase -maxwarn");
+
+               if (ftp2bSet(efTOP,nfile,fnm))
+                       top_update(opt2fn("-p",nfile,fnm),ins,rm_p,mtop);
+
+               sfree(pbc);
+               sfree(rest_at);
+               if (pieces>1) {         sfree(piecename); }
+
+                membed->it_xy=it_xy;
+                membed->it_z=it_z;
+                membed->pos_ins=pos_ins;
+                membed->r_ins=r_ins;
+       }
+}
index 46737516596eeab9947d25a79c9a4586f039f127..6445b6a102970c4ca9013ce707414e818c1fe867 100644 (file)
@@ -79,6 +79,7 @@ static char tcgrps[STRLEN],tau_t[STRLEN],ref_t[STRLEN],
   wall_atomtype[STRLEN],wall_density[STRLEN],deform[STRLEN],QMMM[STRLEN];
 static char foreign_lambda[STRLEN];
 static char **pull_grp;
+static char **rot_grp;
 static char anneal[STRLEN],anneal_npoints[STRLEN],
   anneal_time[STRLEN],anneal_temp[STRLEN];
 static char QMmethod[STRLEN],QMbasis[STRLEN],QMcharge[STRLEN],QMmult[STRLEN],
@@ -1081,6 +1082,15 @@ void get_ir(const char *mdparin,const char *mdparout,
     snew(ir->pull,1);
     pull_grp = read_pullparams(&ninp,&inp,ir->pull,&opts->pull_start,wi);
   }
+  
+  /* Enforced rotation */
+  CCTYPE("ENFORCED ROTATION");
+  CTYPE("Enforced rotation: No or Yes");
+  EETYPE("rotation",       ir->bRot, yesno_names);
+  if (ir->bRot) {
+    snew(ir->rot,1);
+    rot_grp = read_rotparams(&ninp,&inp,ir->rot,wi);
+  }
 
   /* Refinement */
   CCTYPE("NMR refinement stuff");
@@ -1995,6 +2005,10 @@ void do_index(const char* mdparin, const char *ndx,
   if (ir->ePull != epullNO) {
     make_pull_groups(ir->pull,pull_grp,grps,gnames);
   }
+  
+  if (ir->bRot) {
+    make_rotation_groups(ir->rot,rot_grp,grps,gnames);
+  }
 
   nacc = str_nelem(acc,MAXPTR,ptr1);
   nacg = str_nelem(accgrps,MAXPTR,ptr2);
index d9a18e4f7426880327cf846c62d36bb795e0eb08..3f99910756986cca0381b202dd243f1c84a47303 100644 (file)
@@ -136,4 +136,14 @@ extern void set_pull_init(t_inputrec *ir,gmx_mtop_t *mtop,rvec *x,matrix box,
  * If bStart adds the distance to the initial reference location.
  */
 
+extern char **read_rotparams(int *ninp_p,t_inpfile **inp,t_rot *rot,warninp_t wi);
+/* Reads enforced rotation parameters, returns a list of the rot group names */
+
+extern void make_rotation_groups(t_rot *rot,char **rotgnames,
+                 t_blocka *grps,char **gnames);
+/* Process the rotation parameters after reading the index groups */
+
+extern void set_reference_positions(t_rot *rot, gmx_mtop_t *mtop, rvec *x, matrix box,
+        const char *fn, gmx_bool bSet, warninp_t wi);
+
 #endif /* _readir_h */
diff --git a/src/kernel/readrot.c b/src/kernel/readrot.c
new file mode 100644 (file)
index 0000000..6610151
--- /dev/null
@@ -0,0 +1,294 @@
+/*
+ *                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-2004, 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:
+ * GROwing Monsters And Cloning Shrimps
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "vec.h"
+#include "smalloc.h"
+#include "readir.h"
+#include "names.h"
+#include "futil.h"
+#include "trnio.h"
+#include "txtdump.h"
+
+static char *RotStr = {"Enforced rotation:"};
+
+
+static char s_vec[STRLEN];
+
+
+static void string2dvec(char buf[], dvec nums)
+{
+    if (sscanf(buf,"%lf%lf%lf",&nums[0],&nums[1],&nums[2]) != 3)
+        gmx_fatal(FARGS,"Expected three numbers at input line %s",buf);
+}
+
+
+extern char **read_rotparams(int *ninp_p,t_inpfile **inp_p,t_rot *rot,
+        warninp_t wi)
+{
+    int  ninp,g,m;
+    t_inpfile *inp;
+    const char *tmp;
+    char **grpbuf;
+    char buf[STRLEN];
+    char warn_buf[STRLEN];
+    dvec vec;
+    t_rotgrp *rotg;
+
+    ninp   = *ninp_p;
+    inp    = *inp_p;
+    
+    /* read rotation parameters */
+    CTYPE("Output frequency for angle, torque and rotation potential energy for the whole group");
+    ITYPE("rot_nstrout",     rot->nstrout, 100);
+    CTYPE("Output frequency for per-slab data (angles, torques and slab centers)");
+    ITYPE("rot_nstsout",     rot->nstsout, 1000);
+    CTYPE("Number of rotation groups");
+    ITYPE("rot_ngroups",     rot->ngrp,1);
+    
+    if (rot->ngrp < 1)
+    {
+        gmx_fatal(FARGS,"rot_ngroups should be >= 1");
+    }
+    
+    snew(rot->grp,rot->ngrp);
+    
+    /* Read the rotation groups */
+    snew(grpbuf,rot->ngrp);
+    for(g=0; g<rot->ngrp; g++)
+    {
+        rotg = &rot->grp[g];
+        snew(grpbuf[g],STRLEN);
+        CTYPE("Rotation group name");
+        sprintf(buf,"rot_group%d",g);
+        STYPE(buf, grpbuf[g], "");
+        
+        CTYPE("Rotation potential. Can be iso, iso-pf, pm, pm-pf, rm, rm-pf, rm2, rm2-pf, flex, flex-t, flex2, flex2-t");
+        sprintf(buf,"rot_type%d",g);
+        ETYPE(buf, rotg->eType, erotg_names);
+
+        CTYPE("Use mass-weighting of the rotation group positions");
+        sprintf(buf,"rot_massw%d",g);
+        ETYPE(buf, rotg->bMassW, yesno_names);
+
+        CTYPE("Rotation vector, will get normalized");
+        sprintf(buf,"rot_vec%d",g);
+        STYPE(buf, s_vec, "1.0 0.0 0.0");
+        string2dvec(s_vec,vec);
+        /* Normalize the rotation vector */
+        if (dnorm(vec) != 0)
+        {
+            dsvmul(1.0/dnorm(vec),vec,vec);
+        }
+        else
+        {
+            sprintf(warn_buf, "rot_vec%d = 0", g);
+            warning_error(wi, warn_buf);
+        }
+        fprintf(stderr, "%s Group %d (%s) normalized rot. vector: %f %f %f\n",
+                RotStr, g, erotg_names[rotg->eType], vec[0], vec[1], vec[2]);
+        for(m=0; m<DIM; m++)
+            rotg->vec[m] = vec[m];
+        
+        CTYPE("Pivot point for the potentials iso, pm, rm, and rm2 [nm]");
+        sprintf(buf,"rot_pivot%d",g);
+        STYPE(buf, s_vec, "0.0 0.0 0.0");
+        clear_dvec(vec);
+        if ( (rotg->eType==erotgISO) || (rotg->eType==erotgPM) || (rotg->eType==erotgRM) || (rotg->eType==erotgRM2) )
+            string2dvec(s_vec,vec);
+        for(m=0; m<DIM; m++)
+            rotg->pivot[m] = vec[m];
+
+        CTYPE("Rotation rate [degree/ps] and force constant [kJ/(mol*nm^2)]");
+        sprintf(buf,"rot_rate%d",g);
+        RTYPE(buf, rotg->rate, 0.0);
+
+        sprintf(buf,"rot_k%d",g);
+        RTYPE(buf, rotg->k, 0.0);
+        if (rotg->k <= 0.0)
+        {
+            sprintf(warn_buf, "rot_k%d <= 0", g);
+            warning_note(wi, warn_buf);
+        }
+
+        CTYPE("Slab distance for flexible axis rotation [nm]");
+        sprintf(buf,"rot_slab_dist%d",g);
+        RTYPE(buf, rotg->slab_dist, 1.5);
+        if (rotg->slab_dist <= 0.0)
+        {
+            sprintf(warn_buf, "rot_slab_dist%d <= 0", g);
+            warning_error(wi, warn_buf);
+        }
+
+        CTYPE("Minimum value of Gaussian function for the force to be evaluated (for flex* potentials)");
+        sprintf(buf,"rot_min_gauss%d",g);
+        RTYPE(buf, rotg->min_gaussian, 1e-3);
+        if (rotg->min_gaussian <= 0.0)
+        {
+            sprintf(warn_buf, "rot_min_gauss%d <= 0", g);
+            warning_error(wi, warn_buf);
+        }
+
+        CTYPE("Value of additive constant epsilon' [nm^2] for rm2* and flex2* potentials");
+        sprintf(buf, "rot_eps%d",g);
+        RTYPE(buf, rotg->eps, 1e-4);
+        if ( (rotg->eps <= 0.0) && (rotg->eType==erotgRM2 || rotg->eType==erotgFLEX2) )
+        {
+            sprintf(warn_buf, "rot_eps%d <= 0", g);
+            warning_error(wi, warn_buf);
+        }
+
+        CTYPE("Fitting method to determine angle of rotation group (rmsd or norm) (flex* potentials)");
+        sprintf(buf,"rot_fit_method%d",g);
+        ETYPE(buf, rotg->eFittype, erotg_fitnames);
+    }
+    
+    *ninp_p   = ninp;
+    *inp_p    = inp;
+    
+    return grpbuf;
+}
+
+
+/* Check whether the box is unchanged */
+static void check_box(matrix f_box, matrix box, char fn[], warninp_t wi)
+{
+    int i,ii;
+    gmx_bool bSame=TRUE;
+    char warn_buf[STRLEN];
+    
+    
+    for (i=0; i<DIM; i++)
+        for (ii=0; ii<DIM; ii++)
+            if (f_box[i][ii] != box[i][ii]) 
+                bSame = FALSE;
+    if (!bSame)
+    {
+        sprintf(warn_buf, "%s Box size in reference file %s differs from actual box size!",
+                RotStr, fn);
+        warning(wi, warn_buf);
+        pr_rvecs(stderr,0,"Your box is:",box  ,3);
+        pr_rvecs(stderr,0,"Box in file:",f_box,3);
+    }
+}
+
+
+/* Extract the reference positions for the rotation group(s) */
+extern void set_reference_positions(
+        t_rot *rot, gmx_mtop_t *mtop, rvec *x, matrix box,
+        const char *fn, gmx_bool bSet, warninp_t wi)
+{
+    int g,i,ii;
+    t_rotgrp *rotg;
+    t_trnheader header;    /* Header information of reference file */
+    char base[STRLEN],extension[STRLEN],reffile[STRLEN];
+    char *extpos;
+    rvec f_box[3];         /* Box from reference file */
+
+    
+    /* Base name and extension of the reference file: */
+    strncpy(base, fn, STRLEN - 1);
+    extpos = strrchr(base, '.');
+    strcpy(extension,extpos+1);
+    *extpos = '\0';
+
+
+    for (g=0; g<rot->ngrp; g++)
+     {
+         rotg = &rot->grp[g];
+         fprintf(stderr, "%s group %d has %d reference positions.\n",RotStr,g,rotg->nat);
+         snew(rotg->x_ref, rotg->nat);
+         
+         /* Construct the name for the file containing the reference positions for this group: */
+         sprintf(reffile, "%s.%d.%s", base,g,extension);
+
+         /* If the base filename for the reference position files was explicitly set by
+          * the user, we issue a fatal error if the group file can not be found */
+         if (bSet && !gmx_fexist(reffile))
+         {
+             gmx_fatal(FARGS, "%s The file containing the reference positions was not found.\n"
+                              "Expected the file '%s' for group %d.\n",
+                              RotStr, reffile, g);
+         }
+
+         if (gmx_fexist(reffile))
+         {
+             fprintf(stderr, "  Reading them from %s.\n", reffile);
+             read_trnheader(reffile, &header);
+             if (rotg->nat != header.natoms)
+                 gmx_fatal(FARGS,"Number of atoms in file %s (%d) does not match the number of atoms in rotation group (%d)!\n",
+                         reffile, header.natoms, rotg->nat);
+             read_trn(reffile, &header.step, &header.t, &header.lambda, f_box, &header.natoms, rotg->x_ref, NULL, NULL);
+
+             /* Check whether the box is unchanged and output a warning if not: */
+             check_box(f_box,box,reffile,wi);
+         }
+         else
+         {
+             fprintf(stderr, " Saving them to %s.\n", reffile);         
+             for(i=0; i<rotg->nat; i++)
+             {
+                 ii = rotg->ind[i];
+                 copy_rvec(x[ii], rotg->x_ref[i]);
+             }
+             write_trn(reffile,g,0.0,0.0,box,rotg->nat,rotg->x_ref,NULL,NULL);
+         }
+     }
+}
+
+
+extern void make_rotation_groups(t_rot *rot,char **rotgnames,t_blocka *grps,char **gnames)
+{
+    int      g,ig=-1,i;
+    t_rotgrp *rotg;
+    
+    
+    for (g=0; g<rot->ngrp; g++)
+    {
+        rotg = &rot->grp[g];
+        ig = search_string(rotgnames[g],grps->nr,gnames);
+        rotg->nat = grps->index[ig+1] - grps->index[ig];
+        
+        if (rotg->nat > 0)
+        {
+            fprintf(stderr,"Rotation group %d '%s' has %d atoms\n",g,rotgnames[g],rotg->nat);
+            snew(rotg->ind,rotg->nat);
+            for(i=0; i<rotg->nat; i++)
+                rotg->ind[i] = grps->a[grps->index[ig]+i];            
+        }
+        else
+            gmx_fatal(FARGS,"Rotation group %d '%s' is empty",g,rotgnames[g]);
+    }
+}
index 888fe31b7435a760707686e15abc155c356c040d..3c7f97e27e18bf6f639b950603777f0b0c6dcf0a 100644 (file)
@@ -52,6 +52,7 @@
 #include "mdrun.h"
 #include "network.h"
 #include "pull.h"
+#include "pull_rotation.h"
 #include "names.h"
 #include "disre.h"
 #include "orires.h"
@@ -72,6 +73,7 @@
 #include "sighandler.h"
 #include "tpxio.h"
 #include "txtdump.h"
+#include "membed.h"
 
 #include "md_openmm.h"
 
@@ -366,6 +368,7 @@ int mdrunner(int nthreads_requested, FILE *fplog,t_commrec *cr,int nfile,
     gmx_edsam_t ed=NULL;
     t_commrec   *cr_old=cr; 
     int         nthreads=1;
+    gmx_membed_t *membed=NULL;
 
     /* CAUTION: threads may be started later on in this function, so
        cr doesn't reflect the final parallel state right now */
@@ -414,6 +417,16 @@ int mdrunner(int nthreads_requested, FILE *fplog,t_commrec *cr,int nfile,
     }
     /* 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))
+    {
+       fprintf(stderr,"Entering membed code");
+        snew(membed,1);
+        init_membed(fplog,membed,nfile,fnm,mtop,inputrec,state,cr,&cpt_period);
+    }
+
     if (PAR(cr))
     {
         /* now broadcast everything to the non-master nodes/threads: */
@@ -798,6 +811,13 @@ int mdrunner(int nthreads_requested, FILE *fplog,t_commrec *cr,int nfile,
             init_pull(fplog,inputrec,nfile,fnm,mtop,cr,oenv,
                       EI_DYNAMICS(inputrec->eI) && MASTER(cr),Flags);
         }
+        
+        if (inputrec->bRot)
+        {
+           /* Initialize enforced rotation code */
+           init_rot(fplog,inputrec,nfile,fnm,cr,state->x,state->box,mtop,oenv,
+                    bVerbose,Flags);
+        }
 
         constr = init_constraints(fplog,mtop,inputrec,ed,state,cr);
 
@@ -820,6 +840,7 @@ int mdrunner(int nthreads_requested, FILE *fplog,t_commrec *cr,int nfile,
                                       fcd,state,
                                       mdatoms,nrnb,wcycle,ed,fr,
                                       repl_ex_nst,repl_ex_seed,
+                                      membed,
                                       cpt_period,max_hours,
                                       deviceOptions,
                                       Flags,
@@ -829,6 +850,12 @@ int mdrunner(int nthreads_requested, FILE *fplog,t_commrec *cr,int nfile,
         {
             finish_pull(fplog,inputrec->pull);
         }
+        
+        if (inputrec->bRot)
+        {
+            finish_rot(fplog,inputrec->rot);
+        }
+
     } 
     else 
     {
@@ -860,6 +887,11 @@ int mdrunner(int nthreads_requested, FILE *fplog,t_commrec *cr,int nfile,
     finish_run(fplog,cr,ftp2fn(efSTO,nfile,fnm),
                inputrec,nrnb,wcycle,&runtime,
                EI_DYNAMICS(inputrec->eI) && !MULTISIM(cr));
+    
+    if (opt2bSet("-membed",nfile,fnm))
+    {
+        sfree(membed);
+    }
 
     /* Does what it says */  
     print_date_and_time(fplog,cr->nodeid,"Finished mdrun",&runtime);
diff --git a/src/mdlib/.cvsignore b/src/mdlib/.cvsignore
deleted file mode 100644 (file)
index eccc86b..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-Makefile
-Makefile.in
-.deps
-.libs
\ No newline at end of file
diff --git a/src/mdlib/.gitignore b/src/mdlib/.gitignore
deleted file mode 100644 (file)
index c8b0843..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-.deps
-.libs
diff --git a/src/mdlib/CMakeLists.txt b/src/mdlib/CMakeLists.txt
deleted file mode 100644 (file)
index 18f3a6e..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-
-file(GLOB MDLIB_SOURCES *.c)
-
-# Files        called xxx_test.c are test drivers with a main() function for 
-# module xxx.c, so they should not be included in the library
-file(GLOB_RECURSE NOT_MDLIB_SOURCES *_test.c *\#*)
-list(REMOVE_ITEM MDLIB_SOURCES ${NOT_MDLIB_SOURCES})
-
-add_library(md ${MDLIB_SOURCES})
-target_link_libraries(md gmx ${GMX_EXTRA_LIBRARIES} ${FFT_LIBRARIES} ${XML_LIBRARIES})
-set_target_properties(md PROPERTIES OUTPUT_NAME "md${GMX_LIBS_SUFFIX}" SOVERSION ${SOVERSION} INSTALL_NAME_DIR "${LIB_INSTALL_DIR}")
-
-install(TARGETS md DESTINATION ${LIB_INSTALL_DIR} COMPONENT libraries)
-
-configure_file(${CMAKE_CURRENT_SOURCE_DIR}/libmd.pc.cmakein ${CMAKE_CURRENT_BINARY_DIR}/libmd.pc @ONLY)
-install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libmd.pc
-        DESTINATION ${LIB_INSTALL_DIR}/pkgconfig
-        RENAME "libmd${GMX_LIBS_SUFFIX}.pc"
-        COMPONENT development)
diff --git a/src/mdlib/Makefile.am b/src/mdlib/Makefile.am
deleted file mode 100644 (file)
index a413744..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-## Process this file with automake to produce Makefile.in
-# Note: Makefile is automatically generated from Makefile.in by the configure
-# script, and Makefile.in is generated from Makefile.am by automake.
-
-AM_CPPFLAGS = -I$(top_srcdir)/include -DGMXLIBDIR=\"$(datadir)/top\"
-
-libmd@LIBSUFFIX@_la_LIBADD         = ../gmxlib/libgmx@LIBSUFFIX@.la    
-libmd@LIBSUFFIX@_la_DEPENDENCIES   = ../gmxlib/libgmx@LIBSUFFIX@.la    
-libmd@LIBSUFFIX@_la_LDFLAGS        = -no-undefined -version-info @SHARED_VERSION_INFO@ $(FFT_LIBS) $(XML_LIBS) $(PTHREAD_LIBS)
-
-lib_LTLIBRARIES = libmd@LIBSUFFIX@.la
-
-pkgconfigdir = ${libdir}/pkgconfig
-pkgconfig_DATA = libmd@LIBSUFFIX@.pc
-
-EXTRA_DIST = libmd.pc.cmakein
-
-libmd@LIBSUFFIX@_la_SOURCES = \
-       calcmu.c        calcvir.c       constr.c        \
-       coupling.c      \
-       domdec.c        domdec_box.c    domdec_con.c    \
-       domdec_network.c domdec_setup.c domdec_top.c    \
-       ebin.c          \
-       edsam.c         ewald.c         \
-       force.c         forcerec.c      \
-       ghat.c          init.c          \
-       mdatom.c        mdebin.c        minimize.c      \
-       mvxvf.c         ns.c            nsgrid.c        \
-       perf_est.c      genborn.c                       \
-       genborn_sse2_single.c                           \
-       genborn_sse2_single.h                           \
-       genborn_sse2_double.c                           \
-       genborn_sse2_double.h                           \
-       genborn_allvsall.c                              \
-       genborn_allvsall.h                              \
-       genborn_allvsall_sse2_single.c                  \
-       genborn_allvsall_sse2_single.h                  \
-       genborn_allvsall_sse2_double.c                  \
-       genborn_allvsall_sse2_double.h                  \
-       gmx_qhop_parm.c gmx_qhop_parm.h                 \
-       gmx_qhop_xml.c  gmx_qhop_xml.h                  \
-       groupcoord.c                    groupcoord.h    \
-       pme.c           pme_pp.c        pppm.c          \
-       partdec.c       pull.c          pullutil.c      \
-       rf_util.c       shakef.c        sim_util.c      \
-       shellfc.c       stat.c          \
-       tables.c        tgroup.c        tpi.c   \
-       update.c        vcm.c           vsite.c \
-       wall.c          wnblist.c       \
-       csettle.c       clincs.c        \
-       qmmm.c          gmx_fft.c       gmx_parallel_3dfft.c    \
-       fft5d.c         fft5d.h         \
-       gmx_wallcycle.c \
-       qm_gaussian.c   qm_mopac.c      qm_gamess.c             \
-       gmx_fft_fftw2.c gmx_fft_fftw3.c gmx_fft_fftpack.c       \
-       gmx_fft_mkl.c   qm_orca.c       mdebin_bar.c            \
-       mdebin_bar.h
-
-LDADD = ../mdlib/libmd@LIBSUFFIX@.la ../gmxlib/libgmx@LIBSUFFIX@.la 
-
-EXTRA_PROGRAMS = gmx_qhop_db_test
-
-gmx_qhop_db_test_LDADD = ../mdlib/libmd@LIBSUFFIX@.la ../gmxlib/libgmx@LIBSUFFIX@.la ../kernel/libgmxpreprocess@LIBSUFFIX@.la
-
-# clean all libtool libraries, since the target names might have changed
-CLEANFILES     = *.la *~ \\\#*
diff --git a/src/mdlib/domdec.c b/src/mdlib/domdec.c
deleted file mode 100644 (file)
index 8a7a178..0000000
+++ /dev/null
@@ -1,8634 +0,0 @@
-/* -*- mode: c; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; c-file-style: "stroustrup"; -*-
- *
- * 
- * This file is part of Gromacs        Copyright (c) 1991-2008
- * David van der Spoel, Erik Lindahl, Berk Hess, University of Groningen.
- *
- * 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.
- *
- * To help us fund GROMACS development, we humbly ask that you cite
- * the research papers on the package. Check out http://www.gromacs.org
- * 
- * And Hey:
- * Gnomes, ROck Monsters And Chili Sauce
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdio.h>
-#include <time.h>
-#include <math.h>
-#include <string.h>
-#include <stdlib.h>
-#include "typedefs.h"
-#include "smalloc.h"
-#include "vec.h"
-#include "domdec.h"
-#include "domdec_network.h"
-#include "nrnb.h"
-#include "pbc.h"
-#include "chargegroup.h"
-#include "constr.h"
-#include "mdatoms.h"
-#include "names.h"
-#include "pdbio.h"
-#include "futil.h"
-#include "force.h"
-#include "pme.h"
-#include "pull.h"
-#include "gmx_wallcycle.h"
-#include "mdrun.h"
-#include "nsgrid.h"
-#include "shellfc.h"
-#include "mtop_util.h"
-#include "gmxfio.h"
-#include "gmx_ga2la.h"
-#include "gmx_sort.h"
-
-#ifdef GMX_LIB_MPI
-#include <mpi.h>
-#endif
-#ifdef GMX_THREADS
-#include "tmpi.h"
-#endif
-
-#define DDRANK(dd,rank)    (rank)
-#define DDMASTERRANK(dd)   (dd->masterrank)
-
-typedef struct gmx_domdec_master
-{
-    /* The cell boundaries */
-    real **cell_x;
-    /* The global charge group division */
-    int  *ncg;     /* Number of home charge groups for each node */
-    int  *index;   /* Index of nnodes+1 into cg */
-    int  *cg;      /* Global charge group index */
-    int  *nat;     /* Number of home atoms for each node. */
-    int  *ibuf;    /* Buffer for communication */
-    rvec *vbuf;    /* Buffer for state scattering and gathering */
-} gmx_domdec_master_t;
-
-typedef struct
-{
-    /* The numbers of charge groups to send and receive for each cell
-     * that requires communication, the last entry contains the total
-     * number of atoms that needs to be communicated.
-     */
-    int nsend[DD_MAXIZONE+2];
-    int nrecv[DD_MAXIZONE+2];
-    /* The charge groups to send */
-    int *index;
-    int nalloc;
-    /* The atom range for non-in-place communication */
-    int cell2at0[DD_MAXIZONE];
-    int cell2at1[DD_MAXIZONE];
-} gmx_domdec_ind_t;
-
-typedef struct
-{
-    int  np;                   /* Number of grid pulses in this dimension */
-    int  np_dlb;               /* For dlb, for use with edlbAUTO          */
-    gmx_domdec_ind_t *ind;     /* The indices to communicate, size np     */
-    int  np_nalloc;
-    gmx_bool bInPlace;             /* Can we communicate in place?            */
-} gmx_domdec_comm_dim_t;
-
-typedef struct
-{
-    gmx_bool *bCellMin;    /* Temp. var.: is this cell size at the limit     */
-    real *cell_f;      /* State var.: cell boundaries, box relative      */
-    real *old_cell_f;  /* Temp. var.: old cell size                      */
-    real *cell_f_max0; /* State var.: max lower boundary, incl neighbors */
-    real *cell_f_min1; /* State var.: min upper boundary, incl neighbors */
-    real *bound_min;   /* Temp. var.: lower limit for cell boundary      */
-    real *bound_max;   /* Temp. var.: upper limit for cell boundary      */
-    gmx_bool bLimited;     /* State var.: is DLB limited in this dim and row */
-    real *buf_ncd;     /* Temp. var.                                     */
-} gmx_domdec_root_t;
-
-#define DD_NLOAD_MAX 9
-
-/* Here floats are accurate enough, since these variables
- * only influence the load balancing, not the actual MD results.
- */
-typedef struct
-{
-    int  nload;
-    float *load;
-    float sum;
-    float max;
-    float sum_m;
-    float cvol_min;
-    float mdf;
-    float pme;
-    int   flags;
-} gmx_domdec_load_t;
-
-typedef struct
-{
-    int  nsc;
-    int  ind_gl;
-    int  ind;
-} gmx_cgsort_t;
-
-typedef struct
-{
-    gmx_cgsort_t *sort1,*sort2;
-    int  sort_nalloc;
-    gmx_cgsort_t *sort_new;
-    int  sort_new_nalloc;
-    int  *ibuf;
-    int  ibuf_nalloc;
-} gmx_domdec_sort_t;
-
-typedef struct
-{
-    rvec *v;
-    int  nalloc;
-} vec_rvec_t;
-
-/* This enum determines the order of the coordinates.
- * ddnatHOME and ddnatZONE should be first and second,
- * the others can be ordered as wanted.
- */
-enum { ddnatHOME, ddnatZONE, ddnatVSITE, ddnatCON, ddnatNR };
-
-enum { edlbAUTO, edlbNO, edlbYES, edlbNR };
-const char *edlb_names[edlbNR] = { "auto", "no", "yes" };
-
-typedef struct
-{
-    int  dim;      /* The dimension                                          */
-    gmx_bool dim_match;/* Tells if DD and PME dims match                         */
-    int  nslab;    /* The number of PME slabs in this dimension              */
-    real *slb_dim_f; /* Cell sizes for determining the PME comm. with SLB    */
-    int  *pp_min;  /* The minimum pp node location, size nslab               */
-    int  *pp_max;  /* The maximum pp node location,size nslab                */
-    int  maxshift; /* The maximum shift for coordinate redistribution in PME */
-} gmx_ddpme_t;
-
-typedef struct
-{
-    real min0;    /* The minimum bottom of this zone                        */
-    real max1;    /* The maximum top of this zone                           */
-    real mch0;    /* The maximum bottom communicaton height for this zone   */
-    real mch1;    /* The maximum top communicaton height for this zone      */
-    real p1_0;    /* The bottom value of the first cell in this zone        */
-    real p1_1;    /* The top value of the first cell in this zone           */
-} gmx_ddzone_t;
-
-typedef struct gmx_domdec_comm
-{
-    /* All arrays are indexed with 0 to dd->ndim (not Cartesian indexing),
-     * unless stated otherwise.
-     */
-
-    /* The number of decomposition dimensions for PME, 0: no PME */
-    int  npmedecompdim;
-    /* The number of nodes doing PME (PP/PME or only PME) */
-    int  npmenodes;
-    int  npmenodes_x;
-    int  npmenodes_y;
-    /* The communication setup including the PME only nodes */
-    gmx_bool bCartesianPP_PME;
-    ivec ntot;
-    int  cartpmedim;
-    int  *pmenodes;          /* size npmenodes                         */
-    int  *ddindex2simnodeid; /* size npmenodes, only with bCartesianPP
-                              * but with bCartesianPP_PME              */
-    gmx_ddpme_t ddpme[2];
-    
-    /* The DD particle-particle nodes only */
-    gmx_bool bCartesianPP;
-    int  *ddindex2ddnodeid; /* size npmenode, only with bCartesianPP_PME */
-    
-    /* The global charge groups */
-    t_block cgs_gl;
-
-    /* Should we sort the cgs */
-    int  nstSortCG;
-    gmx_domdec_sort_t *sort;
-    
-    /* Are there bonded and multi-body interactions between charge groups? */
-    gmx_bool bInterCGBondeds;
-    gmx_bool bInterCGMultiBody;
-
-    /* Data for the optional bonded interaction atom communication range */
-    gmx_bool bBondComm;
-    t_blocka *cglink;
-    char *bLocalCG;
-
-    /* The DLB option */
-    int  eDLB;
-    /* Are we actually using DLB? */
-    gmx_bool bDynLoadBal;
-
-    /* Cell sizes for static load balancing, first index cartesian */
-    real **slb_frac;
-    
-    /* The width of the communicated boundaries */
-    real cutoff_mbody;
-    real cutoff;
-    /* The minimum cell size (including triclinic correction) */
-    rvec cellsize_min;
-    /* For dlb, for use with edlbAUTO */
-    rvec cellsize_min_dlb;
-    /* The lower limit for the DD cell size with DLB */
-    real cellsize_limit;
-    /* Effectively no NB cut-off limit with DLB for systems without PBC? */
-    gmx_bool bVacDLBNoLimit;
-
-    /* tric_dir is only stored here because dd_get_ns_ranges needs it */
-    ivec tric_dir;
-    /* box0 and box_size are required with dim's without pbc and -gcom */
-    rvec box0;
-    rvec box_size;
-    
-    /* The cell boundaries */
-    rvec cell_x0;
-    rvec cell_x1;
-
-    /* The old location of the cell boundaries, to check cg displacements */
-    rvec old_cell_x0;
-    rvec old_cell_x1;
-
-    /* The communication setup and charge group boundaries for the zones */
-    gmx_domdec_zones_t zones;
-    
-    /* The zone limits for DD dimensions 1 and 2 (not 0), determined from
-     * cell boundaries of neighboring cells for dynamic load balancing.
-     */
-    gmx_ddzone_t zone_d1[2];
-    gmx_ddzone_t zone_d2[2][2];
-    
-    /* The coordinate/force communication setup and indices */
-    gmx_domdec_comm_dim_t cd[DIM];
-    /* The maximum number of cells to communicate with in one dimension */
-    int  maxpulse;
-    
-    /* Which cg distribution is stored on the master node */
-    int master_cg_ddp_count;
-    
-    /* The number of cg's received from the direct neighbors */
-    int  zone_ncg1[DD_MAXZONE];
-    
-    /* The atom counts, the range for each type t is nat[t-1] <= at < nat[t] */
-    int  nat[ddnatNR];
-    
-    /* Communication buffer for general use */
-    int  *buf_int;
-    int  nalloc_int;
-
-     /* Communication buffer for general use */
-    vec_rvec_t vbuf;
-    
-    /* Communication buffers only used with multiple grid pulses */
-    int  *buf_int2;
-    int  nalloc_int2;
-    vec_rvec_t vbuf2;
-    
-    /* Communication buffers for local redistribution */
-    int  **cggl_flag;
-    int  cggl_flag_nalloc[DIM*2];
-    rvec **cgcm_state;
-    int  cgcm_state_nalloc[DIM*2];
-    
-    /* Cell sizes for dynamic load balancing */
-    gmx_domdec_root_t **root;
-    real *cell_f_row;
-    real cell_f0[DIM];
-    real cell_f1[DIM];
-    real cell_f_max0[DIM];
-    real cell_f_min1[DIM];
-    
-    /* Stuff for load communication */
-    gmx_bool bRecordLoad;
-    gmx_domdec_load_t *load;
-#ifdef GMX_MPI
-    MPI_Comm *mpi_comm_load;
-#endif
-    /* Cycle counters */
-    float cycl[ddCyclNr];
-    int   cycl_n[ddCyclNr];
-    float cycl_max[ddCyclNr];
-    /* Flop counter (0=no,1=yes,2=with (eFlop-1)*5% noise */
-    int eFlop;
-    double flop;
-    int    flop_n;
-    /* Have often have did we have load measurements */
-    int    n_load_have;
-    /* Have often have we collected the load measurements */
-    int    n_load_collect;
-    
-    /* Statistics */
-    double sum_nat[ddnatNR-ddnatZONE];
-    int    ndecomp;
-    int    nload;
-    double load_step;
-    double load_sum;
-    double load_max;
-    ivec   load_lim;
-    double load_mdf;
-    double load_pme;
-
-    /* The last partition step */
-    gmx_large_int_t partition_step;
-
-    /* Debugging */
-    int  nstDDDump;
-    int  nstDDDumpGrid;
-    int  DD_debug;
-} gmx_domdec_comm_t;
-
-/* The size per charge group of the cggl_flag buffer in gmx_domdec_comm_t */
-#define DD_CGIBS 2
-
-/* The flags for the cggl_flag buffer in gmx_domdec_comm_t */
-#define DD_FLAG_NRCG  65535
-#define DD_FLAG_FW(d) (1<<(16+(d)*2))
-#define DD_FLAG_BW(d) (1<<(16+(d)*2+1))
-
-/* Zone permutation required to obtain consecutive charge groups
- * for neighbor searching.
- */
-static const int zone_perm[3][4] = { {0,0,0,0},{1,0,0,0},{3,0,1,2} };
-
-/* dd_zo and dd_zp3/dd_zp2 are set up such that i zones with non-zero
- * components see only j zones with that component 0.
- */
-
-/* The DD zone order */
-static const ivec dd_zo[DD_MAXZONE] =
-  {{0,0,0},{1,0,0},{1,1,0},{0,1,0},{0,1,1},{0,0,1},{1,0,1},{1,1,1}};
-
-/* The 3D setup */
-#define dd_z3n  8
-#define dd_zp3n 4
-static const ivec dd_zp3[dd_zp3n] = {{0,0,8},{1,3,6},{2,5,6},{3,5,7}};
-
-/* The 2D setup */
-#define dd_z2n  4
-#define dd_zp2n 2
-static const ivec dd_zp2[dd_zp2n] = {{0,0,4},{1,3,4}};
-
-/* The 1D setup */
-#define dd_z1n  2
-#define dd_zp1n 1
-static const ivec dd_zp1[dd_zp1n] = {{0,0,2}};
-
-/* Factors used to avoid problems due to rounding issues */
-#define DD_CELL_MARGIN       1.0001
-#define DD_CELL_MARGIN2      1.00005
-/* Factor to account for pressure scaling during nstlist steps */
-#define DD_PRES_SCALE_MARGIN 1.02
-
-/* Allowed performance loss before we DLB or warn */
-#define DD_PERF_LOSS 0.05
-
-#define DD_CELL_F_SIZE(dd,di) ((dd)->nc[(dd)->dim[(di)]]+1+(di)*2+1+(di))
-
-/* Use separate MPI send and receive commands
- * when nnodes <= GMX_DD_NNODES_SENDRECV.
- * This saves memory (and some copying for small nnodes).
- * For high parallelization scatter and gather calls are used.
- */
-#define GMX_DD_NNODES_SENDRECV 4
-
-
-/*
-#define dd_index(n,i) ((((i)[ZZ]*(n)[YY] + (i)[YY])*(n)[XX]) + (i)[XX])
-
-static void index2xyz(ivec nc,int ind,ivec xyz)
-{
-  xyz[XX] = ind % nc[XX];
-  xyz[YY] = (ind / nc[XX]) % nc[YY];
-  xyz[ZZ] = ind / (nc[YY]*nc[XX]);
-}
-*/
-
-/* This order is required to minimize the coordinate communication in PME
- * which uses decomposition in the x direction.
- */
-#define dd_index(n,i) ((((i)[XX]*(n)[YY] + (i)[YY])*(n)[ZZ]) + (i)[ZZ])
-
-static void ddindex2xyz(ivec nc,int ind,ivec xyz)
-{
-    xyz[XX] = ind / (nc[YY]*nc[ZZ]);
-    xyz[YY] = (ind / nc[ZZ]) % nc[YY];
-    xyz[ZZ] = ind % nc[ZZ];
-}
-
-static int ddcoord2ddnodeid(gmx_domdec_t *dd,ivec c)
-{
-    int ddindex;
-    int ddnodeid=-1;
-    
-    ddindex = dd_index(dd->nc,c);
-    if (dd->comm->bCartesianPP_PME)
-    {
-        ddnodeid = dd->comm->ddindex2ddnodeid[ddindex];
-    }
-    else if (dd->comm->bCartesianPP)
-    {
-#ifdef GMX_MPI
-        MPI_Cart_rank(dd->mpi_comm_all,c,&ddnodeid);
-#endif
-    }
-    else
-    {
-        ddnodeid = ddindex;
-    }
-    
-    return ddnodeid;
-}
-
-static gmx_bool dynamic_dd_box(gmx_ddbox_t *ddbox,t_inputrec *ir)
-{
-    return (ddbox->nboundeddim < DIM || DYNAMIC_BOX(*ir));
-}
-
-int ddglatnr(gmx_domdec_t *dd,int i)
-{
-    int atnr;
-    
-    if (dd == NULL)
-    {
-        atnr = i + 1;
-    }
-    else
-    {
-        if (i >= dd->comm->nat[ddnatNR-1])
-        {
-            gmx_fatal(FARGS,"glatnr called with %d, which is larger than the local number of atoms (%d)",i,dd->comm->nat[ddnatNR-1]);
-        }
-        atnr = dd->gatindex[i] + 1;
-    }
-    
-    return atnr;
-}
-
-t_block *dd_charge_groups_global(gmx_domdec_t *dd)
-{
-    return &dd->comm->cgs_gl;
-}
-
-static void vec_rvec_init(vec_rvec_t *v)
-{
-    v->nalloc = 0;
-    v->v      = NULL;
-}
-
-static void vec_rvec_check_alloc(vec_rvec_t *v,int n)
-{
-    if (n > v->nalloc)
-    {
-        v->nalloc = over_alloc_dd(n);
-        srenew(v->v,v->nalloc);
-    }
-}
-
-void dd_store_state(gmx_domdec_t *dd,t_state *state)
-{
-    int i;
-    
-    if (state->ddp_count != dd->ddp_count)
-    {
-        gmx_incons("The state does not the domain decomposition state");
-    }
-    
-    state->ncg_gl = dd->ncg_home;
-    if (state->ncg_gl > state->cg_gl_nalloc)
-    {
-        state->cg_gl_nalloc = over_alloc_dd(state->ncg_gl);
-        srenew(state->cg_gl,state->cg_gl_nalloc);
-    }
-    for(i=0; i<state->ncg_gl; i++)
-    {
-        state->cg_gl[i] = dd->index_gl[i];
-    }
-    
-    state->ddp_count_cg_gl = dd->ddp_count;
-}
-
-gmx_domdec_zones_t *domdec_zones(gmx_domdec_t *dd)
-{
-    return &dd->comm->zones;
-}
-
-void dd_get_ns_ranges(gmx_domdec_t *dd,int icg,
-                      int *jcg0,int *jcg1,ivec shift0,ivec shift1)
-{
-    gmx_domdec_zones_t *zones;
-    int izone,d,dim;
-
-    zones = &dd->comm->zones;
-
-    izone = 0;
-    while (icg >= zones->izone[izone].cg1)
-    {
-        izone++;
-    }
-    
-    if (izone == 0)
-    {
-        *jcg0 = icg;
-    }
-    else if (izone < zones->nizone)
-    {
-        *jcg0 = zones->izone[izone].jcg0;
-    }
-    else
-    {
-        gmx_fatal(FARGS,"DD icg %d out of range: izone (%d) >= nizone (%d)",
-                  icg,izone,zones->nizone);
-    }
-        
-    *jcg1 = zones->izone[izone].jcg1;
-    
-    for(d=0; d<dd->ndim; d++)
-    {
-        dim = dd->dim[d];
-        shift0[dim] = zones->izone[izone].shift0[dim];
-        shift1[dim] = zones->izone[izone].shift1[dim];
-        if (dd->comm->tric_dir[dim] || (dd->bGridJump && d > 0))
-        {
-            /* A conservative approach, this can be optimized */
-            shift0[dim] -= 1;
-            shift1[dim] += 1;
-        }
-    }
-}
-
-int dd_natoms_vsite(gmx_domdec_t *dd)
-{
-    return dd->comm->nat[ddnatVSITE];
-}
-
-void dd_get_constraint_range(gmx_domdec_t *dd,int *at_start,int *at_end)
-{
-    *at_start = dd->comm->nat[ddnatCON-1];
-    *at_end   = dd->comm->nat[ddnatCON];
-}
-
-void dd_move_x(gmx_domdec_t *dd,matrix box,rvec x[])
-{
-    int  nzone,nat_tot,n,d,p,i,j,at0,at1,zone;
-    int  *index,*cgindex;
-    gmx_domdec_comm_t *comm;
-    gmx_domdec_comm_dim_t *cd;
-    gmx_domdec_ind_t *ind;
-    rvec shift={0,0,0},*buf,*rbuf;
-    gmx_bool bPBC,bScrew;
-    
-    comm = dd->comm;
-    
-    cgindex = dd->cgindex;
-    
-    buf = comm->vbuf.v;
-
-    nzone = 1;
-    nat_tot = dd->nat_home;
-    for(d=0; d<dd->ndim; d++)
-    {
-        bPBC   = (dd->ci[dd->dim[d]] == 0);
-        bScrew = (bPBC && dd->bScrewPBC && dd->dim[d] == XX);
-        if (bPBC)
-        {
-            copy_rvec(box[dd->dim[d]],shift);
-        }
-        cd = &comm->cd[d];
-        for(p=0; p<cd->np; p++)
-        {
-            ind = &cd->ind[p];
-            index = ind->index;
-            n = 0;
-            if (!bPBC)
-            {
-                for(i=0; i<ind->nsend[nzone]; i++)
-                {
-                    at0 = cgindex[index[i]];
-                    at1 = cgindex[index[i]+1];
-                    for(j=at0; j<at1; j++)
-                    {
-                        copy_rvec(x[j],buf[n]);
-                        n++;
-                    }
-                }
-            }
-            else if (!bScrew)
-            {
-                for(i=0; i<ind->nsend[nzone]; i++)
-                {
-                    at0 = cgindex[index[i]];
-                    at1 = cgindex[index[i]+1];
-                    for(j=at0; j<at1; j++)
-                    {
-                        /* We need to shift the coordinates */
-                        rvec_add(x[j],shift,buf[n]);
-                        n++;
-                    }
-                }
-            }
-            else
-            {
-                for(i=0; i<ind->nsend[nzone]; i++)
-                {
-                    at0 = cgindex[index[i]];
-                    at1 = cgindex[index[i]+1];
-                    for(j=at0; j<at1; j++)
-                    {
-                        /* Shift x */
-                        buf[n][XX] = x[j][XX] + shift[XX];
-                        /* Rotate y and z.
-                         * This operation requires a special shift force
-                         * treatment, which is performed in calc_vir.
-                         */
-                        buf[n][YY] = box[YY][YY] - x[j][YY];
-                        buf[n][ZZ] = box[ZZ][ZZ] - x[j][ZZ];
-                        n++;
-                    }
-                }
-            }
-            
-            if (cd->bInPlace)
-            {
-                rbuf = x + nat_tot;
-            }
-            else
-            {
-                rbuf = comm->vbuf2.v;
-            }
-            /* Send and receive the coordinates */
-            dd_sendrecv_rvec(dd, d, dddirBackward,
-                             buf,  ind->nsend[nzone+1],
-                             rbuf, ind->nrecv[nzone+1]);
-            if (!cd->bInPlace)
-            {
-                j = 0;
-                for(zone=0; zone<nzone; zone++)
-                {
-                    for(i=ind->cell2at0[zone]; i<ind->cell2at1[zone]; i++)
-                    {
-                        copy_rvec(rbuf[j],x[i]);
-                        j++;
-                    }
-                }
-            }
-            nat_tot += ind->nrecv[nzone+1];
-        }
-        nzone += nzone;
-    }
-}
-
-void dd_move_f(gmx_domdec_t *dd,rvec f[],rvec *fshift)
-{
-    int  nzone,nat_tot,n,d,p,i,j,at0,at1,zone;
-    int  *index,*cgindex;
-    gmx_domdec_comm_t *comm;
-    gmx_domdec_comm_dim_t *cd;
-    gmx_domdec_ind_t *ind;
-    rvec *buf,*sbuf;
-    ivec vis;
-    int  is;
-    gmx_bool bPBC,bScrew;
-    
-    comm = dd->comm;
-    
-    cgindex = dd->cgindex;
-
-    buf = comm->vbuf.v;
-
-    n = 0;
-    nzone = comm->zones.n/2;
-    nat_tot = dd->nat_tot;
-    for(d=dd->ndim-1; d>=0; d--)
-    {
-        bPBC   = (dd->ci[dd->dim[d]] == 0);
-        bScrew = (bPBC && dd->bScrewPBC && dd->dim[d] == XX);
-        if (fshift == NULL && !bScrew)
-        {
-            bPBC = FALSE;
-        }
-        /* Determine which shift vector we need */
-        clear_ivec(vis);
-        vis[dd->dim[d]] = 1;
-        is = IVEC2IS(vis);
-        
-        cd = &comm->cd[d];
-        for(p=cd->np-1; p>=0; p--) {
-            ind = &cd->ind[p];
-            nat_tot -= ind->nrecv[nzone+1];
-            if (cd->bInPlace)
-            {
-                sbuf = f + nat_tot;
-            }
-            else
-            {
-                sbuf = comm->vbuf2.v;
-                j = 0;
-                for(zone=0; zone<nzone; zone++)
-                {
-                    for(i=ind->cell2at0[zone]; i<ind->cell2at1[zone]; i++)
-                    {
-                        copy_rvec(f[i],sbuf[j]);
-                        j++;
-                    }
-                }
-            }
-            /* Communicate the forces */
-            dd_sendrecv_rvec(dd, d, dddirForward,
-                             sbuf, ind->nrecv[nzone+1],
-                             buf,  ind->nsend[nzone+1]);
-            index = ind->index;
-            /* Add the received forces */
-            n = 0;
-            if (!bPBC)
-            {
-                for(i=0; i<ind->nsend[nzone]; i++)
-                {
-                    at0 = cgindex[index[i]];
-                    at1 = cgindex[index[i]+1];
-                    for(j=at0; j<at1; j++)
-                    {
-                        rvec_inc(f[j],buf[n]);
-                        n++;
-                    }
-                } 
-            }
-            else if (!bScrew)
-            {
-                for(i=0; i<ind->nsend[nzone]; i++)
-                {
-                    at0 = cgindex[index[i]];
-                    at1 = cgindex[index[i]+1];
-                    for(j=at0; j<at1; j++)
-                    {
-                        rvec_inc(f[j],buf[n]);
-                        /* Add this force to the shift force */
-                        rvec_inc(fshift[is],buf[n]);
-                        n++;
-                    }
-                }
-            }
-            else
-            {
-                for(i=0; i<ind->nsend[nzone]; i++)
-                {
-                    at0 = cgindex[index[i]];
-                    at1 = cgindex[index[i]+1];
-                    for(j=at0; j<at1; j++)
-                    {
-                        /* Rotate the force */
-                        f[j][XX] += buf[n][XX];
-                        f[j][YY] -= buf[n][YY];
-                        f[j][ZZ] -= buf[n][ZZ];
-                        if (fshift)
-                        {
-                            /* Add this force to the shift force */
-                            rvec_inc(fshift[is],buf[n]);
-                        }
-                        n++;
-                    }
-                }
-            }
-        }
-        nzone /= 2;
-    }
-}
-
-void dd_atom_spread_real(gmx_domdec_t *dd,real v[])
-{
-    int  nzone,nat_tot,n,d,p,i,j,at0,at1,zone;
-    int  *index,*cgindex;
-    gmx_domdec_comm_t *comm;
-    gmx_domdec_comm_dim_t *cd;
-    gmx_domdec_ind_t *ind;
-    real *buf,*rbuf;
-    
-    comm = dd->comm;
-    
-    cgindex = dd->cgindex;
-    
-    buf = &comm->vbuf.v[0][0];
-
-    nzone = 1;
-    nat_tot = dd->nat_home;
-    for(d=0; d<dd->ndim; d++)
-    {
-        cd = &comm->cd[d];
-        for(p=0; p<cd->np; p++)
-        {
-            ind = &cd->ind[p];
-            index = ind->index;
-            n = 0;
-            for(i=0; i<ind->nsend[nzone]; i++)
-            {
-                at0 = cgindex[index[i]];
-                at1 = cgindex[index[i]+1];
-                for(j=at0; j<at1; j++)
-                {
-                    buf[n] = v[j];
-                    n++;
-                }
-            }
-            
-            if (cd->bInPlace)
-            {
-                rbuf = v + nat_tot;
-            }
-            else
-            {
-                rbuf = &comm->vbuf2.v[0][0];
-            }
-            /* Send and receive the coordinates */
-            dd_sendrecv_real(dd, d, dddirBackward,
-                             buf,  ind->nsend[nzone+1],
-                             rbuf, ind->nrecv[nzone+1]);
-            if (!cd->bInPlace)
-            {
-                j = 0;
-                for(zone=0; zone<nzone; zone++)
-                {
-                    for(i=ind->cell2at0[zone]; i<ind->cell2at1[zone]; i++)
-                    {
-                        v[i] = rbuf[j];
-                        j++;
-                    }
-                }
-            }
-            nat_tot += ind->nrecv[nzone+1];
-        }
-        nzone += nzone;
-    }
-}
-
-void dd_atom_sum_real(gmx_domdec_t *dd,real v[])
-{
-    int  nzone,nat_tot,n,d,p,i,j,at0,at1,zone;
-    int  *index,*cgindex;
-    gmx_domdec_comm_t *comm;
-    gmx_domdec_comm_dim_t *cd;
-    gmx_domdec_ind_t *ind;
-    real *buf,*sbuf;
-    
-    comm = dd->comm;
-    
-    cgindex = dd->cgindex;
-
-    buf = &comm->vbuf.v[0][0];
-
-    n = 0;
-    nzone = comm->zones.n/2;
-    nat_tot = dd->nat_tot;
-    for(d=dd->ndim-1; d>=0; d--)
-    {
-        cd = &comm->cd[d];
-        for(p=cd->np-1; p>=0; p--) {
-            ind = &cd->ind[p];
-            nat_tot -= ind->nrecv[nzone+1];
-            if (cd->bInPlace)
-            {
-                sbuf = v + nat_tot;
-            }
-            else
-            {
-                sbuf = &comm->vbuf2.v[0][0];
-                j = 0;
-                for(zone=0; zone<nzone; zone++)
-                {
-                    for(i=ind->cell2at0[zone]; i<ind->cell2at1[zone]; i++)
-                    {
-                        sbuf[j] = v[i];
-                        j++;
-                    }
-                }
-            }
-            /* Communicate the forces */
-            dd_sendrecv_real(dd, d, dddirForward,
-                             sbuf, ind->nrecv[nzone+1],
-                             buf,  ind->nsend[nzone+1]);
-            index = ind->index;
-            /* Add the received forces */
-            n = 0;
-            for(i=0; i<ind->nsend[nzone]; i++)
-            {
-                at0 = cgindex[index[i]];
-                at1 = cgindex[index[i]+1];
-                for(j=at0; j<at1; j++)
-                {
-                    v[j] += buf[n];
-                    n++;
-                }
-            } 
-        }
-        nzone /= 2;
-    }
-}
-
-static void print_ddzone(FILE *fp,int d,int i,int j,gmx_ddzone_t *zone)
-{
-    fprintf(fp,"zone d0 %d d1 %d d2 %d  min0 %6.3f max1 %6.3f mch0 %6.3f mch1 %6.3f p1_0 %6.3f p1_1 %6.3f\n",
-            d,i,j,
-            zone->min0,zone->max1,
-            zone->mch0,zone->mch0,
-            zone->p1_0,zone->p1_1);
-}
-
-static void dd_sendrecv_ddzone(const gmx_domdec_t *dd,
-                               int ddimind,int direction,
-                               gmx_ddzone_t *buf_s,int n_s,
-                               gmx_ddzone_t *buf_r,int n_r)
-{
-    rvec vbuf_s[5*2],vbuf_r[5*2];
-    int i;
-
-    for(i=0; i<n_s; i++)
-    {
-        vbuf_s[i*2  ][0] = buf_s[i].min0;
-        vbuf_s[i*2  ][1] = buf_s[i].max1;
-        vbuf_s[i*2  ][2] = buf_s[i].mch0;
-        vbuf_s[i*2+1][0] = buf_s[i].mch1;
-        vbuf_s[i*2+1][1] = buf_s[i].p1_0;
-        vbuf_s[i*2+1][2] = buf_s[i].p1_1;
-    }
-
-    dd_sendrecv_rvec(dd, ddimind, direction,
-                     vbuf_s, n_s*2,
-                     vbuf_r, n_r*2);
-
-    for(i=0; i<n_r; i++)
-    {
-        buf_r[i].min0 = vbuf_r[i*2  ][0];
-        buf_r[i].max1 = vbuf_r[i*2  ][1];
-        buf_r[i].mch0 = vbuf_r[i*2  ][2];
-        buf_r[i].mch1 = vbuf_r[i*2+1][0];
-        buf_r[i].p1_0 = vbuf_r[i*2+1][1];
-        buf_r[i].p1_1 = vbuf_r[i*2+1][2];
-    }
-}
-
-static void dd_move_cellx(gmx_domdec_t *dd,gmx_ddbox_t *ddbox,
-                          rvec cell_ns_x0,rvec cell_ns_x1)
-{
-    int  d,d1,dim,dim1,pos,buf_size,i,j,k,p,npulse,npulse_min;
-    gmx_ddzone_t *zp,buf_s[5],buf_r[5],buf_e[5];
-    rvec extr_s[2],extr_r[2];
-    rvec dh;
-    real dist_d,c=0,det;
-    gmx_domdec_comm_t *comm;
-    gmx_bool bPBC,bUse;
-
-    comm = dd->comm;
-
-    for(d=1; d<dd->ndim; d++)
-    {
-        dim = dd->dim[d];
-        zp = (d == 1) ? &comm->zone_d1[0] : &comm->zone_d2[0][0];
-        zp->min0 = cell_ns_x0[dim];
-        zp->max1 = cell_ns_x1[dim];
-        zp->mch0 = cell_ns_x0[dim];
-        zp->mch1 = cell_ns_x1[dim];
-        zp->p1_0 = cell_ns_x0[dim];
-        zp->p1_1 = cell_ns_x1[dim];
-    }
-    
-    for(d=dd->ndim-2; d>=0; d--)
-    {
-        dim  = dd->dim[d];
-        bPBC = (dim < ddbox->npbcdim);
-
-        /* Use an rvec to store two reals */
-        extr_s[d][0] = comm->cell_f0[d+1];
-        extr_s[d][1] = comm->cell_f1[d+1];
-        extr_s[d][2] = 0;
-
-        pos = 0;
-        /* Store the extremes in the backward sending buffer,
-         * so the get updated separately from the forward communication.
-         */
-        for(d1=d; d1<dd->ndim-1; d1++)
-        {
-            /* We invert the order to be able to use the same loop for buf_e */
-            buf_s[pos].min0 = extr_s[d1][1];
-            buf_s[pos].max1 = extr_s[d1][0];
-            buf_s[pos].mch0 = 0;
-            buf_s[pos].mch1 = 0;
-            /* Store the cell corner of the dimension we communicate along */
-            buf_s[pos].p1_0 = comm->cell_x0[dim];
-            buf_s[pos].p1_1 = 0;
-            pos++;
-        }
-
-        buf_s[pos] = (dd->ndim == 2) ? comm->zone_d1[0] : comm->zone_d2[0][0];
-        pos++;
-
-        if (dd->ndim == 3 && d == 0)
-        {
-            buf_s[pos] = comm->zone_d2[0][1];
-            pos++;
-            buf_s[pos] = comm->zone_d1[0];
-            pos++;
-        }
-
-        /* We only need to communicate the extremes
-         * in the forward direction
-         */
-        npulse = comm->cd[d].np;
-        if (bPBC)
-        {
-            /* Take the minimum to avoid double communication */
-            npulse_min = min(npulse,dd->nc[dim]-1-npulse);
-        }
-        else
-        {
-            /* Without PBC we should really not communicate over
-             * the boundaries, but implementing that complicates
-             * the communication setup and therefore we simply
-             * do all communication, but ignore some data.
-             */
-            npulse_min = npulse;
-        }
-        for(p=0; p<npulse_min; p++)
-        {
-            /* Communicate the extremes forward */
-            bUse = (bPBC || dd->ci[dim] > 0);
-
-            dd_sendrecv_rvec(dd, d, dddirForward,
-                             extr_s+d, dd->ndim-d-1,
-                             extr_r+d, dd->ndim-d-1);
-
-            if (bUse)
-            {
-                for(d1=d; d1<dd->ndim-1; d1++)
-                {
-                    extr_s[d1][0] = max(extr_s[d1][0],extr_r[d1][0]);
-                    extr_s[d1][1] = min(extr_s[d1][1],extr_r[d1][1]);
-                }
-            }
-        }
-
-        buf_size = pos;
-        for(p=0; p<npulse; p++)
-        {
-            /* Communicate all the zone information backward */
-            bUse = (bPBC || dd->ci[dim] < dd->nc[dim] - 1);
-
-            dd_sendrecv_ddzone(dd, d, dddirBackward,
-                               buf_s, buf_size,
-                               buf_r, buf_size);
-
-            clear_rvec(dh);
-            if (p > 0)
-            {
-                for(d1=d+1; d1<dd->ndim; d1++)
-                {
-                    /* Determine the decrease of maximum required
-                     * communication height along d1 due to the distance along d,
-                     * this avoids a lot of useless atom communication.
-                     */
-                    dist_d = comm->cell_x1[dim] - buf_r[0].p1_0;
-
-                    if (ddbox->tric_dir[dim])
-                    {
-                        /* c is the off-diagonal coupling between the cell planes
-                         * along directions d and d1.
-                         */
-                        c = ddbox->v[dim][dd->dim[d1]][dim];
-                    }
-                    else
-                    {
-                        c = 0;
-                    }
-                    det = (1 + c*c)*comm->cutoff*comm->cutoff - dist_d*dist_d;
-                    if (det > 0)
-                    {
-                        dh[d1] = comm->cutoff - (c*dist_d + sqrt(det))/(1 + c*c);
-                    }
-                    else
-                    {
-                        /* A negative value signals out of range */
-                        dh[d1] = -1;
-                    }
-                }
-            }
-
-            /* Accumulate the extremes over all pulses */
-            for(i=0; i<buf_size; i++)
-            {
-                if (p == 0)
-                {
-                    buf_e[i] = buf_r[i];
-                }
-                else
-                {
-                    if (bUse)
-                    {
-                        buf_e[i].min0 = min(buf_e[i].min0,buf_r[i].min0);
-                        buf_e[i].max1 = max(buf_e[i].max1,buf_r[i].max1);
-                    }
-
-                    if (dd->ndim == 3 && d == 0 && i == buf_size - 1)
-                    {
-                        d1 = 1;
-                    }
-                    else
-                    {
-                        d1 = d + 1;
-                    }
-                    if (bUse && dh[d1] >= 0)
-                    {
-                        buf_e[i].mch0 = max(buf_e[i].mch0,buf_r[i].mch0-dh[d1]);
-                        buf_e[i].mch1 = max(buf_e[i].mch1,buf_r[i].mch1-dh[d1]);
-                    }
-                }
-                /* Copy the received buffer to the send buffer,
-                 * to pass the data through with the next pulse.
-                 */
-                buf_s[i] = buf_r[i];
-            }
-            if (((bPBC || dd->ci[dim]+npulse < dd->nc[dim]) && p == npulse-1) ||
-                (!bPBC && dd->ci[dim]+1+p == dd->nc[dim]-1))
-            {
-                /* Store the extremes */ 
-                pos = 0;
-
-                for(d1=d; d1<dd->ndim-1; d1++)
-                {
-                    extr_s[d1][1] = min(extr_s[d1][1],buf_e[pos].min0);
-                    extr_s[d1][0] = max(extr_s[d1][0],buf_e[pos].max1);
-                    pos++;
-                }
-
-                if (d == 1 || (d == 0 && dd->ndim == 3))
-                {
-                    for(i=d; i<2; i++)
-                    {
-                        comm->zone_d2[1-d][i] = buf_e[pos];
-                        pos++;
-                    }
-                }
-                if (d == 0)
-                {
-                    comm->zone_d1[1] = buf_e[pos];
-                    pos++;
-                }
-            }
-        }
-    }
-    
-    if (dd->ndim >= 2)
-    {
-        dim = dd->dim[1];
-        for(i=0; i<2; i++)
-        {
-            if (debug)
-            {
-                print_ddzone(debug,1,i,0,&comm->zone_d1[i]);
-            }
-            cell_ns_x0[dim] = min(cell_ns_x0[dim],comm->zone_d1[i].min0);
-            cell_ns_x1[dim] = max(cell_ns_x1[dim],comm->zone_d1[i].max1);
-        }
-    }
-    if (dd->ndim >= 3)
-    {
-        dim = dd->dim[2];
-        for(i=0; i<2; i++)
-        {
-            for(j=0; j<2; j++)
-            {
-                if (debug)
-                {
-                    print_ddzone(debug,2,i,j,&comm->zone_d2[i][j]);
-                }
-                cell_ns_x0[dim] = min(cell_ns_x0[dim],comm->zone_d2[i][j].min0);
-                cell_ns_x1[dim] = max(cell_ns_x1[dim],comm->zone_d2[i][j].max1);
-            }
-        }
-    }
-    for(d=1; d<dd->ndim; d++)
-    {
-        comm->cell_f_max0[d] = extr_s[d-1][0];
-        comm->cell_f_min1[d] = extr_s[d-1][1];
-        if (debug)
-        {
-            fprintf(debug,"Cell fraction d %d, max0 %f, min1 %f\n",
-                    d,comm->cell_f_max0[d],comm->cell_f_min1[d]);
-        }
-    }
-}
-
-static void dd_collect_cg(gmx_domdec_t *dd,
-                          t_state *state_local)
-{
-    gmx_domdec_master_t *ma=NULL;
-    int buf2[2],*ibuf,i,ncg_home=0,*cg=NULL,nat_home=0;
-    t_block *cgs_gl;
-
-    if (state_local->ddp_count == dd->comm->master_cg_ddp_count)
-    {
-        /* The master has the correct distribution */
-        return;
-    }
-    
-    if (state_local->ddp_count == dd->ddp_count)
-    {
-        ncg_home = dd->ncg_home;
-        cg       = dd->index_gl;
-        nat_home = dd->nat_home;
-    } 
-    else if (state_local->ddp_count_cg_gl == state_local->ddp_count)
-    {
-        cgs_gl = &dd->comm->cgs_gl;
-
-        ncg_home = state_local->ncg_gl;
-        cg       = state_local->cg_gl;
-        nat_home = 0;
-        for(i=0; i<ncg_home; i++)
-        {
-            nat_home += cgs_gl->index[cg[i]+1] - cgs_gl->index[cg[i]];
-        }
-    }
-    else
-    {
-        gmx_incons("Attempted to collect a vector for a state for which the charge group distribution is unknown");
-    }
-    
-    buf2[0] = dd->ncg_home;
-    buf2[1] = dd->nat_home;
-    if (DDMASTER(dd))
-    {
-        ma = dd->ma;
-        ibuf = ma->ibuf;
-    }
-    else
-    {
-        ibuf = NULL;
-    }
-    /* Collect the charge group and atom counts on the master */
-    dd_gather(dd,2*sizeof(int),buf2,ibuf);
-    
-    if (DDMASTER(dd))
-    {
-        ma->index[0] = 0;
-        for(i=0; i<dd->nnodes; i++)
-        {
-            ma->ncg[i] = ma->ibuf[2*i];
-            ma->nat[i] = ma->ibuf[2*i+1];
-            ma->index[i+1] = ma->index[i] + ma->ncg[i];
-            
-        }
-        /* Make byte counts and indices */
-        for(i=0; i<dd->nnodes; i++)
-        {
-            ma->ibuf[i] = ma->ncg[i]*sizeof(int);
-            ma->ibuf[dd->nnodes+i] = ma->index[i]*sizeof(int);
-        }
-        if (debug)
-        {
-            fprintf(debug,"Initial charge group distribution: ");
-            for(i=0; i<dd->nnodes; i++)
-                fprintf(debug," %d",ma->ncg[i]);
-            fprintf(debug,"\n");
-        }
-    }
-    
-    /* Collect the charge group indices on the master */
-    dd_gatherv(dd,
-               dd->ncg_home*sizeof(int),dd->index_gl,
-               DDMASTER(dd) ? ma->ibuf : NULL,
-               DDMASTER(dd) ? ma->ibuf+dd->nnodes : NULL,
-               DDMASTER(dd) ? ma->cg : NULL);
-    
-    dd->comm->master_cg_ddp_count = state_local->ddp_count;
-}
-
-static void dd_collect_vec_sendrecv(gmx_domdec_t *dd,
-                                    rvec *lv,rvec *v)
-{
-    gmx_domdec_master_t *ma;
-    int  n,i,c,a,nalloc=0;
-    rvec *buf=NULL;
-    t_block *cgs_gl;
-
-    ma = dd->ma;
-    
-    if (!DDMASTER(dd))
-    {
-#ifdef GMX_MPI
-        MPI_Send(lv,dd->nat_home*sizeof(rvec),MPI_BYTE,DDMASTERRANK(dd),
-                 dd->rank,dd->mpi_comm_all);
-#endif
-    } else {
-        /* Copy the master coordinates to the global array */
-        cgs_gl = &dd->comm->cgs_gl;
-
-        n = DDMASTERRANK(dd);
-        a = 0;
-        for(i=ma->index[n]; i<ma->index[n+1]; i++)
-        {
-            for(c=cgs_gl->index[ma->cg[i]]; c<cgs_gl->index[ma->cg[i]+1]; c++)
-            {
-                copy_rvec(lv[a++],v[c]);
-            }
-        }
-        
-        for(n=0; n<dd->nnodes; n++)
-        {
-            if (n != dd->rank)
-            {
-                if (ma->nat[n] > nalloc)
-                {
-                    nalloc = over_alloc_dd(ma->nat[n]);
-                    srenew(buf,nalloc);
-                }
-#ifdef GMX_MPI
-                MPI_Recv(buf,ma->nat[n]*sizeof(rvec),MPI_BYTE,DDRANK(dd,n),
-                         n,dd->mpi_comm_all,MPI_STATUS_IGNORE);
-#endif
-                a = 0;
-                for(i=ma->index[n]; i<ma->index[n+1]; i++)
-                {
-                    for(c=cgs_gl->index[ma->cg[i]]; c<cgs_gl->index[ma->cg[i]+1]; c++)
-                    {
-                        copy_rvec(buf[a++],v[c]);
-                    }
-                }
-            }
-        }
-        sfree(buf);
-    }
-}
-
-static void get_commbuffer_counts(gmx_domdec_t *dd,
-                                  int **counts,int **disps)
-{
-    gmx_domdec_master_t *ma;
-    int n;
-
-    ma = dd->ma;
-    
-    /* Make the rvec count and displacment arrays */
-    *counts  = ma->ibuf;
-    *disps   = ma->ibuf + dd->nnodes;
-    for(n=0; n<dd->nnodes; n++)
-    {
-        (*counts)[n] = ma->nat[n]*sizeof(rvec);
-        (*disps)[n]  = (n == 0 ? 0 : (*disps)[n-1] + (*counts)[n-1]);
-    }
-}
-
-static void dd_collect_vec_gatherv(gmx_domdec_t *dd,
-                                   rvec *lv,rvec *v)
-{
-    gmx_domdec_master_t *ma;
-    int  *rcounts=NULL,*disps=NULL;
-    int  n,i,c,a;
-    rvec *buf=NULL;
-    t_block *cgs_gl;
-    
-    ma = dd->ma;
-    
-    if (DDMASTER(dd))
-    {
-        get_commbuffer_counts(dd,&rcounts,&disps);
-
-        buf = ma->vbuf;
-    }
-    
-    dd_gatherv(dd,dd->nat_home*sizeof(rvec),lv,rcounts,disps,buf);
-
-    if (DDMASTER(dd))
-    {
-        cgs_gl = &dd->comm->cgs_gl;
-
-        a = 0;
-        for(n=0; n<dd->nnodes; n++)
-        {
-            for(i=ma->index[n]; i<ma->index[n+1]; i++)
-            {
-                for(c=cgs_gl->index[ma->cg[i]]; c<cgs_gl->index[ma->cg[i]+1]; c++)
-                {
-                    copy_rvec(buf[a++],v[c]);
-                }
-            }
-        }
-    }
-}
-
-void dd_collect_vec(gmx_domdec_t *dd,
-                    t_state *state_local,rvec *lv,rvec *v)
-{
-    gmx_domdec_master_t *ma;
-    int  n,i,c,a,nalloc=0;
-    rvec *buf=NULL;
-    
-    dd_collect_cg(dd,state_local);
-
-    if (dd->nnodes <= GMX_DD_NNODES_SENDRECV)
-    {
-        dd_collect_vec_sendrecv(dd,lv,v);
-    }
-    else
-    {
-        dd_collect_vec_gatherv(dd,lv,v);
-    }
-}
-
-
-void dd_collect_state(gmx_domdec_t *dd,
-                      t_state *state_local,t_state *state)
-{
-    int est,i,j,nh;
-
-    nh = state->nhchainlength;
-
-    if (DDMASTER(dd))
-    {
-        state->lambda = state_local->lambda;
-        state->veta = state_local->veta;
-        state->vol0 = state_local->vol0;
-        copy_mat(state_local->box,state->box);
-        copy_mat(state_local->boxv,state->boxv);
-        copy_mat(state_local->svir_prev,state->svir_prev);
-        copy_mat(state_local->fvir_prev,state->fvir_prev);
-        copy_mat(state_local->pres_prev,state->pres_prev);
-
-
-        for(i=0; i<state_local->ngtc; i++)
-        {
-            for(j=0; j<nh; j++) {
-                state->nosehoover_xi[i*nh+j]        = state_local->nosehoover_xi[i*nh+j];
-                state->nosehoover_vxi[i*nh+j]       = state_local->nosehoover_vxi[i*nh+j];
-            }
-            state->therm_integral[i] = state_local->therm_integral[i];            
-        }
-        for(i=0; i<state_local->nnhpres; i++) 
-        {
-            for(j=0; j<nh; j++) {
-                state->nhpres_xi[i*nh+j]        = state_local->nhpres_xi[i*nh+j];
-                state->nhpres_vxi[i*nh+j]       = state_local->nhpres_vxi[i*nh+j];
-            }
-        }
-    }
-    for(est=0; est<estNR; est++)
-    {
-        if (EST_DISTR(est) && state_local->flags & (1<<est))
-        {
-            switch (est) {
-            case estX:
-                dd_collect_vec(dd,state_local,state_local->x,state->x);
-                break;
-            case estV:
-                dd_collect_vec(dd,state_local,state_local->v,state->v);
-                break;
-            case estSDX:
-                dd_collect_vec(dd,state_local,state_local->sd_X,state->sd_X);
-                break;
-            case estCGP:
-                dd_collect_vec(dd,state_local,state_local->cg_p,state->cg_p);
-                break;
-            case estLD_RNG:
-                if (state->nrngi == 1)
-                {
-                    if (DDMASTER(dd))
-                    {
-                        for(i=0; i<state_local->nrng; i++)
-                        {
-                            state->ld_rng[i] = state_local->ld_rng[i];
-                        }
-                    }
-                }
-                else
-                {
-                    dd_gather(dd,state_local->nrng*sizeof(state->ld_rng[0]),
-                              state_local->ld_rng,state->ld_rng);
-                }
-                break;
-            case estLD_RNGI:
-                if (state->nrngi == 1)
-                {
-                   if (DDMASTER(dd))
-                    {
-                        state->ld_rngi[0] = state_local->ld_rngi[0];
-                    } 
-                }
-                else
-                {
-                    dd_gather(dd,sizeof(state->ld_rngi[0]),
-                              state_local->ld_rngi,state->ld_rngi);
-                }
-                break;
-            case estDISRE_INITF:
-            case estDISRE_RM3TAV:
-            case estORIRE_INITF:
-            case estORIRE_DTAV:
-                break;
-            default:
-                gmx_incons("Unknown state entry encountered in dd_collect_state");
-            }
-        }
-    }
-}
-
-static void dd_realloc_fr_cg(t_forcerec *fr,int nalloc)
-{
-    if (debug)
-    {
-        fprintf(debug,"Reallocating forcerec: currently %d, required %d, allocating %d\n",fr->cg_nalloc,nalloc,over_alloc_dd(nalloc));
-    }
-    fr->cg_nalloc = over_alloc_dd(nalloc);
-    srenew(fr->cg_cm,fr->cg_nalloc);
-    srenew(fr->cginfo,fr->cg_nalloc);
-}
-
-static void dd_realloc_state(t_state *state,rvec **f,int nalloc)
-{
-    int est;
-
-    if (debug)
-    {
-        fprintf(debug,"Reallocating state: currently %d, required %d, allocating %d\n",state->nalloc,nalloc,over_alloc_dd(nalloc));
-    }
-
-    state->nalloc = over_alloc_dd(nalloc);
-    
-    for(est=0; est<estNR; est++)
-    {
-        if (EST_DISTR(est) && state->flags & (1<<est))
-        {
-            switch(est) {
-            case estX:
-                srenew(state->x,state->nalloc);
-                break;
-            case estV:
-                srenew(state->v,state->nalloc);
-                break;
-            case estSDX:
-                srenew(state->sd_X,state->nalloc);
-                break;
-            case estCGP:
-                srenew(state->cg_p,state->nalloc);
-                break;
-            case estLD_RNG:
-            case estLD_RNGI:
-            case estDISRE_INITF:
-            case estDISRE_RM3TAV:
-            case estORIRE_INITF:
-            case estORIRE_DTAV:
-                /* No reallocation required */
-                break;
-            default:
-                gmx_incons("Unknown state entry encountered in dd_realloc_state");            
-            }
-        }
-    }
-    
-    if (f != NULL)
-    {
-        srenew(*f,state->nalloc);
-    }
-}
-
-static void dd_distribute_vec_sendrecv(gmx_domdec_t *dd,t_block *cgs,
-                                       rvec *v,rvec *lv)
-{
-    gmx_domdec_master_t *ma;
-    int  n,i,c,a,nalloc=0;
-    rvec *buf=NULL;
-    
-    if (DDMASTER(dd))
-    {
-        ma  = dd->ma;
-        
-        for(n=0; n<dd->nnodes; n++)
-        {
-            if (n != dd->rank)
-            {
-                if (ma->nat[n] > nalloc)
-                {
-                    nalloc = over_alloc_dd(ma->nat[n]);
-                    srenew(buf,nalloc);
-                }
-                /* Use lv as a temporary buffer */
-                a = 0;
-                for(i=ma->index[n]; i<ma->index[n+1]; i++)
-                {
-                    for(c=cgs->index[ma->cg[i]]; c<cgs->index[ma->cg[i]+1]; c++)
-                    {
-                        copy_rvec(v[c],buf[a++]);
-                    }
-                }
-                if (a != ma->nat[n])
-                {
-                    gmx_fatal(FARGS,"Internal error a (%d) != nat (%d)",
-                              a,ma->nat[n]);
-                }
-                
-#ifdef GMX_MPI
-                MPI_Send(buf,ma->nat[n]*sizeof(rvec),MPI_BYTE,
-                         DDRANK(dd,n),n,dd->mpi_comm_all);
-#endif
-            }
-        }
-        sfree(buf);
-        n = DDMASTERRANK(dd);
-        a = 0;
-        for(i=ma->index[n]; i<ma->index[n+1]; i++)
-        {
-            for(c=cgs->index[ma->cg[i]]; c<cgs->index[ma->cg[i]+1]; c++)
-            {
-                copy_rvec(v[c],lv[a++]);
-            }
-        }
-    }
-    else
-    {
-#ifdef GMX_MPI
-        MPI_Recv(lv,dd->nat_home*sizeof(rvec),MPI_BYTE,DDMASTERRANK(dd),
-                 MPI_ANY_TAG,dd->mpi_comm_all,MPI_STATUS_IGNORE);
-#endif
-    }
-}
-
-static void dd_distribute_vec_scatterv(gmx_domdec_t *dd,t_block *cgs,
-                                       rvec *v,rvec *lv)
-{
-    gmx_domdec_master_t *ma;
-    int  *scounts=NULL,*disps=NULL;
-    int  n,i,c,a,nalloc=0;
-    rvec *buf=NULL;
-    
-    if (DDMASTER(dd))
-    {
-        ma  = dd->ma;
-     
-        get_commbuffer_counts(dd,&scounts,&disps);
-
-        buf = ma->vbuf;
-        a = 0;
-        for(n=0; n<dd->nnodes; n++)
-        {
-            for(i=ma->index[n]; i<ma->index[n+1]; i++)
-            {
-                for(c=cgs->index[ma->cg[i]]; c<cgs->index[ma->cg[i]+1]; c++)
-                {
-                    copy_rvec(v[c],buf[a++]);
-                }
-            }
-        }
-    }
-
-    dd_scatterv(dd,scounts,disps,buf,dd->nat_home*sizeof(rvec),lv);
-}
-
-static void dd_distribute_vec(gmx_domdec_t *dd,t_block *cgs,rvec *v,rvec *lv)
-{
-    if (dd->nnodes <= GMX_DD_NNODES_SENDRECV)
-    {
-        dd_distribute_vec_sendrecv(dd,cgs,v,lv);
-    }
-    else
-    {
-        dd_distribute_vec_scatterv(dd,cgs,v,lv);
-    }
-}
-
-static void dd_distribute_state(gmx_domdec_t *dd,t_block *cgs,
-                                t_state *state,t_state *state_local,
-                                rvec **f)
-{
-    int  i,j,ngtch,ngtcp,nh;
-
-    nh = state->nhchainlength;
-
-    if (DDMASTER(dd))
-    {
-        state_local->lambda = state->lambda;
-        state_local->veta   = state->veta;
-        state_local->vol0   = state->vol0;
-        copy_mat(state->box,state_local->box);
-        copy_mat(state->box_rel,state_local->box_rel);
-        copy_mat(state->boxv,state_local->boxv);
-        copy_mat(state->svir_prev,state_local->svir_prev);
-        copy_mat(state->fvir_prev,state_local->fvir_prev);
-        for(i=0; i<state_local->ngtc; i++)
-        {
-            for(j=0; j<nh; j++) {
-                state_local->nosehoover_xi[i*nh+j]        = state->nosehoover_xi[i*nh+j];
-                state_local->nosehoover_vxi[i*nh+j]       = state->nosehoover_vxi[i*nh+j];
-            }
-            state_local->therm_integral[i] = state->therm_integral[i];
-        }
-        for(i=0; i<state_local->nnhpres; i++)
-        {
-            for(j=0; j<nh; j++) {
-                state_local->nhpres_xi[i*nh+j]        = state->nhpres_xi[i*nh+j];
-                state_local->nhpres_vxi[i*nh+j]       = state->nhpres_vxi[i*nh+j];
-            }
-        }
-    }
-    dd_bcast(dd,sizeof(real),&state_local->lambda);
-    dd_bcast(dd,sizeof(real),&state_local->veta);
-    dd_bcast(dd,sizeof(real),&state_local->vol0);
-    dd_bcast(dd,sizeof(state_local->box),state_local->box);
-    dd_bcast(dd,sizeof(state_local->box_rel),state_local->box_rel);
-    dd_bcast(dd,sizeof(state_local->boxv),state_local->boxv);
-    dd_bcast(dd,sizeof(state_local->svir_prev),state_local->svir_prev);
-    dd_bcast(dd,sizeof(state_local->fvir_prev),state_local->fvir_prev);
-    dd_bcast(dd,((state_local->ngtc*nh)*sizeof(double)),state_local->nosehoover_xi);
-    dd_bcast(dd,((state_local->ngtc*nh)*sizeof(double)),state_local->nosehoover_vxi);
-    dd_bcast(dd,state_local->ngtc*sizeof(double),state_local->therm_integral);
-    dd_bcast(dd,((state_local->nnhpres*nh)*sizeof(double)),state_local->nhpres_xi);
-    dd_bcast(dd,((state_local->nnhpres*nh)*sizeof(double)),state_local->nhpres_vxi);
-
-    if (dd->nat_home > state_local->nalloc)
-    {
-        dd_realloc_state(state_local,f,dd->nat_home);
-    }
-    for(i=0; i<estNR; i++)
-    {
-        if (EST_DISTR(i) && state_local->flags & (1<<i))
-        {
-            switch (i) {
-            case estX:
-                dd_distribute_vec(dd,cgs,state->x,state_local->x);
-                break;
-            case estV:
-                dd_distribute_vec(dd,cgs,state->v,state_local->v);
-                break;
-            case estSDX:
-                dd_distribute_vec(dd,cgs,state->sd_X,state_local->sd_X);
-                break;
-            case estCGP:
-                dd_distribute_vec(dd,cgs,state->cg_p,state_local->cg_p);
-                break;
-            case estLD_RNG:
-                if (state->nrngi == 1)
-                {
-                    dd_bcastc(dd,
-                              state_local->nrng*sizeof(state_local->ld_rng[0]),
-                              state->ld_rng,state_local->ld_rng);
-                }
-                else
-                {
-                    dd_scatter(dd,
-                               state_local->nrng*sizeof(state_local->ld_rng[0]),
-                               state->ld_rng,state_local->ld_rng);
-                }
-                break;
-            case estLD_RNGI:
-                if (state->nrngi == 1)
-                {
-                    dd_bcastc(dd,sizeof(state_local->ld_rngi[0]),
-                              state->ld_rngi,state_local->ld_rngi);
-                }
-                else
-                {
-                     dd_scatter(dd,sizeof(state_local->ld_rngi[0]),
-                               state->ld_rngi,state_local->ld_rngi);
-                }   
-                break;
-            case estDISRE_INITF:
-            case estDISRE_RM3TAV:
-            case estORIRE_INITF:
-            case estORIRE_DTAV:
-                /* Not implemented yet */
-                break;
-            default:
-                gmx_incons("Unknown state entry encountered in dd_distribute_state");
-            }
-        }
-    }
-}
-
-static char dim2char(int dim)
-{
-    char c='?';
-    
-    switch (dim)
-    {
-    case XX: c = 'X'; break;
-    case YY: c = 'Y'; break;
-    case ZZ: c = 'Z'; break;
-    default: gmx_fatal(FARGS,"Unknown dim %d",dim);
-    }
-    
-    return c;
-}
-
-static void write_dd_grid_pdb(const char *fn,gmx_large_int_t step,
-                              gmx_domdec_t *dd,matrix box,gmx_ddbox_t *ddbox)
-{
-    rvec grid_s[2],*grid_r=NULL,cx,r;
-    char fname[STRLEN],format[STRLEN],buf[22];
-    FILE *out;
-    int  a,i,d,z,y,x;
-    matrix tric;
-    real vol;
-
-    copy_rvec(dd->comm->cell_x0,grid_s[0]);
-    copy_rvec(dd->comm->cell_x1,grid_s[1]);
-    
-    if (DDMASTER(dd))
-    {
-        snew(grid_r,2*dd->nnodes);
-    }
-    
-    dd_gather(dd,2*sizeof(rvec),grid_s[0],DDMASTER(dd) ? grid_r[0] : NULL);
-    
-    if (DDMASTER(dd))
-    {
-        for(d=0; d<DIM; d++)
-        {
-            for(i=0; i<DIM; i++)
-            {
-                if (d == i)
-                {
-                    tric[d][i] = 1;
-                }
-                else
-                {
-                    if (dd->nc[d] > 1 && d < ddbox->npbcdim)
-                    {
-                        tric[d][i] = box[i][d]/box[i][i];
-                    }
-                    else
-                    {
-                        tric[d][i] = 0;
-                    }
-                }
-            }
-        }
-        sprintf(fname,"%s_%s.pdb",fn,gmx_step_str(step,buf));
-        sprintf(format,"%s%s\n",pdbformat,"%6.2f%6.2f");
-        out = gmx_fio_fopen(fname,"w");
-        gmx_write_pdb_box(out,dd->bScrewPBC ? epbcSCREW : epbcXYZ,box);
-        a = 1;
-        for(i=0; i<dd->nnodes; i++)
-        {
-            vol = dd->nnodes/(box[XX][XX]*box[YY][YY]*box[ZZ][ZZ]);
-            for(d=0; d<DIM; d++)
-            {
-                vol *= grid_r[i*2+1][d] - grid_r[i*2][d];
-            }
-            for(z=0; z<2; z++)
-            {
-                for(y=0; y<2; y++)
-                {
-                    for(x=0; x<2; x++)
-                    {
-                        cx[XX] = grid_r[i*2+x][XX];
-                        cx[YY] = grid_r[i*2+y][YY];
-                        cx[ZZ] = grid_r[i*2+z][ZZ];
-                        mvmul(tric,cx,r);
-                        fprintf(out,format,"ATOM",a++,"CA","GLY",' ',1+i,
-                                10*r[XX],10*r[YY],10*r[ZZ],1.0,vol);
-                    }
-                }
-            }
-            for(d=0; d<DIM; d++)
-            {
-                for(x=0; x<4; x++)
-                {
-                    switch(d)
-                    {
-                    case 0: y = 1 + i*8 + 2*x; break;
-                    case 1: y = 1 + i*8 + 2*x - (x % 2); break;
-                    case 2: y = 1 + i*8 + x; break;
-                    }
-                    fprintf(out,"%6s%5d%5d\n","CONECT",y,y+(1<<d));
-                }
-            }
-        }
-        gmx_fio_fclose(out);
-        sfree(grid_r);
-    }
-}
-
-void write_dd_pdb(const char *fn,gmx_large_int_t step,const char *title,
-                  gmx_mtop_t *mtop,t_commrec *cr,
-                  int natoms,rvec x[],matrix box)
-{
-    char fname[STRLEN],format[STRLEN],format4[STRLEN],buf[22];
-    FILE *out;
-    int  i,ii,resnr,c;
-    char *atomname,*resname;
-    real b;
-    gmx_domdec_t *dd;
-    
-    dd = cr->dd;
-    if (natoms == -1)
-    {
-        natoms = dd->comm->nat[ddnatVSITE];
-    }
-    
-    sprintf(fname,"%s_%s_n%d.pdb",fn,gmx_step_str(step,buf),cr->sim_nodeid);
-    
-    sprintf(format,"%s%s\n",pdbformat,"%6.2f%6.2f");
-    sprintf(format4,"%s%s\n",pdbformat4,"%6.2f%6.2f");
-    
-    out = gmx_fio_fopen(fname,"w");
-    
-    fprintf(out,"TITLE     %s\n",title);
-    gmx_write_pdb_box(out,dd->bScrewPBC ? epbcSCREW : epbcXYZ,box);
-    for(i=0; i<natoms; i++)
-    {
-        ii = dd->gatindex[i];
-        gmx_mtop_atominfo_global(mtop,ii,&atomname,&resnr,&resname);
-        if (i < dd->comm->nat[ddnatZONE])
-        {
-            c = 0;
-            while (i >= dd->cgindex[dd->comm->zones.cg_range[c+1]])
-            {
-                c++;
-            }
-            b = c;
-        }
-        else if (i < dd->comm->nat[ddnatVSITE])
-        {
-            b = dd->comm->zones.n;
-        }
-        else
-        {
-            b = dd->comm->zones.n + 1;
-        }
-        fprintf(out,strlen(atomname)<4 ? format : format4,
-                "ATOM",(ii+1)%100000,
-                atomname,resname,' ',resnr%10000,' ',
-                10*x[i][XX],10*x[i][YY],10*x[i][ZZ],1.0,b);
-    }
-    fprintf(out,"TER\n");
-    
-    gmx_fio_fclose(out);
-}
-
-real dd_cutoff_mbody(gmx_domdec_t *dd)
-{
-    gmx_domdec_comm_t *comm;
-    int  di;
-    real r;
-
-    comm = dd->comm;
-
-    r = -1;
-    if (comm->bInterCGBondeds)
-    {
-        if (comm->cutoff_mbody > 0)
-        {
-            r = comm->cutoff_mbody;
-        }
-        else
-        {
-            /* cutoff_mbody=0 means we do not have DLB */
-            r = comm->cellsize_min[dd->dim[0]];
-            for(di=1; di<dd->ndim; di++)
-            {
-                r = min(r,comm->cellsize_min[dd->dim[di]]);
-            }
-            if (comm->bBondComm)
-            {
-                r = max(r,comm->cutoff_mbody);
-            }
-            else
-            {
-                r = min(r,comm->cutoff);
-            }
-        }
-    }
-
-    return r;
-}
-
-real dd_cutoff_twobody(gmx_domdec_t *dd)
-{
-    real r_mb;
-
-    r_mb = dd_cutoff_mbody(dd);
-
-    return max(dd->comm->cutoff,r_mb);
-}
-
-
-static void dd_cart_coord2pmecoord(gmx_domdec_t *dd,ivec coord,ivec coord_pme)
-{
-    int nc,ntot;
-    
-    nc   = dd->nc[dd->comm->cartpmedim];
-    ntot = dd->comm->ntot[dd->comm->cartpmedim];
-    copy_ivec(coord,coord_pme);
-    coord_pme[dd->comm->cartpmedim] =
-        nc + (coord[dd->comm->cartpmedim]*(ntot - nc) + (ntot - nc)/2)/nc;
-}
-
-static int low_ddindex2pmeindex(int ndd,int npme,int ddindex)
-{
-    /* Here we assign a PME node to communicate with this DD node
-     * by assuming that the major index of both is x.
-     * We add cr->npmenodes/2 to obtain an even distribution.
-     */
-    return (ddindex*npme + npme/2)/ndd;
-}
-
-static int ddindex2pmeindex(const gmx_domdec_t *dd,int ddindex)
-{
-    return low_ddindex2pmeindex(dd->nnodes,dd->comm->npmenodes,ddindex);
-}
-
-static int cr_ddindex2pmeindex(const t_commrec *cr,int ddindex)
-{
-    return low_ddindex2pmeindex(cr->dd->nnodes,cr->npmenodes,ddindex);
-}
-
-static int *dd_pmenodes(t_commrec *cr)
-{
-    int *pmenodes;
-    int n,i,p0,p1;
-    
-    snew(pmenodes,cr->npmenodes);
-    n = 0;
-    for(i=0; i<cr->dd->nnodes; i++) {
-        p0 = cr_ddindex2pmeindex(cr,i);
-        p1 = cr_ddindex2pmeindex(cr,i+1);
-        if (i+1 == cr->dd->nnodes || p1 > p0) {
-            if (debug)
-                fprintf(debug,"pmenode[%d] = %d\n",n,i+1+n);
-            pmenodes[n] = i + 1 + n;
-            n++;
-        }
-    }
-
-    return pmenodes;
-}
-
-static int gmx_ddcoord2pmeindex(t_commrec *cr,int x,int y,int z)
-{
-    gmx_domdec_t *dd;
-    ivec coords,coords_pme,nc;
-    int  slab;
-    
-    dd = cr->dd;
-    /*
-      if (dd->comm->bCartesian) {
-      gmx_ddindex2xyz(dd->nc,ddindex,coords);
-      dd_coords2pmecoords(dd,coords,coords_pme);
-      copy_ivec(dd->ntot,nc);
-      nc[dd->cartpmedim]         -= dd->nc[dd->cartpmedim];
-      coords_pme[dd->cartpmedim] -= dd->nc[dd->cartpmedim];
-      
-      slab = (coords_pme[XX]*nc[YY] + coords_pme[YY])*nc[ZZ] + coords_pme[ZZ];
-      } else {
-      slab = (ddindex*cr->npmenodes + cr->npmenodes/2)/dd->nnodes;
-      }
-    */
-    coords[XX] = x;
-    coords[YY] = y;
-    coords[ZZ] = z;
-    slab = ddindex2pmeindex(dd,dd_index(dd->nc,coords));
-    
-    return slab;
-}
-
-static int ddcoord2simnodeid(t_commrec *cr,int x,int y,int z)
-{
-    gmx_domdec_comm_t *comm;
-    ivec coords;
-    int  ddindex,nodeid=-1;
-    
-    comm = cr->dd->comm;
-    
-    coords[XX] = x;
-    coords[YY] = y;
-    coords[ZZ] = z;
-    if (comm->bCartesianPP_PME)
-    {
-#ifdef GMX_MPI
-        MPI_Cart_rank(cr->mpi_comm_mysim,coords,&nodeid);
-#endif
-    }
-    else
-    {
-        ddindex = dd_index(cr->dd->nc,coords);
-        if (comm->bCartesianPP)
-        {
-            nodeid = comm->ddindex2simnodeid[ddindex];
-        }
-        else
-        {
-            if (comm->pmenodes)
-            {
-                nodeid = ddindex + gmx_ddcoord2pmeindex(cr,x,y,z);
-            }
-            else
-            {
-                nodeid = ddindex;
-            }
-        }
-    }
-  
-    return nodeid;
-}
-
-static int dd_simnode2pmenode(t_commrec *cr,int sim_nodeid)
-{
-    gmx_domdec_t *dd;
-    gmx_domdec_comm_t *comm;
-    ivec coord,coord_pme;
-    int  i;
-    int  pmenode=-1;
-    
-    dd = cr->dd;
-    comm = dd->comm;
-    
-    /* This assumes a uniform x domain decomposition grid cell size */
-    if (comm->bCartesianPP_PME)
-    {
-#ifdef GMX_MPI
-        MPI_Cart_coords(cr->mpi_comm_mysim,sim_nodeid,DIM,coord);
-        if (coord[comm->cartpmedim] < dd->nc[comm->cartpmedim])
-        {
-            /* This is a PP node */
-            dd_cart_coord2pmecoord(dd,coord,coord_pme);
-            MPI_Cart_rank(cr->mpi_comm_mysim,coord_pme,&pmenode);
-        }
-#endif
-    }
-    else if (comm->bCartesianPP)
-    {
-        if (sim_nodeid < dd->nnodes)
-        {
-            pmenode = dd->nnodes + ddindex2pmeindex(dd,sim_nodeid);
-        }
-    }
-    else
-    {
-        /* This assumes DD cells with identical x coordinates
-         * are numbered sequentially.
-         */
-        if (dd->comm->pmenodes == NULL)
-        {
-            if (sim_nodeid < dd->nnodes)
-            {
-                /* The DD index equals the nodeid */
-                pmenode = dd->nnodes + ddindex2pmeindex(dd,sim_nodeid);
-            }
-        }
-        else
-        {
-            i = 0;
-            while (sim_nodeid > dd->comm->pmenodes[i])
-            {
-                i++;
-            }
-            if (sim_nodeid < dd->comm->pmenodes[i])
-            {
-                pmenode = dd->comm->pmenodes[i];
-            }
-        }
-    }
-    
-    return pmenode;
-}
-
-gmx_bool gmx_pmeonlynode(t_commrec *cr,int sim_nodeid)
-{
-    gmx_bool bPMEOnlyNode;
-    
-    if (DOMAINDECOMP(cr))
-    {
-        bPMEOnlyNode = (dd_simnode2pmenode(cr,sim_nodeid) == -1);
-    }
-    else
-    {
-        bPMEOnlyNode = FALSE;
-    }
-    
-    return bPMEOnlyNode;
-}
-
-void get_pme_ddnodes(t_commrec *cr,int pmenodeid,
-                     int *nmy_ddnodes,int **my_ddnodes,int *node_peer)
-{
-    gmx_domdec_t *dd;
-    int x,y,z;
-    ivec coord,coord_pme;
-    
-    dd = cr->dd;
-    
-    snew(*my_ddnodes,(dd->nnodes+cr->npmenodes-1)/cr->npmenodes);
-    
-    *nmy_ddnodes = 0;
-    for(x=0; x<dd->nc[XX]; x++)
-    {
-        for(y=0; y<dd->nc[YY]; y++)
-        {
-            for(z=0; z<dd->nc[ZZ]; z++)
-            {
-                if (dd->comm->bCartesianPP_PME)
-                {
-                    coord[XX] = x;
-                    coord[YY] = y;
-                    coord[ZZ] = z;
-                    dd_cart_coord2pmecoord(dd,coord,coord_pme);
-                    if (dd->ci[XX] == coord_pme[XX] &&
-                        dd->ci[YY] == coord_pme[YY] &&
-                        dd->ci[ZZ] == coord_pme[ZZ])
-                        (*my_ddnodes)[(*nmy_ddnodes)++] = ddcoord2simnodeid(cr,x,y,z);
-                }
-                else
-                {
-                    /* The slab corresponds to the nodeid in the PME group */
-                    if (gmx_ddcoord2pmeindex(cr,x,y,z) == pmenodeid)
-                    {
-                        (*my_ddnodes)[(*nmy_ddnodes)++] = ddcoord2simnodeid(cr,x,y,z);
-                    }
-                }
-            }
-        }
-    }
-    
-    /* The last PP-only node is the peer node */
-    *node_peer = (*my_ddnodes)[*nmy_ddnodes-1];
-    
-    if (debug)
-    {
-        fprintf(debug,"Receive coordinates from PP nodes:");
-        for(x=0; x<*nmy_ddnodes; x++)
-        {
-            fprintf(debug," %d",(*my_ddnodes)[x]);
-        }
-        fprintf(debug,"\n");
-    }
-}
-
-static gmx_bool receive_vir_ener(t_commrec *cr)
-{
-    gmx_domdec_comm_t *comm;
-    int  pmenode,coords[DIM],rank;
-    gmx_bool bReceive;
-    
-    bReceive = TRUE;
-    if (cr->npmenodes < cr->dd->nnodes)
-    {
-        comm = cr->dd->comm;
-        if (comm->bCartesianPP_PME)
-        {
-            pmenode = dd_simnode2pmenode(cr,cr->sim_nodeid);
-#ifdef GMX_MPI
-            MPI_Cart_coords(cr->mpi_comm_mysim,cr->sim_nodeid,DIM,coords);
-            coords[comm->cartpmedim]++;
-            if (coords[comm->cartpmedim] < cr->dd->nc[comm->cartpmedim])
-            {
-                MPI_Cart_rank(cr->mpi_comm_mysim,coords,&rank);
-                if (dd_simnode2pmenode(cr,rank) == pmenode)
-                {
-                    /* This is not the last PP node for pmenode */
-                    bReceive = FALSE;
-                }
-            }
-#endif  
-        }
-        else
-        {
-            pmenode = dd_simnode2pmenode(cr,cr->sim_nodeid);
-            if (cr->sim_nodeid+1 < cr->nnodes &&
-                dd_simnode2pmenode(cr,cr->sim_nodeid+1) == pmenode)
-            {
-                /* This is not the last PP node for pmenode */
-                bReceive = FALSE;
-            }
-        }
-    }
-    
-    return bReceive;
-}
-
-static void set_zones_ncg_home(gmx_domdec_t *dd)
-{
-    gmx_domdec_zones_t *zones;
-    int i;
-
-    zones = &dd->comm->zones;
-
-    zones->cg_range[0] = 0;
-    for(i=1; i<zones->n+1; i++)
-    {
-        zones->cg_range[i] = dd->ncg_home;
-    }
-}
-
-static void rebuild_cgindex(gmx_domdec_t *dd,int *gcgs_index,t_state *state)
-{
-    int nat,i,*ind,*dd_cg_gl,*cgindex,cg_gl;
-    
-    ind = state->cg_gl;
-    dd_cg_gl = dd->index_gl;
-    cgindex  = dd->cgindex;
-    nat = 0;
-    cgindex[0] = nat;
-    for(i=0; i<state->ncg_gl; i++)
-    {
-        cgindex[i] = nat;
-        cg_gl = ind[i];
-        dd_cg_gl[i] = cg_gl;
-        nat += gcgs_index[cg_gl+1] - gcgs_index[cg_gl];
-    }
-    cgindex[i] = nat;
-    
-    dd->ncg_home = state->ncg_gl;
-    dd->nat_home = nat;
-
-    set_zones_ncg_home(dd);
-}
-
-static int ddcginfo(const cginfo_mb_t *cginfo_mb,int cg)
-{
-    while (cg >= cginfo_mb->cg_end)
-    {
-        cginfo_mb++;
-    }
-
-    return cginfo_mb->cginfo[(cg - cginfo_mb->cg_start) % cginfo_mb->cg_mod];
-}
-
-static void dd_set_cginfo(int *index_gl,int cg0,int cg1,
-                          t_forcerec *fr,char *bLocalCG)
-{
-    cginfo_mb_t *cginfo_mb;
-    int *cginfo;
-    int cg;
-
-    if (fr != NULL)
-    {
-        cginfo_mb = fr->cginfo_mb;
-        cginfo    = fr->cginfo;
-
-        for(cg=cg0; cg<cg1; cg++)
-        {
-            cginfo[cg] = ddcginfo(cginfo_mb,index_gl[cg]);
-        }
-    }
-
-    if (bLocalCG != NULL)
-    {
-        for(cg=cg0; cg<cg1; cg++)
-        {
-            bLocalCG[index_gl[cg]] = TRUE;
-        }
-    }
-}
-
-static void make_dd_indices(gmx_domdec_t *dd,int *gcgs_index,int cg_start)
-{
-    int nzone,zone,zone1,cg0,cg,cg_gl,a,a_gl;
-    int *zone2cg,*zone_ncg1,*index_gl,*gatindex;
-    gmx_ga2la_t *ga2la;
-    char *bLocalCG;
-
-    bLocalCG = dd->comm->bLocalCG;
-
-    if (dd->nat_tot > dd->gatindex_nalloc)
-    {
-        dd->gatindex_nalloc = over_alloc_dd(dd->nat_tot);
-        srenew(dd->gatindex,dd->gatindex_nalloc);
-    }
-
-    nzone      = dd->comm->zones.n;
-    zone2cg    = dd->comm->zones.cg_range;
-    zone_ncg1  = dd->comm->zone_ncg1;
-    index_gl   = dd->index_gl;
-    gatindex   = dd->gatindex;
-
-    if (zone2cg[1] != dd->ncg_home)
-    {
-        gmx_incons("dd->ncg_zone is not up to date");
-    }
-    
-    /* Make the local to global and global to local atom index */
-    a = dd->cgindex[cg_start];
-    for(zone=0; zone<nzone; zone++)
-    {
-        if (zone == 0)
-        {
-            cg0 = cg_start;
-        }
-        else
-        {
-            cg0 = zone2cg[zone];
-        }
-        for(cg=cg0; cg<zone2cg[zone+1]; cg++)
-        {
-            zone1 = zone;
-            if (cg - cg0 >= zone_ncg1[zone])
-            {
-                /* Signal that this cg is from more than one zone away */
-                zone1 += nzone;
-            }
-            cg_gl = index_gl[cg];
-            for(a_gl=gcgs_index[cg_gl]; a_gl<gcgs_index[cg_gl+1]; a_gl++)
-            {
-                gatindex[a] = a_gl;
-                ga2la_set(dd->ga2la,a_gl,a,zone1);
-                a++;
-            }
-        }
-    }
-}
-
-static int check_bLocalCG(gmx_domdec_t *dd,int ncg_sys,const char *bLocalCG,
-                          const char *where)
-{
-    int ncg,i,ngl,nerr;
-
-    nerr = 0;
-    if (bLocalCG == NULL)
-    {
-        return nerr;
-    }
-    for(i=0; i<dd->ncg_tot; i++)
-    {
-        if (!bLocalCG[dd->index_gl[i]])
-        {
-            fprintf(stderr,
-                    "DD node %d, %s: cg %d, global cg %d is not marked in bLocalCG (ncg_home %d)\n",dd->rank,where,i+1,dd->index_gl[i]+1,dd->ncg_home);
-            nerr++;
-        }
-    }
-    ngl = 0;
-    for(i=0; i<ncg_sys; i++)
-    {
-        if (bLocalCG[i])
-        {
-            ngl++;
-        }
-    }
-    if (ngl != dd->ncg_tot)
-    {
-        fprintf(stderr,"DD node %d, %s: In bLocalCG %d cgs are marked as local, whereas there are %d\n",dd->rank,where,ngl,dd->ncg_tot);
-        nerr++;
-    }
-
-    return nerr;
-}
-
-static void check_index_consistency(gmx_domdec_t *dd,
-                                    int natoms_sys,int ncg_sys,
-                                    const char *where)
-{
-    int  nerr,ngl,i,a,cell;
-    int  *have;
-
-    nerr = 0;
-
-    if (dd->comm->DD_debug > 1)
-    {
-        snew(have,natoms_sys);
-        for(a=0; a<dd->nat_tot; a++)
-        {
-            if (have[dd->gatindex[a]] > 0)
-            {
-                fprintf(stderr,"DD node %d: global atom %d occurs twice: index %d and %d\n",dd->rank,dd->gatindex[a]+1,have[dd->gatindex[a]],a+1);
-            }
-            else
-            {
-                have[dd->gatindex[a]] = a + 1;
-            }
-        }
-        sfree(have);
-    }
-
-    snew(have,dd->nat_tot);
-
-    ngl  = 0;
-    for(i=0; i<natoms_sys; i++)
-    {
-        if (ga2la_get(dd->ga2la,i,&a,&cell))
-        {
-            if (a >= dd->nat_tot)
-            {
-                fprintf(stderr,"DD node %d: global atom %d marked as local atom %d, which is larger than nat_tot (%d)\n",dd->rank,i+1,a+1,dd->nat_tot);
-                nerr++;
-            }
-            else
-            {
-                have[a] = 1;
-                if (dd->gatindex[a] != i)
-                {
-                    fprintf(stderr,"DD node %d: global atom %d marked as local atom %d, which has global atom index %d\n",dd->rank,i+1,a+1,dd->gatindex[a]+1);
-                    nerr++;
-                }
-            }
-            ngl++;
-        }
-    }
-    if (ngl != dd->nat_tot)
-    {
-        fprintf(stderr,
-                "DD node %d, %s: %d global atom indices, %d local atoms\n",
-                dd->rank,where,ngl,dd->nat_tot);
-    }
-    for(a=0; a<dd->nat_tot; a++)
-    {
-        if (have[a] == 0)
-        {
-            fprintf(stderr,
-                    "DD node %d, %s: local atom %d, global %d has no global index\n",
-                    dd->rank,where,a+1,dd->gatindex[a]+1);
-        }
-    }
-    sfree(have);
-
-    nerr += check_bLocalCG(dd,ncg_sys,dd->comm->bLocalCG,where);
-
-    if (nerr > 0) {
-        gmx_fatal(FARGS,"DD node %d, %s: %d atom/cg index inconsistencies",
-                  dd->rank,where,nerr);
-    }
-}
-
-static void clear_dd_indices(gmx_domdec_t *dd,int cg_start,int a_start)
-{
-    int  i;
-    char *bLocalCG;
-
-    if (a_start == 0)
-    {
-        /* Clear the whole list without searching */
-        ga2la_clear(dd->ga2la);
-    }
-    else
-    {
-        for(i=a_start; i<dd->nat_tot; i++)
-        {
-            ga2la_del(dd->ga2la,dd->gatindex[i]);
-        }
-    }
-
-    bLocalCG = dd->comm->bLocalCG;
-    if (bLocalCG)
-    {
-        for(i=cg_start; i<dd->ncg_tot; i++)
-        {
-            bLocalCG[dd->index_gl[i]] = FALSE;
-        }
-    }
-
-    dd_clear_local_vsite_indices(dd);
-    
-    if (dd->constraints)
-    {
-        dd_clear_local_constraint_indices(dd);
-    }
-}
-
-static real grid_jump_limit(gmx_domdec_comm_t *comm,int dim_ind)
-{
-    real grid_jump_limit;
-
-    /* The distance between the boundaries of cells at distance
-     * x+-1,y+-1 or y+-1,z+-1 is limited by the cut-off restrictions
-     * and by the fact that cells should not be shifted by more than
-     * half their size, such that cg's only shift by one cell
-     * at redecomposition.
-     */
-    grid_jump_limit = comm->cellsize_limit;
-    if (!comm->bVacDLBNoLimit)
-    {
-        grid_jump_limit = max(grid_jump_limit,
-                              comm->cutoff/comm->cd[dim_ind].np);
-    }
-
-    return grid_jump_limit;
-}
-
-static void check_grid_jump(gmx_large_int_t step,gmx_domdec_t *dd,gmx_ddbox_t *ddbox)
-{
-    gmx_domdec_comm_t *comm;
-    int  d,dim;
-    real limit,bfac;
-    
-    comm = dd->comm;
-    
-    for(d=1; d<dd->ndim; d++)
-    {
-        dim = dd->dim[d];
-        limit = grid_jump_limit(comm,d);
-        bfac = ddbox->box_size[dim];
-        if (ddbox->tric_dir[dim])
-        {
-            bfac *= ddbox->skew_fac[dim];
-        }
-        if ((comm->cell_f1[d] - comm->cell_f_max0[d])*bfac <  limit ||
-            (comm->cell_f0[d] - comm->cell_f_min1[d])*bfac > -limit)
-        {
-            char buf[22];
-            gmx_fatal(FARGS,"Step %s: The domain decomposition grid has shifted too much in the %c-direction around cell %d %d %d\n",
-                      gmx_step_str(step,buf),
-                      dim2char(dim),dd->ci[XX],dd->ci[YY],dd->ci[ZZ]);
-        }
-    }
-}
-
-static int dd_load_count(gmx_domdec_comm_t *comm)
-{
-    return (comm->eFlop ? comm->flop_n : comm->cycl_n[ddCyclF]);
-}
-
-static float dd_force_load(gmx_domdec_comm_t *comm)
-{
-    float load;
-    
-    if (comm->eFlop)
-    {
-        load = comm->flop;
-        if (comm->eFlop > 1)
-        {
-            load *= 1.0 + (comm->eFlop - 1)*(0.1*rand()/RAND_MAX - 0.05);
-        }
-    } 
-    else
-    {
-        load = comm->cycl[ddCyclF];
-        if (comm->cycl_n[ddCyclF] > 1)
-        {
-            /* Subtract the maximum of the last n cycle counts
-             * to get rid of possible high counts due to other soures,
-             * for instance system activity, that would otherwise
-             * affect the dynamic load balancing.
-             */
-            load -= comm->cycl_max[ddCyclF];
-        }
-    }
-    
-    return load;
-}
-
-static void set_slb_pme_dim_f(gmx_domdec_t *dd,int dim,real **dim_f)
-{
-    gmx_domdec_comm_t *comm;
-    int i;
-    
-    comm = dd->comm;
-    
-    snew(*dim_f,dd->nc[dim]+1);
-    (*dim_f)[0] = 0;
-    for(i=1; i<dd->nc[dim]; i++)
-    {
-        if (comm->slb_frac[dim])
-        {
-            (*dim_f)[i] = (*dim_f)[i-1] + comm->slb_frac[dim][i-1];
-        }
-        else
-        {
-            (*dim_f)[i] = (real)i/(real)dd->nc[dim];
-        }
-    }
-    (*dim_f)[dd->nc[dim]] = 1;
-}
-
-static void init_ddpme(gmx_domdec_t *dd,gmx_ddpme_t *ddpme,int dimind)
-{
-    int         pmeindex,slab,nso,i;
-    ivec xyz;
-    
-    if (dimind == 0 && dd->dim[0] == YY && dd->comm->npmenodes_x == 1)
-    {
-        ddpme->dim = YY;
-    }
-    else
-    {
-        ddpme->dim = dimind;
-    }
-    ddpme->dim_match = (ddpme->dim == dd->dim[dimind]);
-    
-    ddpme->nslab = (ddpme->dim == 0 ?
-                    dd->comm->npmenodes_x :
-                    dd->comm->npmenodes_y);
-
-    if (ddpme->nslab <= 1)
-    {
-        return;
-    }
-
-    nso = dd->comm->npmenodes/ddpme->nslab;
-    /* Determine for each PME slab the PP location range for dimension dim */
-    snew(ddpme->pp_min,ddpme->nslab);
-    snew(ddpme->pp_max,ddpme->nslab);
-    for(slab=0; slab<ddpme->nslab; slab++) {
-        ddpme->pp_min[slab] = dd->nc[dd->dim[dimind]] - 1;
-        ddpme->pp_max[slab] = 0;
-    }
-    for(i=0; i<dd->nnodes; i++) {
-        ddindex2xyz(dd->nc,i,xyz);
-        /* For y only use our y/z slab.
-         * This assumes that the PME x grid size matches the DD grid size.
-         */
-        if (dimind == 0 || xyz[XX] == dd->ci[XX]) {
-            pmeindex = ddindex2pmeindex(dd,i);
-            if (dimind == 0) {
-                slab = pmeindex/nso;
-            } else {
-                slab = pmeindex % ddpme->nslab;
-            }
-            ddpme->pp_min[slab] = min(ddpme->pp_min[slab],xyz[dimind]);
-            ddpme->pp_max[slab] = max(ddpme->pp_max[slab],xyz[dimind]);
-        }
-    }
-
-    set_slb_pme_dim_f(dd,ddpme->dim,&ddpme->slb_dim_f);
-}
-
-int dd_pme_maxshift_x(gmx_domdec_t *dd)
-{
-    if (dd->comm->ddpme[0].dim == XX)
-    {
-        return dd->comm->ddpme[0].maxshift;
-    }
-    else
-    {
-        return 0;
-    }
-}
-
-int dd_pme_maxshift_y(gmx_domdec_t *dd)
-{
-    if (dd->comm->ddpme[0].dim == YY)
-    {
-        return dd->comm->ddpme[0].maxshift;
-    }
-    else if (dd->comm->npmedecompdim >= 2 && dd->comm->ddpme[1].dim == YY)
-    {
-        return dd->comm->ddpme[1].maxshift;
-    }
-    else
-    {
-        return 0;
-    }
-}
-
-static void set_pme_maxshift(gmx_domdec_t *dd,gmx_ddpme_t *ddpme,
-                             gmx_bool bUniform,gmx_ddbox_t *ddbox,real *cell_f)
-{
-    gmx_domdec_comm_t *comm;
-    int  nc,ns,s;
-    int  *xmin,*xmax;
-    real range,pme_boundary;
-    int  sh;
-    
-    comm = dd->comm;
-    nc  = dd->nc[ddpme->dim];
-    ns  = ddpme->nslab;
-    
-    if (!ddpme->dim_match)
-    {
-        /* PP decomposition is not along dim: the worst situation */
-        sh = ns/2;
-    }
-    else if (ns <= 3 || (bUniform && ns == nc))
-    {
-        /* The optimal situation */
-        sh = 1;
-    }
-    else
-    {
-        /* We need to check for all pme nodes which nodes they
-         * could possibly need to communicate with.
-         */
-        xmin = ddpme->pp_min;
-        xmax = ddpme->pp_max;
-        /* Allow for atoms to be maximally 2/3 times the cut-off
-         * out of their DD cell. This is a reasonable balance between
-         * between performance and support for most charge-group/cut-off
-         * combinations.
-         */
-        range  = 2.0/3.0*comm->cutoff/ddbox->box_size[ddpme->dim];
-        /* Avoid extra communication when we are exactly at a boundary */
-        range *= 0.999;
-        
-        sh = 1;
-        for(s=0; s<ns; s++)
-        {
-            /* PME slab s spreads atoms between box frac. s/ns and (s+1)/ns */
-            pme_boundary = (real)s/ns;
-            while (sh+1 < ns &&
-                   ((s-(sh+1) >= 0 &&
-                     cell_f[xmax[s-(sh+1)   ]+1]     + range > pme_boundary) ||
-                    (s-(sh+1) <  0 &&
-                     cell_f[xmax[s-(sh+1)+ns]+1] - 1 + range > pme_boundary)))
-            {
-                sh++;
-            }
-            pme_boundary = (real)(s+1)/ns;
-            while (sh+1 < ns &&
-                   ((s+(sh+1) <  ns &&
-                     cell_f[xmin[s+(sh+1)   ]  ]     - range < pme_boundary) ||
-                    (s+(sh+1) >= ns &&
-                     cell_f[xmin[s+(sh+1)-ns]  ] + 1 - range < pme_boundary)))
-            {
-                sh++;
-            }
-        }
-    }
-    
-    ddpme->maxshift = sh;
-    
-    if (debug)
-    {
-        fprintf(debug,"PME slab communication range for dim %d is %d\n",
-                ddpme->dim,ddpme->maxshift);
-    }
-}
-
-static void check_box_size(gmx_domdec_t *dd,gmx_ddbox_t *ddbox)
-{
-    int d,dim;
-    
-    for(d=0; d<dd->ndim; d++)
-    {
-        dim = dd->dim[d];
-        if (dim < ddbox->nboundeddim &&
-            ddbox->box_size[dim]*ddbox->skew_fac[dim] <
-            dd->nc[dim]*dd->comm->cellsize_limit*DD_CELL_MARGIN)
-        {
-            gmx_fatal(FARGS,"The %c-size of the box (%f) times the triclinic skew factor (%f) is smaller than the number of DD cells (%d) times the smallest allowed cell size (%f)\n",
-                      dim2char(dim),ddbox->box_size[dim],ddbox->skew_fac[dim],
-                      dd->nc[dim],dd->comm->cellsize_limit);
-        }
-    }
-}
-
-static void set_dd_cell_sizes_slb(gmx_domdec_t *dd,gmx_ddbox_t *ddbox,
-                                  gmx_bool bMaster,ivec npulse)
-{
-    gmx_domdec_comm_t *comm;
-    int  d,j;
-    rvec cellsize_min;
-    real *cell_x,cell_dx,cellsize;
-    
-    comm = dd->comm;
-    
-    for(d=0; d<DIM; d++)
-    {
-        cellsize_min[d] = ddbox->box_size[d]*ddbox->skew_fac[d];
-        npulse[d] = 1;
-        if (dd->nc[d] == 1 || comm->slb_frac[d] == NULL)
-        {
-            /* Uniform grid */
-            cell_dx = ddbox->box_size[d]/dd->nc[d];
-            if (bMaster)
-            {
-                for(j=0; j<dd->nc[d]+1; j++)
-                {
-                    dd->ma->cell_x[d][j] = ddbox->box0[d] + j*cell_dx;
-                }
-            }
-            else
-            {
-                comm->cell_x0[d] = ddbox->box0[d] + (dd->ci[d]  )*cell_dx;
-                comm->cell_x1[d] = ddbox->box0[d] + (dd->ci[d]+1)*cell_dx;
-            }
-            cellsize = cell_dx*ddbox->skew_fac[d];
-            while (cellsize*npulse[d] < comm->cutoff && npulse[d] < dd->nc[d]-1)
-            {
-                npulse[d]++;
-            }
-            cellsize_min[d] = cellsize;
-        }
-        else
-        {
-            /* Statically load balanced grid */
-            /* Also when we are not doing a master distribution we determine
-             * all cell borders in a loop to obtain identical values
-             * to the master distribution case and to determine npulse.
-             */
-            if (bMaster)
-            {
-                cell_x = dd->ma->cell_x[d];
-            }
-            else
-            {
-                snew(cell_x,dd->nc[d]+1);
-            }
-            cell_x[0] = ddbox->box0[d];
-            for(j=0; j<dd->nc[d]; j++)
-            {
-                cell_dx = ddbox->box_size[d]*comm->slb_frac[d][j];
-                cell_x[j+1] = cell_x[j] + cell_dx;
-                cellsize = cell_dx*ddbox->skew_fac[d];
-                while (cellsize*npulse[d] < comm->cutoff &&
-                       npulse[d] < dd->nc[d]-1)
-                {
-                    npulse[d]++;
-                }
-                cellsize_min[d] = min(cellsize_min[d],cellsize);
-            }
-            if (!bMaster)
-            {
-                comm->cell_x0[d] = cell_x[dd->ci[d]];
-                comm->cell_x1[d] = cell_x[dd->ci[d]+1];
-                sfree(cell_x);
-            }
-        }
-        /* The following limitation is to avoid that a cell would receive
-         * some of its own home charge groups back over the periodic boundary.
-         * Double charge groups cause trouble with the global indices.
-         */
-        if (d < ddbox->npbcdim &&
-            dd->nc[d] > 1 && npulse[d] >= dd->nc[d])
-        {
-            gmx_fatal_collective(FARGS,NULL,dd,
-                                 "The box size in direction %c (%f) times the triclinic skew factor (%f) is too small for a cut-off of %f with %d domain decomposition cells, use 1 or more than %d %s or increase the box size in this direction",
-                                 dim2char(d),ddbox->box_size[d],ddbox->skew_fac[d],
-                                 comm->cutoff,
-                                 dd->nc[d],dd->nc[d],
-                                 dd->nnodes > dd->nc[d] ? "cells" : "processors");
-        }
-    }
-    
-    if (!comm->bDynLoadBal)
-    {
-        copy_rvec(cellsize_min,comm->cellsize_min);
-    }
-   
-    for(d=0; d<comm->npmedecompdim; d++)
-    {
-        set_pme_maxshift(dd,&comm->ddpme[d],
-                         comm->slb_frac[dd->dim[d]]==NULL,ddbox,
-                         comm->ddpme[d].slb_dim_f);
-    }
-}
-
-
-static void dd_cell_sizes_dlb_root_enforce_limits(gmx_domdec_t *dd,
-                                       int d,int dim,gmx_domdec_root_t *root,
-                                       gmx_ddbox_t *ddbox,
-                                       gmx_bool bUniform,gmx_large_int_t step, real cellsize_limit_f, int range[])
-{
-    gmx_domdec_comm_t *comm;
-    int  ncd,i,j,nmin,nmin_old;
-    gmx_bool bLimLo,bLimHi;
-    real *cell_size;
-    real fac,halfway,cellsize_limit_f_i,region_size;
-    gmx_bool bPBC,bLastHi=FALSE;
-    int nrange[]={range[0],range[1]};
-
-    region_size= root->cell_f[range[1]]-root->cell_f[range[0]];  
-
-    comm = dd->comm;
-
-    ncd = dd->nc[dim];
-
-    bPBC = (dim < ddbox->npbcdim);
-
-    cell_size = root->buf_ncd;
-
-    if (debug) 
-    {
-        fprintf(debug,"enforce_limits: %d %d\n",range[0],range[1]);
-    }
-
-    /* First we need to check if the scaling does not make cells
-     * smaller than the smallest allowed size.
-     * We need to do this iteratively, since if a cell is too small,
-     * it needs to be enlarged, which makes all the other cells smaller,
-     * which could in turn make another cell smaller than allowed.
-     */
-    for(i=range[0]; i<range[1]; i++)
-    {
-        root->bCellMin[i] = FALSE;
-    }
-    nmin = 0;
-    do
-    {
-        nmin_old = nmin;
-        /* We need the total for normalization */
-        fac = 0;
-        for(i=range[0]; i<range[1]; i++)
-        {
-            if (root->bCellMin[i] == FALSE)
-            {
-                fac += cell_size[i];
-            }
-        }
-        fac = ( region_size - nmin*cellsize_limit_f)/fac; /* substracting cells already set to cellsize_limit_f */
-        /* Determine the cell boundaries */
-        for(i=range[0]; i<range[1]; i++)
-        {
-            if (root->bCellMin[i] == FALSE)
-            {
-                cell_size[i] *= fac;
-                if (!bPBC && (i == 0 || i == dd->nc[dim] -1))
-                {
-                    cellsize_limit_f_i = 0;
-                }
-                else
-                {
-                    cellsize_limit_f_i = cellsize_limit_f;
-                }
-                if (cell_size[i] < cellsize_limit_f_i)
-                {
-                    root->bCellMin[i] = TRUE;
-                    cell_size[i] = cellsize_limit_f_i;
-                    nmin++;
-                }
-            }
-            root->cell_f[i+1] = root->cell_f[i] + cell_size[i];
-        }
-    }
-    while (nmin > nmin_old);
-    
-    i=range[1]-1;
-    cell_size[i] = root->cell_f[i+1] - root->cell_f[i];
-    /* For this check we should not use DD_CELL_MARGIN,
-     * but a slightly smaller factor,
-     * since rounding could get use below the limit.
-     */
-    if (bPBC && cell_size[i] < cellsize_limit_f*DD_CELL_MARGIN2/DD_CELL_MARGIN)
-    {
-        char buf[22];
-        gmx_fatal(FARGS,"Step %s: the dynamic load balancing could not balance dimension %c: box size %f, triclinic skew factor %f, #cells %d, minimum cell size %f\n",
-                  gmx_step_str(step,buf),
-                  dim2char(dim),ddbox->box_size[dim],ddbox->skew_fac[dim],
-                  ncd,comm->cellsize_min[dim]);
-    }
-    
-    root->bLimited = (nmin > 0) || (range[0]>0) || (range[1]<ncd);
-    
-    if (!bUniform)
-    {
-        /* Check if the boundary did not displace more than halfway
-         * each of the cells it bounds, as this could cause problems,
-         * especially when the differences between cell sizes are large.
-         * If changes are applied, they will not make cells smaller
-         * than the cut-off, as we check all the boundaries which
-         * might be affected by a change and if the old state was ok,
-         * the cells will at most be shrunk back to their old size.
-         */
-        for(i=range[0]+1; i<range[1]; i++)
-        {
-            halfway = 0.5*(root->old_cell_f[i] + root->old_cell_f[i-1]);
-            if (root->cell_f[i] < halfway)
-            {
-                root->cell_f[i] = halfway;
-                /* Check if the change also causes shifts of the next boundaries */
-                for(j=i+1; j<range[1]; j++)
-                {
-                    if (root->cell_f[j] < root->cell_f[j-1] + cellsize_limit_f)
-                        root->cell_f[j] =  root->cell_f[j-1] + cellsize_limit_f;
-                }
-            }
-            halfway = 0.5*(root->old_cell_f[i] + root->old_cell_f[i+1]);
-            if (root->cell_f[i] > halfway)
-            {
-                root->cell_f[i] = halfway;
-                /* Check if the change also causes shifts of the next boundaries */
-                for(j=i-1; j>=range[0]+1; j--)
-                {
-                    if (root->cell_f[j] > root->cell_f[j+1] - cellsize_limit_f)
-                        root->cell_f[j] = root->cell_f[j+1] - cellsize_limit_f;
-                }
-            }
-        }
-    }
-    
-    /* nrange is defined as [lower, upper) range for new call to enforce_limits */
-    /* find highest violation of LimLo (a) and the following violation of LimHi (thus the lowest following) (b)
-     * then call enforce_limits for (oldb,a), (a,b). In the next step: (b,nexta). oldb and nexta can be the boundaries.
-     * for a and b nrange is used */
-    if (d > 0)
-    {
-        /* Take care of the staggering of the cell boundaries */
-        if (bUniform)
-        {
-            for(i=range[0]; i<range[1]; i++)
-            {
-                root->cell_f_max0[i] = root->cell_f[i];
-                root->cell_f_min1[i] = root->cell_f[i+1];
-            }
-        }
-        else
-        {
-            for(i=range[0]+1; i<range[1]; i++)
-            {
-                bLimLo = (root->cell_f[i] < root->bound_min[i]);
-                bLimHi = (root->cell_f[i] > root->bound_max[i]);
-                if (bLimLo && bLimHi)
-                {
-                    /* Both limits violated, try the best we can */
-                    /* For this case we split the original range (range) in two parts and care about the other limitiations in the next iteration. */
-                    root->cell_f[i] = 0.5*(root->bound_min[i] + root->bound_max[i]);
-                    nrange[0]=range[0];
-                    nrange[1]=i;
-                    dd_cell_sizes_dlb_root_enforce_limits(dd, d, dim, root, ddbox, bUniform, step, cellsize_limit_f, nrange);
-
-                    nrange[0]=i;
-                    nrange[1]=range[1];
-                    dd_cell_sizes_dlb_root_enforce_limits(dd, d, dim, root, ddbox, bUniform, step, cellsize_limit_f, nrange);
-
-                    return;
-                }
-                else if (bLimLo)
-                {
-                    /* root->cell_f[i] = root->bound_min[i]; */
-                    nrange[1]=i;  /* only store violation location. There could be a LimLo violation following with an higher index */
-                    bLastHi=FALSE;
-                }
-                else if (bLimHi && !bLastHi)
-                {
-                    bLastHi=TRUE;
-                    if (nrange[1] < range[1])   /* found a LimLo before */
-                    {
-                        root->cell_f[nrange[1]] = root->bound_min[nrange[1]];
-                        dd_cell_sizes_dlb_root_enforce_limits(dd, d, dim, root, ddbox, bUniform, step, cellsize_limit_f, nrange);
-                        nrange[0]=nrange[1];
-                    }
-                    root->cell_f[i] = root->bound_max[i];
-                    nrange[1]=i; 
-                    dd_cell_sizes_dlb_root_enforce_limits(dd, d, dim, root, ddbox, bUniform, step, cellsize_limit_f, nrange);
-                    nrange[0]=i;
-                    nrange[1]=range[1];
-                }
-            }
-            if (nrange[1] < range[1])   /* found last a LimLo */
-            {
-                root->cell_f[nrange[1]] = root->bound_min[nrange[1]];
-                dd_cell_sizes_dlb_root_enforce_limits(dd, d, dim, root, ddbox, bUniform, step, cellsize_limit_f, nrange);
-                nrange[0]=nrange[1];
-                nrange[1]=range[1];
-                dd_cell_sizes_dlb_root_enforce_limits(dd, d, dim, root, ddbox, bUniform, step, cellsize_limit_f, nrange);
-            } 
-            else if (nrange[0] > range[0]) /* found at least one LimHi */
-            {
-                dd_cell_sizes_dlb_root_enforce_limits(dd, d, dim, root, ddbox, bUniform, step, cellsize_limit_f, nrange);
-            }
-        }
-    }
-}
-
-
-static void set_dd_cell_sizes_dlb_root(gmx_domdec_t *dd,
-                                       int d,int dim,gmx_domdec_root_t *root,
-                                       gmx_ddbox_t *ddbox,gmx_bool bDynamicBox,
-                                       gmx_bool bUniform,gmx_large_int_t step)
-{
-    gmx_domdec_comm_t *comm;
-    int  ncd,d1,i,j,pos;
-    real *cell_size;
-    real load_aver,load_i,imbalance,change,change_max,sc;
-    real cellsize_limit_f,dist_min_f,dist_min_f_hard,space;
-    real change_limit = 0.1;
-    real relax = 0.5;
-    gmx_bool bPBC;
-    int range[] = { 0, 0 };
-
-    comm = dd->comm;
-
-    ncd = dd->nc[dim];
-
-    bPBC = (dim < ddbox->npbcdim);
-
-    cell_size = root->buf_ncd;
-
-    /* Store the original boundaries */
-    for(i=0; i<ncd+1; i++)
-    {
-        root->old_cell_f[i] = root->cell_f[i];
-    }
-    if (bUniform) {
-        for(i=0; i<ncd; i++)
-        {
-            cell_size[i] = 1.0/ncd;
-        }
-    }
-    else if (dd_load_count(comm))
-    {
-        load_aver = comm->load[d].sum_m/ncd;
-        change_max = 0;
-        for(i=0; i<ncd; i++)
-        {
-            /* Determine the relative imbalance of cell i */
-            load_i = comm->load[d].load[i*comm->load[d].nload+2];
-            imbalance = (load_i - load_aver)/(load_aver>0 ? load_aver : 1);
-            /* Determine the change of the cell size using underrelaxation */
-            change = -relax*imbalance;
-            change_max = max(change_max,max(change,-change));
-        }
-        /* Limit the amount of scaling.
-         * We need to use the same rescaling for all cells in one row,
-         * otherwise the load balancing might not converge.
-         */
-        sc = relax;
-        if (change_max > change_limit)
-        {
-            sc *= change_limit/change_max;
-        }
-        for(i=0; i<ncd; i++)
-        {
-            /* Determine the relative imbalance of cell i */
-            load_i = comm->load[d].load[i*comm->load[d].nload+2];
-            imbalance = (load_i - load_aver)/(load_aver>0 ? load_aver : 1);
-            /* Determine the change of the cell size using underrelaxation */
-            change = -sc*imbalance;
-            cell_size[i] = (root->cell_f[i+1]-root->cell_f[i])*(1 + change);
-        }
-    }
-    
-    cellsize_limit_f  = comm->cellsize_min[dim]/ddbox->box_size[dim];
-    cellsize_limit_f *= DD_CELL_MARGIN;
-    dist_min_f_hard        = grid_jump_limit(comm,d)/ddbox->box_size[dim];
-    dist_min_f       = dist_min_f_hard * DD_CELL_MARGIN;
-    if (ddbox->tric_dir[dim])
-    {
-        cellsize_limit_f /= ddbox->skew_fac[dim];
-        dist_min_f       /= ddbox->skew_fac[dim];
-    }
-    if (bDynamicBox && d > 0)
-    {
-        dist_min_f *= DD_PRES_SCALE_MARGIN;
-    }
-    if (d > 0 && !bUniform)
-    {
-        /* Make sure that the grid is not shifted too much */
-        for(i=1; i<ncd; i++) {
-            if (root->cell_f_min1[i] - root->cell_f_max0[i-1] < 2 * dist_min_f_hard) 
-            {
-                gmx_incons("Inconsistent DD boundary staggering limits!");
-            }
-            root->bound_min[i] = root->cell_f_max0[i-1] + dist_min_f;
-            space = root->cell_f[i] - (root->cell_f_max0[i-1] + dist_min_f);
-            if (space > 0) {
-                root->bound_min[i] += 0.5*space;
-            }
-            root->bound_max[i] = root->cell_f_min1[i] - dist_min_f;
-            space = root->cell_f[i] - (root->cell_f_min1[i] - dist_min_f);
-            if (space < 0) {
-                root->bound_max[i] += 0.5*space;
-            }
-            if (debug)
-            {
-                fprintf(debug,
-                        "dim %d boundary %d %.3f < %.3f < %.3f < %.3f < %.3f\n",
-                        d,i,
-                        root->cell_f_max0[i-1] + dist_min_f,
-                        root->bound_min[i],root->cell_f[i],root->bound_max[i],
-                        root->cell_f_min1[i] - dist_min_f);
-            }
-        }
-    }
-    range[1]=ncd;
-    root->cell_f[0] = 0;
-    root->cell_f[ncd] = 1;
-    dd_cell_sizes_dlb_root_enforce_limits(dd, d, dim, root, ddbox, bUniform, step, cellsize_limit_f, range);
-
-
-    /* After the checks above, the cells should obey the cut-off
-     * restrictions, but it does not hurt to check.
-     */
-    for(i=0; i<ncd; i++)
-    {
-        if (debug)
-        {
-            fprintf(debug,"Relative bounds dim %d  cell %d: %f %f\n",
-                    dim,i,root->cell_f[i],root->cell_f[i+1]);
-        }
-
-        if ((bPBC || (i != 0 && i != dd->nc[dim]-1)) &&
-            root->cell_f[i+1] - root->cell_f[i] <
-            cellsize_limit_f/DD_CELL_MARGIN)
-        {
-            char buf[22];
-            fprintf(stderr,
-                    "\nWARNING step %s: direction %c, cell %d too small: %f\n",
-                    gmx_step_str(step,buf),dim2char(dim),i,
-                    (root->cell_f[i+1] - root->cell_f[i])
-                    *ddbox->box_size[dim]*ddbox->skew_fac[dim]);
-        }
-    }
-    
-    pos = ncd + 1;
-    /* Store the cell boundaries of the lower dimensions at the end */
-    for(d1=0; d1<d; d1++)
-    {
-        root->cell_f[pos++] = comm->cell_f0[d1];
-        root->cell_f[pos++] = comm->cell_f1[d1];
-    }
-    
-    if (d < comm->npmedecompdim)
-    {
-        /* The master determines the maximum shift for
-         * the coordinate communication between separate PME nodes.
-         */
-        set_pme_maxshift(dd,&comm->ddpme[d],bUniform,ddbox,root->cell_f);
-    }
-    root->cell_f[pos++] = comm->ddpme[0].maxshift;
-    if (d >= 1)
-    {
-        root->cell_f[pos++] = comm->ddpme[1].maxshift;
-    }
-}    
-
-static void relative_to_absolute_cell_bounds(gmx_domdec_t *dd,
-                                             gmx_ddbox_t *ddbox,int dimind)
-{
-    gmx_domdec_comm_t *comm;
-    int dim;
-
-    comm = dd->comm;
-
-    /* Set the cell dimensions */
-    dim = dd->dim[dimind];
-    comm->cell_x0[dim] = comm->cell_f0[dimind]*ddbox->box_size[dim];
-    comm->cell_x1[dim] = comm->cell_f1[dimind]*ddbox->box_size[dim];
-    if (dim >= ddbox->nboundeddim)
-    {
-        comm->cell_x0[dim] += ddbox->box0[dim];
-        comm->cell_x1[dim] += ddbox->box0[dim];
-    }
-}
-
-static void distribute_dd_cell_sizes_dlb(gmx_domdec_t *dd,
-                                         int d,int dim,real *cell_f_row,
-                                         gmx_ddbox_t *ddbox)
-{
-    gmx_domdec_comm_t *comm;
-    int d1,dim1,pos;
-
-    comm = dd->comm;
-
-#ifdef GMX_MPI
-    /* Each node would only need to know two fractions,
-     * but it is probably cheaper to broadcast the whole array.
-     */
-    MPI_Bcast(cell_f_row,DD_CELL_F_SIZE(dd,d)*sizeof(real),MPI_BYTE,
-              0,comm->mpi_comm_load[d]);
-#endif
-    /* Copy the fractions for this dimension from the buffer */
-    comm->cell_f0[d] = cell_f_row[dd->ci[dim]  ];
-    comm->cell_f1[d] = cell_f_row[dd->ci[dim]+1];
-    /* The whole array was communicated, so set the buffer position */
-    pos = dd->nc[dim] + 1;
-    for(d1=0; d1<=d; d1++)
-    {
-        if (d1 < d)
-        {
-            /* Copy the cell fractions of the lower dimensions */
-            comm->cell_f0[d1] = cell_f_row[pos++];
-            comm->cell_f1[d1] = cell_f_row[pos++];
-        }
-        relative_to_absolute_cell_bounds(dd,ddbox,d1);
-    }
-    /* Convert the communicated shift from float to int */
-    comm->ddpme[0].maxshift = (int)(cell_f_row[pos++] + 0.5);
-    if (d >= 1)
-    {
-        comm->ddpme[1].maxshift = (int)(cell_f_row[pos++] + 0.5);
-    }
-}
-
-static void set_dd_cell_sizes_dlb_change(gmx_domdec_t *dd,
-                                         gmx_ddbox_t *ddbox,gmx_bool bDynamicBox,
-                                         gmx_bool bUniform,gmx_large_int_t step)
-{
-    gmx_domdec_comm_t *comm;
-    int d,dim,d1;
-    gmx_bool bRowMember,bRowRoot;
-    real *cell_f_row;
-    
-    comm = dd->comm;
-
-    for(d=0; d<dd->ndim; d++)
-    {
-        dim = dd->dim[d];
-        bRowMember = TRUE;
-        bRowRoot = TRUE;
-        for(d1=d; d1<dd->ndim; d1++)
-        {
-            if (dd->ci[dd->dim[d1]] > 0)
-            {
-                if (d1 > d)
-                {
-                    bRowMember = FALSE;
-                }
-                bRowRoot = FALSE;
-            }
-        }
-        if (bRowMember)
-        {
-            if (bRowRoot)
-            {
-                set_dd_cell_sizes_dlb_root(dd,d,dim,comm->root[d],
-                                           ddbox,bDynamicBox,bUniform,step);
-                cell_f_row = comm->root[d]->cell_f;
-            }
-            else
-            {
-                cell_f_row = comm->cell_f_row;
-            }
-            distribute_dd_cell_sizes_dlb(dd,d,dim,cell_f_row,ddbox);
-        }
-    }
-}    
-
-static void set_dd_cell_sizes_dlb_nochange(gmx_domdec_t *dd,gmx_ddbox_t *ddbox)
-{
-    int d;
-
-    /* This function assumes the box is static and should therefore
-     * not be called when the box has changed since the last
-     * call to dd_partition_system.
-     */
-    for(d=0; d<dd->ndim; d++)
-    {
-        relative_to_absolute_cell_bounds(dd,ddbox,d); 
-    }
-}
-
-
-
-static void set_dd_cell_sizes_dlb(gmx_domdec_t *dd,
-                                  gmx_ddbox_t *ddbox,gmx_bool bDynamicBox,
-                                  gmx_bool bUniform,gmx_bool bDoDLB,gmx_large_int_t step,
-                                  gmx_wallcycle_t wcycle)
-{
-    gmx_domdec_comm_t *comm;
-    int dim;
-
-    comm = dd->comm;
-    
-    if (bDoDLB)
-    {
-        wallcycle_start(wcycle,ewcDDCOMMBOUND);
-        set_dd_cell_sizes_dlb_change(dd,ddbox,bDynamicBox,bUniform,step);
-        wallcycle_stop(wcycle,ewcDDCOMMBOUND);
-    }
-    else if (bDynamicBox)
-    {
-        set_dd_cell_sizes_dlb_nochange(dd,ddbox);
-    }
-    
-    /* Set the dimensions for which no DD is used */
-    for(dim=0; dim<DIM; dim++) {
-        if (dd->nc[dim] == 1) {
-            comm->cell_x0[dim] = 0;
-            comm->cell_x1[dim] = ddbox->box_size[dim];
-            if (dim >= ddbox->nboundeddim)
-            {
-                comm->cell_x0[dim] += ddbox->box0[dim];
-                comm->cell_x1[dim] += ddbox->box0[dim];
-            }
-        }
-    }
-}
-
-static void realloc_comm_ind(gmx_domdec_t *dd,ivec npulse)
-{
-    int d,np,i;
-    gmx_domdec_comm_dim_t *cd;
-    
-    for(d=0; d<dd->ndim; d++)
-    {
-        cd = &dd->comm->cd[d];
-        np = npulse[dd->dim[d]];
-        if (np > cd->np_nalloc)
-        {
-            if (debug)
-            {
-                fprintf(debug,"(Re)allocing cd for %c to %d pulses\n",
-                        dim2char(dd->dim[d]),np);
-            }
-            if (DDMASTER(dd) && cd->np_nalloc > 0)
-            {
-                fprintf(stderr,"\nIncreasing the number of cell to communicate in dimension %c to %d for the first time\n",dim2char(dd->dim[d]),np);
-            }
-            srenew(cd->ind,np);
-            for(i=cd->np_nalloc; i<np; i++)
-            {
-                cd->ind[i].index  = NULL;
-                cd->ind[i].nalloc = 0;
-            }
-            cd->np_nalloc = np;
-        }
-        cd->np = np;
-    }
-}
-
-
-static void set_dd_cell_sizes(gmx_domdec_t *dd,
-                              gmx_ddbox_t *ddbox,gmx_bool bDynamicBox,
-                              gmx_bool bUniform,gmx_bool bDoDLB,gmx_large_int_t step,
-                              gmx_wallcycle_t wcycle)
-{
-    gmx_domdec_comm_t *comm;
-    int  d;
-    ivec npulse;
-    
-    comm = dd->comm;
-
-    /* Copy the old cell boundaries for the cg displacement check */
-    copy_rvec(comm->cell_x0,comm->old_cell_x0);
-    copy_rvec(comm->cell_x1,comm->old_cell_x1);
-    
-    if (comm->bDynLoadBal)
-    {
-        if (DDMASTER(dd))
-        {
-            check_box_size(dd,ddbox);
-        }
-        set_dd_cell_sizes_dlb(dd,ddbox,bDynamicBox,bUniform,bDoDLB,step,wcycle);
-    }
-    else
-    {
-        set_dd_cell_sizes_slb(dd,ddbox,FALSE,npulse);
-        realloc_comm_ind(dd,npulse);
-    }
-    
-    if (debug)
-    {
-        for(d=0; d<DIM; d++)
-        {
-            fprintf(debug,"cell_x[%d] %f - %f skew_fac %f\n",
-                    d,comm->cell_x0[d],comm->cell_x1[d],ddbox->skew_fac[d]);
-        }
-    }
-}
-
-static void comm_dd_ns_cell_sizes(gmx_domdec_t *dd,
-                                  gmx_ddbox_t *ddbox,
-                                  rvec cell_ns_x0,rvec cell_ns_x1,
-                                  gmx_large_int_t step)
-{
-    gmx_domdec_comm_t *comm;
-    int dim_ind,dim;
-    
-    comm = dd->comm;
-
-    for(dim_ind=0; dim_ind<dd->ndim; dim_ind++)
-    {
-        dim = dd->dim[dim_ind];
-        
-        /* Without PBC we don't have restrictions on the outer cells */
-        if (!(dim >= ddbox->npbcdim && 
-              (dd->ci[dim] == 0 || dd->ci[dim] == dd->nc[dim] - 1)) &&
-            comm->bDynLoadBal &&
-            (comm->cell_x1[dim] - comm->cell_x0[dim])*ddbox->skew_fac[dim] <
-            comm->cellsize_min[dim])
-        {
-            char buf[22];
-            gmx_fatal(FARGS,"Step %s: The %c-size (%f) times the triclinic skew factor (%f) is smaller than the smallest allowed cell size (%f) for domain decomposition grid cell %d %d %d",
-                      gmx_step_str(step,buf),dim2char(dim),
-                      comm->cell_x1[dim] - comm->cell_x0[dim],
-                      ddbox->skew_fac[dim],
-                      dd->comm->cellsize_min[dim],
-                      dd->ci[XX],dd->ci[YY],dd->ci[ZZ]);
-        }
-    }
-    
-    if ((dd->bGridJump && dd->ndim > 1) || ddbox->nboundeddim < DIM)
-    {
-        /* Communicate the boundaries and update cell_ns_x0/1 */
-        dd_move_cellx(dd,ddbox,cell_ns_x0,cell_ns_x1);
-        if (dd->bGridJump && dd->ndim > 1)
-        {
-            check_grid_jump(step,dd,ddbox);
-        }
-    }
-}
-
-static void make_tric_corr_matrix(int npbcdim,matrix box,matrix tcm)
-{
-    if (YY < npbcdim)
-    {
-        tcm[YY][XX] = -box[YY][XX]/box[YY][YY];
-    }
-    else
-    {
-        tcm[YY][XX] = 0;
-    }
-    if (ZZ < npbcdim)
-    {
-        tcm[ZZ][XX] = -(box[ZZ][YY]*tcm[YY][XX] + box[ZZ][XX])/box[ZZ][ZZ];
-        tcm[ZZ][YY] = -box[ZZ][YY]/box[ZZ][ZZ];
-    }
-    else
-    {
-        tcm[ZZ][XX] = 0;
-        tcm[ZZ][YY] = 0;
-    }
-}
-
-static void check_screw_box(matrix box)
-{
-    /* Mathematical limitation */
-    if (box[YY][XX] != 0 || box[ZZ][XX] != 0)
-    {
-        gmx_fatal(FARGS,"With screw pbc the unit cell can not have non-zero off-diagonal x-components");
-    }
-    
-    /* Limitation due to the asymmetry of the eighth shell method */
-    if (box[ZZ][YY] != 0)
-    {
-        gmx_fatal(FARGS,"pbc=screw with non-zero box_zy is not supported");
-    }
-}
-
-static void distribute_cg(FILE *fplog,gmx_large_int_t step,
-                          matrix box,ivec tric_dir,t_block *cgs,rvec pos[],
-                          gmx_domdec_t *dd)
-{
-    gmx_domdec_master_t *ma;
-    int **tmp_ind=NULL,*tmp_nalloc=NULL;
-    int  i,icg,j,k,k0,k1,d,npbcdim;
-    matrix tcm;
-    rvec box_size,cg_cm;
-    ivec ind;
-    real nrcg,inv_ncg,pos_d;
-    atom_id *cgindex;
-    gmx_bool bUnbounded,bScrew;
-
-    ma = dd->ma;
-    
-    if (tmp_ind == NULL)
-    {
-        snew(tmp_nalloc,dd->nnodes);
-        snew(tmp_ind,dd->nnodes);
-        for(i=0; i<dd->nnodes; i++)
-        {
-            tmp_nalloc[i] = over_alloc_large(cgs->nr/dd->nnodes+1);
-            snew(tmp_ind[i],tmp_nalloc[i]);
-        }
-    }
-    
-    /* Clear the count */
-    for(i=0; i<dd->nnodes; i++)
-    {
-        ma->ncg[i] = 0;
-        ma->nat[i] = 0;
-    }
-    
-    make_tric_corr_matrix(dd->npbcdim,box,tcm);
-    
-    cgindex = cgs->index;
-    
-    /* Compute the center of geometry for all charge groups */
-    for(icg=0; icg<cgs->nr; icg++)
-    {
-        k0      = cgindex[icg];
-        k1      = cgindex[icg+1];
-        nrcg    = k1 - k0;
-        if (nrcg == 1)
-        {
-            copy_rvec(pos[k0],cg_cm);
-        }
-        else
-        {
-            inv_ncg = 1.0/nrcg;
-            
-            clear_rvec(cg_cm);
-            for(k=k0; (k<k1); k++)
-            {
-                rvec_inc(cg_cm,pos[k]);
-            }
-            for(d=0; (d<DIM); d++)
-            {
-                cg_cm[d] *= inv_ncg;
-            }
-        }
-        /* Put the charge group in the box and determine the cell index */
-        for(d=DIM-1; d>=0; d--) {
-            pos_d = cg_cm[d];
-            if (d < dd->npbcdim)
-            {
-                bScrew = (dd->bScrewPBC && d == XX);
-                if (tric_dir[d] && dd->nc[d] > 1)
-                {
-                    /* Use triclinic coordintates for this dimension */
-                    for(j=d+1; j<DIM; j++)
-                    {
-                        pos_d += cg_cm[j]*tcm[j][d];
-                    }
-                }
-                while(pos_d >= box[d][d])
-                {
-                    pos_d -= box[d][d];
-                    rvec_dec(cg_cm,box[d]);
-                    if (bScrew)
-                    {
-                        cg_cm[YY] = box[YY][YY] - cg_cm[YY];
-                        cg_cm[ZZ] = box[ZZ][ZZ] - cg_cm[ZZ];
-                    }
-                    for(k=k0; (k<k1); k++)
-                    {
-                        rvec_dec(pos[k],box[d]);
-                        if (bScrew)
-                        {
-                            pos[k][YY] = box[YY][YY] - pos[k][YY];
-                            pos[k][ZZ] = box[ZZ][ZZ] - pos[k][ZZ];
-                        }
-                    }
-                }
-                while(pos_d < 0)
-                {
-                    pos_d += box[d][d];
-                    rvec_inc(cg_cm,box[d]);
-                    if (bScrew)
-                    {
-                        cg_cm[YY] = box[YY][YY] - cg_cm[YY];
-                        cg_cm[ZZ] = box[ZZ][ZZ] - cg_cm[ZZ];
-                    }
-                    for(k=k0; (k<k1); k++)
-                    {
-                        rvec_inc(pos[k],box[d]);
-                        if (bScrew) {
-                            pos[k][YY] = box[YY][YY] - pos[k][YY];
-                            pos[k][ZZ] = box[ZZ][ZZ] - pos[k][ZZ];
-                        }
-                    }
-                }
-            }
-            /* This could be done more efficiently */
-            ind[d] = 0;
-            while(ind[d]+1 < dd->nc[d] && pos_d >= ma->cell_x[d][ind[d]+1])
-            {
-                ind[d]++;
-            }
-        }
-        i = dd_index(dd->nc,ind);
-        if (ma->ncg[i] == tmp_nalloc[i])
-        {
-            tmp_nalloc[i] = over_alloc_large(ma->ncg[i]+1);
-            srenew(tmp_ind[i],tmp_nalloc[i]);
-        }
-        tmp_ind[i][ma->ncg[i]] = icg;
-        ma->ncg[i]++;
-        ma->nat[i] += cgindex[icg+1] - cgindex[icg];
-    }
-    
-    k1 = 0;
-    for(i=0; i<dd->nnodes; i++)
-    {
-        ma->index[i] = k1;
-        for(k=0; k<ma->ncg[i]; k++)
-        {
-            ma->cg[k1++] = tmp_ind[i][k];
-        }
-    }
-    ma->index[dd->nnodes] = k1;
-    
-    for(i=0; i<dd->nnodes; i++)
-    {
-        sfree(tmp_ind[i]);
-    }
-    sfree(tmp_ind);
-    sfree(tmp_nalloc);
-    
-    if (fplog)
-    {
-        char buf[22];
-        fprintf(fplog,"Charge group distribution at step %s:",
-                gmx_step_str(step,buf));
-        for(i=0; i<dd->nnodes; i++)
-        {
-            fprintf(fplog," %d",ma->ncg[i]);
-        }
-        fprintf(fplog,"\n");
-    }
-}
-
-static void get_cg_distribution(FILE *fplog,gmx_large_int_t step,gmx_domdec_t *dd,
-                                t_block *cgs,matrix box,gmx_ddbox_t *ddbox,
-                                rvec pos[])
-{
-    gmx_domdec_master_t *ma=NULL;
-    ivec npulse;
-    int  i,cg_gl;
-    int  *ibuf,buf2[2] = { 0, 0 };
-    
-    if (DDMASTER(dd))
-    {
-        ma = dd->ma;
-        
-        if (dd->bScrewPBC)
-        {
-            check_screw_box(box);
-        }
-    
-        set_dd_cell_sizes_slb(dd,ddbox,TRUE,npulse);
-    
-        distribute_cg(fplog,step,box,ddbox->tric_dir,cgs,pos,dd);
-        for(i=0; i<dd->nnodes; i++)
-        {
-            ma->ibuf[2*i]   = ma->ncg[i];
-            ma->ibuf[2*i+1] = ma->nat[i];
-        }
-        ibuf = ma->ibuf;
-    }
-    else
-    {
-        ibuf = NULL;
-    }
-    dd_scatter(dd,2*sizeof(int),ibuf,buf2);
-    
-    dd->ncg_home = buf2[0];
-    dd->nat_home = buf2[1];
-    dd->ncg_tot  = dd->ncg_home;
-    dd->nat_tot  = dd->nat_home;
-    if (dd->ncg_home > dd->cg_nalloc || dd->cg_nalloc == 0)
-    {
-        dd->cg_nalloc = over_alloc_dd(dd->ncg_home);
-        srenew(dd->index_gl,dd->cg_nalloc);
-        srenew(dd->cgindex,dd->cg_nalloc+1);
-    }
-    if (DDMASTER(dd))
-    {
-        for(i=0; i<dd->nnodes; i++)
-        {
-            ma->ibuf[i] = ma->ncg[i]*sizeof(int);
-            ma->ibuf[dd->nnodes+i] = ma->index[i]*sizeof(int);
-        }
-    }
-    
-    dd_scatterv(dd,
-                DDMASTER(dd) ? ma->ibuf : NULL,
-                DDMASTER(dd) ? ma->ibuf+dd->nnodes : NULL,
-                DDMASTER(dd) ? ma->cg : NULL,
-                dd->ncg_home*sizeof(int),dd->index_gl);
-    
-    /* Determine the home charge group sizes */
-    dd->cgindex[0] = 0;
-    for(i=0; i<dd->ncg_home; i++)
-    {
-        cg_gl = dd->index_gl[i];
-        dd->cgindex[i+1] =
-            dd->cgindex[i] + cgs->index[cg_gl+1] - cgs->index[cg_gl];
-    }
-    
-    if (debug)
-    {
-        fprintf(debug,"Home charge groups:\n");
-        for(i=0; i<dd->ncg_home; i++)
-        {
-            fprintf(debug," %d",dd->index_gl[i]);
-            if (i % 10 == 9) 
-                fprintf(debug,"\n");
-        }
-        fprintf(debug,"\n");
-    }
-}
-
-static int compact_and_copy_vec_at(int ncg,int *move,
-                                   int *cgindex,
-                                   int nvec,int vec,
-                                   rvec *src,gmx_domdec_comm_t *comm,
-                                   gmx_bool bCompact)
-{
-    int m,icg,i,i0,i1,nrcg;
-    int home_pos;
-    int pos_vec[DIM*2];
-    
-    home_pos = 0;
-
-    for(m=0; m<DIM*2; m++)
-    {
-        pos_vec[m] = 0;
-    }
-    
-    i0 = 0;
-    for(icg=0; icg<ncg; icg++)
-    {
-        i1 = cgindex[icg+1];
-        m = move[icg];
-        if (m == -1)
-        {
-            if (bCompact)
-            {
-                /* Compact the home array in place */
-                for(i=i0; i<i1; i++)
-                {
-                    copy_rvec(src[i],src[home_pos++]);
-                }
-            }
-        }
-        else
-        {
-            /* Copy to the communication buffer */
-            nrcg = i1 - i0;
-            pos_vec[m] += 1 + vec*nrcg;
-            for(i=i0; i<i1; i++)
-            {
-                copy_rvec(src[i],comm->cgcm_state[m][pos_vec[m]++]);
-            }
-            pos_vec[m] += (nvec - vec - 1)*nrcg;
-        }
-        if (!bCompact)
-        {
-            home_pos += i1 - i0;
-        }
-        i0 = i1;
-    }
-    
-    return home_pos;
-}
-
-static int compact_and_copy_vec_cg(int ncg,int *move,
-                                   int *cgindex,
-                                   int nvec,rvec *src,gmx_domdec_comm_t *comm,
-                                   gmx_bool bCompact)
-{
-    int m,icg,i0,i1,nrcg;
-    int home_pos;
-    int pos_vec[DIM*2];
-    
-    home_pos = 0;
-    
-    for(m=0; m<DIM*2; m++)
-    {
-        pos_vec[m] = 0;
-    }
-    
-    i0 = 0;
-    for(icg=0; icg<ncg; icg++)
-    {
-        i1 = cgindex[icg+1];
-        m = move[icg];
-        if (m == -1)
-        {
-            if (bCompact)
-            {
-                /* Compact the home array in place */
-                copy_rvec(src[icg],src[home_pos++]);
-            }
-        }
-        else
-        {
-            nrcg = i1 - i0;
-            /* Copy to the communication buffer */
-            copy_rvec(src[icg],comm->cgcm_state[m][pos_vec[m]]);
-            pos_vec[m] += 1 + nrcg*nvec;
-        }
-        i0 = i1;
-    }
-    if (!bCompact)
-    {
-        home_pos = ncg;
-    }
-    
-    return home_pos;
-}
-
-static int compact_ind(int ncg,int *move,
-                       int *index_gl,int *cgindex,
-                       int *gatindex,
-                       gmx_ga2la_t ga2la,char *bLocalCG,
-                       int *cginfo)
-{
-    int cg,nat,a0,a1,a,a_gl;
-    int home_pos;
-
-    home_pos = 0;
-    nat = 0;
-    for(cg=0; cg<ncg; cg++)
-    {
-        a0 = cgindex[cg];
-        a1 = cgindex[cg+1];
-        if (move[cg] == -1)
-        {
-            /* Compact the home arrays in place.
-             * Anything that can be done here avoids access to global arrays.
-             */
-            cgindex[home_pos] = nat;
-            for(a=a0; a<a1; a++)
-            {
-                a_gl = gatindex[a];
-                gatindex[nat] = a_gl;
-                /* The cell number stays 0, so we don't need to set it */
-                ga2la_change_la(ga2la,a_gl,nat);
-                nat++;
-            }
-            index_gl[home_pos] = index_gl[cg];
-            cginfo[home_pos]   = cginfo[cg];
-            /* The charge group remains local, so bLocalCG does not change */
-            home_pos++;
-        }
-        else
-        {
-            /* Clear the global indices */
-            for(a=a0; a<a1; a++)
-            {
-                ga2la_del(ga2la,gatindex[a]);
-            }
-            if (bLocalCG)
-            {
-                bLocalCG[index_gl[cg]] = FALSE;
-            }
-        }
-    }
-    cgindex[home_pos] = nat;
-    
-    return home_pos;
-}
-
-static void clear_and_mark_ind(int ncg,int *move,
-                               int *index_gl,int *cgindex,int *gatindex,
-                               gmx_ga2la_t ga2la,char *bLocalCG,
-                               int *cell_index)
-{
-    int cg,a0,a1,a;
-    
-    for(cg=0; cg<ncg; cg++)
-    {
-        if (move[cg] >= 0)
-        {
-            a0 = cgindex[cg];
-            a1 = cgindex[cg+1];
-            /* Clear the global indices */
-            for(a=a0; a<a1; a++)
-            {
-                ga2la_del(ga2la,gatindex[a]);
-            }
-            if (bLocalCG)
-            {
-                bLocalCG[index_gl[cg]] = FALSE;
-            }
-            /* Signal that this cg has moved using the ns cell index.
-             * Here we set it to -1.
-             * fill_grid will change it from -1 to 4*grid->ncells.
-             */
-            cell_index[cg] = -1;
-        }
-    }
-}
-
-static void print_cg_move(FILE *fplog,
-                          gmx_domdec_t *dd,
-                          gmx_large_int_t step,int cg,int dim,int dir,
-                          gmx_bool bHaveLimitdAndCMOld,real limitd,
-                          rvec cm_old,rvec cm_new,real pos_d)
-{
-    gmx_domdec_comm_t *comm;
-    char buf[22];
-
-    comm = dd->comm;
-
-    fprintf(fplog,"\nStep %s:\n",gmx_step_str(step,buf));
-    if (bHaveLimitdAndCMOld)
-    {
-        fprintf(fplog,"The charge group starting at atom %d moved than the distance allowed by the domain decomposition (%f) in direction %c\n",
-                ddglatnr(dd,dd->cgindex[cg]),limitd,dim2char(dim));
-    }
-    else
-    {
-        fprintf(fplog,"The charge group starting at atom %d moved than the distance allowed by the domain decomposition in direction %c\n",
-                ddglatnr(dd,dd->cgindex[cg]),dim2char(dim));
-    }
-    fprintf(fplog,"distance out of cell %f\n",
-            dir==1 ? pos_d - comm->cell_x1[dim] : pos_d - comm->cell_x0[dim]);
-    if (bHaveLimitdAndCMOld)
-    {
-        fprintf(fplog,"Old coordinates: %8.3f %8.3f %8.3f\n",
-                cm_old[XX],cm_old[YY],cm_old[ZZ]);
-    }
-    fprintf(fplog,"New coordinates: %8.3f %8.3f %8.3f\n",
-            cm_new[XX],cm_new[YY],cm_new[ZZ]);
-    fprintf(fplog,"Old cell boundaries in direction %c: %8.3f %8.3f\n",
-            dim2char(dim),
-            comm->old_cell_x0[dim],comm->old_cell_x1[dim]);
-    fprintf(fplog,"New cell boundaries in direction %c: %8.3f %8.3f\n",
-            dim2char(dim),
-            comm->cell_x0[dim],comm->cell_x1[dim]);
-}
-
-static void cg_move_error(FILE *fplog,
-                          gmx_domdec_t *dd,
-                          gmx_large_int_t step,int cg,int dim,int dir,
-                          gmx_bool bHaveLimitdAndCMOld,real limitd,
-                          rvec cm_old,rvec cm_new,real pos_d)
-{
-    if (fplog)
-    {
-        print_cg_move(fplog, dd,step,cg,dim,dir,
-                      bHaveLimitdAndCMOld,limitd,cm_old,cm_new,pos_d);
-    }
-    print_cg_move(stderr,dd,step,cg,dim,dir,
-                  bHaveLimitdAndCMOld,limitd,cm_old,cm_new,pos_d);
-    gmx_fatal(FARGS,
-              "A charge group moved too far between two domain decomposition steps\n"
-              "This usually means that your system is not well equilibrated");
-}
-
-static void rotate_state_atom(t_state *state,int a)
-{
-    int est;
-
-    for(est=0; est<estNR; est++)
-    {
-        if (EST_DISTR(est) && state->flags & (1<<est)) {
-            switch (est) {
-            case estX:
-                /* Rotate the complete state; for a rectangular box only */
-                state->x[a][YY] = state->box[YY][YY] - state->x[a][YY];
-                state->x[a][ZZ] = state->box[ZZ][ZZ] - state->x[a][ZZ];
-                break;
-            case estV:
-                state->v[a][YY] = -state->v[a][YY];
-                state->v[a][ZZ] = -state->v[a][ZZ];
-                break;
-            case estSDX:
-                state->sd_X[a][YY] = -state->sd_X[a][YY];
-                state->sd_X[a][ZZ] = -state->sd_X[a][ZZ];
-                break;
-            case estCGP:
-                state->cg_p[a][YY] = -state->cg_p[a][YY];
-                state->cg_p[a][ZZ] = -state->cg_p[a][ZZ];
-                break;
-            case estDISRE_INITF:
-            case estDISRE_RM3TAV:
-            case estORIRE_INITF:
-            case estORIRE_DTAV:
-                /* These are distances, so not affected by rotation */
-                break;
-            default:
-                gmx_incons("Unknown state entry encountered in rotate_state_atom");            
-            }
-        }
-    }
-}
-
-static int dd_redistribute_cg(FILE *fplog,gmx_large_int_t step,
-                              gmx_domdec_t *dd,ivec tric_dir,
-                              t_state *state,rvec **f,
-                              t_forcerec *fr,t_mdatoms *md,
-                              gmx_bool bCompact,
-                              t_nrnb *nrnb)
-{
-    int  *move;
-    int  npbcdim;
-    int  ncg[DIM*2],nat[DIM*2];
-    int  c,i,cg,k,k0,k1,d,dim,dim2,dir,d2,d3,d4,cell_d;
-    int  mc,cdd,nrcg,ncg_recv,nat_recv,nvs,nvr,nvec,vec;
-    int  sbuf[2],rbuf[2];
-    int  home_pos_cg,home_pos_at,ncg_stay_home,buf_pos;
-    int  flag;
-    gmx_bool bV=FALSE,bSDX=FALSE,bCGP=FALSE;
-    gmx_bool bScrew;
-    ivec dev;
-    real inv_ncg,pos_d;
-    matrix tcm;
-    rvec *cg_cm,cell_x0,cell_x1,limitd,limit0,limit1,cm_new;
-    atom_id *cgindex;
-    cginfo_mb_t *cginfo_mb;
-    gmx_domdec_comm_t *comm;
-    
-    if (dd->bScrewPBC)
-    {
-        check_screw_box(state->box);
-    }
-    
-    comm  = dd->comm;
-    cg_cm = fr->cg_cm;
-    
-    for(i=0; i<estNR; i++)
-    {
-        if (EST_DISTR(i))
-        {
-            switch (i)
-            {
-            case estX:   /* Always present */            break;
-            case estV:   bV   = (state->flags & (1<<i)); break;
-            case estSDX: bSDX = (state->flags & (1<<i)); break;
-            case estCGP: bCGP = (state->flags & (1<<i)); break;
-            case estLD_RNG:
-            case estLD_RNGI:
-            case estDISRE_INITF:
-            case estDISRE_RM3TAV:
-            case estORIRE_INITF:
-            case estORIRE_DTAV:
-                /* No processing required */
-                break;
-            default:
-            gmx_incons("Unknown state entry encountered in dd_redistribute_cg");
-            }
-        }
-    }
-    
-    if (dd->ncg_tot > comm->nalloc_int)
-    {
-        comm->nalloc_int = over_alloc_dd(dd->ncg_tot);
-        srenew(comm->buf_int,comm->nalloc_int);
-    }
-    move = comm->buf_int;
-    
-    /* Clear the count */
-    for(c=0; c<dd->ndim*2; c++)
-    {
-        ncg[c] = 0;
-        nat[c] = 0;
-    }
-
-    npbcdim = dd->npbcdim;
-
-    for(d=0; (d<DIM); d++)
-    {
-        limitd[d] = dd->comm->cellsize_min[d];
-        if (d >= npbcdim && dd->ci[d] == 0)
-        {
-            cell_x0[d] = -GMX_FLOAT_MAX;
-        }
-        else
-        {
-            cell_x0[d] = comm->cell_x0[d];
-        }
-        if (d >= npbcdim && dd->ci[d] == dd->nc[d] - 1)
-        {
-            cell_x1[d] = GMX_FLOAT_MAX;
-        }
-        else
-        {
-            cell_x1[d] = comm->cell_x1[d];
-        }
-        if (d < npbcdim)
-        {
-            limit0[d] = comm->old_cell_x0[d] - limitd[d];
-            limit1[d] = comm->old_cell_x1[d] + limitd[d];
-        }
-        else
-        {
-            /* We check after communication if a charge group moved
-             * more than one cell. Set the pre-comm check limit to float_max.
-             */
-            limit0[d] = -GMX_FLOAT_MAX;
-            limit1[d] =  GMX_FLOAT_MAX;
-        }
-    }
-    
-    make_tric_corr_matrix(npbcdim,state->box,tcm);
-    
-    cgindex = dd->cgindex;
-    
-    /* Compute the center of geometry for all home charge groups
-     * and put them in the box and determine where they should go.
-     */
-    for(cg=0; cg<dd->ncg_home; cg++)
-    {
-        k0   = cgindex[cg];
-        k1   = cgindex[cg+1];
-        nrcg = k1 - k0;
-        if (nrcg == 1)
-        {
-            copy_rvec(state->x[k0],cm_new);
-        }
-        else
-        {
-            inv_ncg = 1.0/nrcg;
-            
-            clear_rvec(cm_new);
-            for(k=k0; (k<k1); k++)
-            {
-                rvec_inc(cm_new,state->x[k]);
-            }
-            for(d=0; (d<DIM); d++)
-            {
-                cm_new[d] = inv_ncg*cm_new[d];
-            }
-        }
-        
-        clear_ivec(dev);
-        /* Do pbc and check DD cell boundary crossings */
-        for(d=DIM-1; d>=0; d--)
-        {
-            if (dd->nc[d] > 1)
-            {
-                bScrew = (dd->bScrewPBC && d == XX);
-                /* Determine the location of this cg in lattice coordinates */
-                pos_d = cm_new[d];
-                if (tric_dir[d])
-                {
-                    for(d2=d+1; d2<DIM; d2++)
-                    {
-                        pos_d += cm_new[d2]*tcm[d2][d];
-                    }
-                }
-                /* Put the charge group in the triclinic unit-cell */
-                if (pos_d >= cell_x1[d])
-                {
-                    if (pos_d >= limit1[d])
-                    {
-                        cg_move_error(fplog,dd,step,cg,d,1,TRUE,limitd[d],
-                                      cg_cm[cg],cm_new,pos_d);
-                    }
-                    dev[d] = 1;
-                    if (dd->ci[d] == dd->nc[d] - 1)
-                    {
-                        rvec_dec(cm_new,state->box[d]);
-                        if (bScrew)
-                        {
-                            cm_new[YY] = state->box[YY][YY] - cm_new[YY];
-                            cm_new[ZZ] = state->box[ZZ][ZZ] - cm_new[ZZ];
-                        }
-                        for(k=k0; (k<k1); k++)
-                        {
-                            rvec_dec(state->x[k],state->box[d]);
-                            if (bScrew)
-                            {
-                                rotate_state_atom(state,k);
-                            }
-                        }
-                    }
-                }
-                else if (pos_d < cell_x0[d])
-                {
-                    if (pos_d < limit0[d])
-                    {
-                        cg_move_error(fplog,dd,step,cg,d,-1,TRUE,limitd[d],
-                                      cg_cm[cg],cm_new,pos_d);
-                    }
-                    dev[d] = -1;
-                    if (dd->ci[d] == 0)
-                    {
-                        rvec_inc(cm_new,state->box[d]);
-                        if (bScrew)
-                        {
-                            cm_new[YY] = state->box[YY][YY] - cm_new[YY];
-                            cm_new[ZZ] = state->box[ZZ][ZZ] - cm_new[ZZ];
-                        }
-                        for(k=k0; (k<k1); k++)
-                        {
-                            rvec_inc(state->x[k],state->box[d]);
-                            if (bScrew)
-                            {
-                                rotate_state_atom(state,k);
-                            }
-                        }
-                    }
-                }
-            }
-            else if (d < npbcdim)
-            {
-                /* Put the charge group in the rectangular unit-cell */
-                while (cm_new[d] >= state->box[d][d])
-                {
-                    rvec_dec(cm_new,state->box[d]);
-                    for(k=k0; (k<k1); k++)
-                    {
-                        rvec_dec(state->x[k],state->box[d]);
-                    }
-                }
-                while (cm_new[d] < 0)
-                {
-                    rvec_inc(cm_new,state->box[d]);
-                    for(k=k0; (k<k1); k++)
-                    {
-                        rvec_inc(state->x[k],state->box[d]);
-                    }
-                }
-            }
-        }
-    
-        copy_rvec(cm_new,cg_cm[cg]);
-        
-        /* Determine where this cg should go */
-        flag = 0;
-        mc = -1;
-        for(d=0; d<dd->ndim; d++)
-        {
-            dim = dd->dim[d];
-            if (dev[dim] == 1)
-            {
-                flag |= DD_FLAG_FW(d);
-                if (mc == -1)
-                {
-                    mc = d*2;
-                }
-            }
-            else if (dev[dim] == -1)
-            {
-                flag |= DD_FLAG_BW(d);
-                if (mc == -1) {
-                    if (dd->nc[dim] > 2)
-                    {
-                        mc = d*2 + 1;
-                    }
-                    else
-                    {
-                        mc = d*2;
-                    }
-                }
-            }
-        }
-        move[cg] = mc;
-        if (mc >= 0)
-        {
-            if (ncg[mc]+1 > comm->cggl_flag_nalloc[mc])
-            {
-                comm->cggl_flag_nalloc[mc] = over_alloc_dd(ncg[mc]+1);
-                srenew(comm->cggl_flag[mc],comm->cggl_flag_nalloc[mc]*DD_CGIBS);
-            }
-            comm->cggl_flag[mc][ncg[mc]*DD_CGIBS  ] = dd->index_gl[cg];
-            /* We store the cg size in the lower 16 bits
-             * and the place where the charge group should go
-             * in the next 6 bits. This saves some communication volume.
-             */
-            comm->cggl_flag[mc][ncg[mc]*DD_CGIBS+1] = nrcg | flag;
-            ncg[mc] += 1;
-            nat[mc] += nrcg;
-        }
-    }
-    
-    inc_nrnb(nrnb,eNR_CGCM,dd->nat_home);
-    inc_nrnb(nrnb,eNR_RESETX,dd->ncg_home);
-    
-    nvec = 1;
-    if (bV)
-    {
-        nvec++;
-    }
-    if (bSDX)
-    {
-        nvec++;
-    }
-    if (bCGP)
-    {
-        nvec++;
-    }
-    
-    /* Make sure the communication buffers are large enough */
-    for(mc=0; mc<dd->ndim*2; mc++)
-    {
-        nvr = ncg[mc] + nat[mc]*nvec;
-        if (nvr > comm->cgcm_state_nalloc[mc])
-        {
-            comm->cgcm_state_nalloc[mc] = over_alloc_dd(nvr);
-            srenew(comm->cgcm_state[mc],comm->cgcm_state_nalloc[mc]);
-        }
-    }
-    
-    /* Recalculating cg_cm might be cheaper than communicating,
-     * but that could give rise to rounding issues.
-     */
-    home_pos_cg =
-        compact_and_copy_vec_cg(dd->ncg_home,move,cgindex,
-                                nvec,cg_cm,comm,bCompact);
-    
-    vec = 0;
-    home_pos_at =
-        compact_and_copy_vec_at(dd->ncg_home,move,cgindex,
-                                nvec,vec++,state->x,comm,bCompact);
-    if (bV)
-    {
-        compact_and_copy_vec_at(dd->ncg_home,move,cgindex,
-                                nvec,vec++,state->v,comm,bCompact);
-    }
-    if (bSDX)
-    {
-        compact_and_copy_vec_at(dd->ncg_home,move,cgindex,
-                                nvec,vec++,state->sd_X,comm,bCompact);
-    }
-    if (bCGP)
-    {
-        compact_and_copy_vec_at(dd->ncg_home,move,cgindex,
-                                nvec,vec++,state->cg_p,comm,bCompact);
-    }
-    
-    if (bCompact)
-    {
-        compact_ind(dd->ncg_home,move,
-                    dd->index_gl,dd->cgindex,dd->gatindex,
-                    dd->ga2la,comm->bLocalCG,
-                    fr->cginfo);
-    }
-    else
-    {
-        clear_and_mark_ind(dd->ncg_home,move,
-                           dd->index_gl,dd->cgindex,dd->gatindex,
-                           dd->ga2la,comm->bLocalCG,
-                           fr->ns.grid->cell_index);
-    }
-    
-    cginfo_mb = fr->cginfo_mb;
-
-    ncg_stay_home = home_pos_cg;
-    for(d=0; d<dd->ndim; d++)
-    {
-        dim = dd->dim[d];
-        ncg_recv = 0;
-        nat_recv = 0;
-        nvr      = 0;
-        for(dir=0; dir<(dd->nc[dim]==2 ? 1 : 2); dir++)
-        {
-            cdd = d*2 + dir;
-            /* Communicate the cg and atom counts */
-            sbuf[0] = ncg[cdd];
-            sbuf[1] = nat[cdd];
-            if (debug)
-            {
-                fprintf(debug,"Sending ddim %d dir %d: ncg %d nat %d\n",
-                        d,dir,sbuf[0],sbuf[1]);
-            }
-            dd_sendrecv_int(dd, d, dir, sbuf, 2, rbuf, 2);
-            
-            if ((ncg_recv+rbuf[0])*DD_CGIBS > comm->nalloc_int)
-            {
-                comm->nalloc_int = over_alloc_dd((ncg_recv+rbuf[0])*DD_CGIBS);
-                srenew(comm->buf_int,comm->nalloc_int);
-            }
-            
-            /* Communicate the charge group indices, sizes and flags */
-            dd_sendrecv_int(dd, d, dir,
-                            comm->cggl_flag[cdd], sbuf[0]*DD_CGIBS,
-                            comm->buf_int+ncg_recv*DD_CGIBS, rbuf[0]*DD_CGIBS);
-            
-            nvs = ncg[cdd] + nat[cdd]*nvec;
-            i   = rbuf[0]  + rbuf[1] *nvec;
-            vec_rvec_check_alloc(&comm->vbuf,nvr+i);
-            
-            /* Communicate cgcm and state */
-            dd_sendrecv_rvec(dd, d, dir,
-                             comm->cgcm_state[cdd], nvs,
-                             comm->vbuf.v+nvr, i);
-            ncg_recv += rbuf[0];
-            nat_recv += rbuf[1];
-            nvr      += i;
-        }
-        
-        /* Process the received charge groups */
-        buf_pos = 0;
-        for(cg=0; cg<ncg_recv; cg++)
-        {
-            flag = comm->buf_int[cg*DD_CGIBS+1];
-
-            if (dim >= npbcdim && dd->nc[dim] > 2)
-            {
-                /* No pbc in this dim and more than one domain boundary.
-                 * We to a separate check if a charge did not move too far.
-                 */
-                if (((flag & DD_FLAG_FW(d)) &&
-                     comm->vbuf.v[buf_pos][d] > cell_x1[dim]) ||
-                    ((flag & DD_FLAG_BW(d)) &&
-                     comm->vbuf.v[buf_pos][d] < cell_x0[dim]))
-                {
-                    cg_move_error(fplog,dd,step,cg,d,
-                                  (flag & DD_FLAG_FW(d)) ? 1 : 0,
-                                   FALSE,0,
-                                   comm->vbuf.v[buf_pos],
-                                   comm->vbuf.v[buf_pos],
-                                   comm->vbuf.v[buf_pos][d]);
-                }
-            }
-
-            mc = -1;
-            if (d < dd->ndim-1)
-            {
-                /* Check which direction this cg should go */
-                for(d2=d+1; (d2<dd->ndim && mc==-1); d2++)
-                {
-                    if (dd->bGridJump)
-                    {
-                        /* The cell boundaries for dimension d2 are not equal
-                         * for each cell row of the lower dimension(s),
-                         * therefore we might need to redetermine where
-                         * this cg should go.
-                         */
-                        dim2 = dd->dim[d2];
-                        /* If this cg crosses the box boundary in dimension d2
-                         * we can use the communicated flag, so we do not
-                         * have to worry about pbc.
-                         */
-                        if (!((dd->ci[dim2] == dd->nc[dim2]-1 &&
-                               (flag & DD_FLAG_FW(d2))) ||
-                              (dd->ci[dim2] == 0 &&
-                               (flag & DD_FLAG_BW(d2)))))
-                        {
-                            /* Clear the two flags for this dimension */
-                            flag &= ~(DD_FLAG_FW(d2) | DD_FLAG_BW(d2));
-                            /* Determine the location of this cg
-                             * in lattice coordinates
-                             */
-                            pos_d = comm->vbuf.v[buf_pos][dim2];
-                            if (tric_dir[dim2])
-                            {
-                                for(d3=dim2+1; d3<DIM; d3++)
-                                {
-                                    pos_d +=
-                                        comm->vbuf.v[buf_pos][d3]*tcm[d3][dim2];
-                                }
-                            }
-                            /* Check of we are not at the box edge.
-                             * pbc is only handled in the first step above,
-                             * but this check could move over pbc while
-                             * the first step did not due to different rounding.
-                             */
-                            if (pos_d >= cell_x1[dim2] &&
-                                dd->ci[dim2] != dd->nc[dim2]-1)
-                            {
-                                flag |= DD_FLAG_FW(d2);
-                            }
-                            else if (pos_d < cell_x0[dim2] &&
-                                     dd->ci[dim2] != 0)
-                            {
-                                flag |= DD_FLAG_BW(d2);
-                            }
-                            comm->buf_int[cg*DD_CGIBS+1] = flag;
-                        }
-                    }
-                    /* Set to which neighboring cell this cg should go */
-                    if (flag & DD_FLAG_FW(d2))
-                    {
-                        mc = d2*2;
-                    }
-                    else if (flag & DD_FLAG_BW(d2))
-                    {
-                        if (dd->nc[dd->dim[d2]] > 2)
-                        {
-                            mc = d2*2+1;
-                        }
-                        else
-                        {
-                            mc = d2*2;
-                        }
-                    }
-                }
-            }
-            
-            nrcg = flag & DD_FLAG_NRCG;
-            if (mc == -1)
-            {
-                if (home_pos_cg+1 > dd->cg_nalloc)
-                {
-                    dd->cg_nalloc = over_alloc_dd(home_pos_cg+1);
-                    srenew(dd->index_gl,dd->cg_nalloc);
-                    srenew(dd->cgindex,dd->cg_nalloc+1);
-                }
-                /* Set the global charge group index and size */
-                dd->index_gl[home_pos_cg] = comm->buf_int[cg*DD_CGIBS];
-                dd->cgindex[home_pos_cg+1] = dd->cgindex[home_pos_cg] + nrcg;
-                /* Copy the state from the buffer */
-                if (home_pos_cg >= fr->cg_nalloc)
-                {
-                    dd_realloc_fr_cg(fr,home_pos_cg+1);
-                    cg_cm = fr->cg_cm;
-                }
-                copy_rvec(comm->vbuf.v[buf_pos++],cg_cm[home_pos_cg]);
-                /* Set the cginfo */
-                fr->cginfo[home_pos_cg] = ddcginfo(cginfo_mb,
-                                                   dd->index_gl[home_pos_cg]);
-                if (comm->bLocalCG)
-                {
-                    comm->bLocalCG[dd->index_gl[home_pos_cg]] = TRUE;
-                }
-
-                if (home_pos_at+nrcg > state->nalloc)
-                {
-                    dd_realloc_state(state,f,home_pos_at+nrcg);
-                }
-                for(i=0; i<nrcg; i++)
-                {
-                    copy_rvec(comm->vbuf.v[buf_pos++],
-                              state->x[home_pos_at+i]);
-                }
-                if (bV)
-                {
-                    for(i=0; i<nrcg; i++)
-                    {
-                        copy_rvec(comm->vbuf.v[buf_pos++],
-                                  state->v[home_pos_at+i]);
-                    }
-                }
-                if (bSDX)
-                {
-                    for(i=0; i<nrcg; i++)
-                    {
-                        copy_rvec(comm->vbuf.v[buf_pos++],
-                                  state->sd_X[home_pos_at+i]);
-                    }
-                }
-                if (bCGP)
-                {
-                    for(i=0; i<nrcg; i++)
-                    {
-                        copy_rvec(comm->vbuf.v[buf_pos++],
-                                  state->cg_p[home_pos_at+i]);
-                    }
-                }
-                home_pos_cg += 1;
-                home_pos_at += nrcg;
-            }
-            else
-            {
-                /* Reallocate the buffers if necessary  */
-                if (ncg[mc]+1 > comm->cggl_flag_nalloc[mc])
-                {
-                    comm->cggl_flag_nalloc[mc] = over_alloc_dd(ncg[mc]+1);
-                    srenew(comm->cggl_flag[mc],comm->cggl_flag_nalloc[mc]*DD_CGIBS);
-                }
-                nvr = ncg[mc] + nat[mc]*nvec;
-                if (nvr + 1 + nrcg*nvec > comm->cgcm_state_nalloc[mc])
-                {
-                    comm->cgcm_state_nalloc[mc] = over_alloc_dd(nvr + 1 + nrcg*nvec);
-                    srenew(comm->cgcm_state[mc],comm->cgcm_state_nalloc[mc]);
-                }
-                /* Copy from the receive to the send buffers */
-                memcpy(comm->cggl_flag[mc] + ncg[mc]*DD_CGIBS,
-                       comm->buf_int + cg*DD_CGIBS,
-                       DD_CGIBS*sizeof(int));
-                memcpy(comm->cgcm_state[mc][nvr],
-                       comm->vbuf.v[buf_pos],
-                       (1+nrcg*nvec)*sizeof(rvec));
-                buf_pos += 1 + nrcg*nvec;
-                ncg[mc] += 1;
-                nat[mc] += nrcg;
-            }
-        }
-    }
-    
-    /* With sorting (!bCompact) the indices are now only partially up to date
-     * and ncg_home and nat_home are not the real count, since there are
-     * "holes" in the arrays for the charge groups that moved to neighbors.
-     */
-    dd->ncg_home = home_pos_cg;
-    dd->nat_home = home_pos_at;
-
-    if (debug)
-    {
-        fprintf(debug,"Finished repartitioning\n");
-    }
-
-    return ncg_stay_home;
-}
-
-void dd_cycles_add(gmx_domdec_t *dd,float cycles,int ddCycl)
-{
-    dd->comm->cycl[ddCycl] += cycles;
-    dd->comm->cycl_n[ddCycl]++;
-    if (cycles > dd->comm->cycl_max[ddCycl])
-    {
-        dd->comm->cycl_max[ddCycl] = cycles;
-    }
-}
-
-static double force_flop_count(t_nrnb *nrnb)
-{
-    int i;
-    double sum;
-    const char *name;
-
-    sum = 0;
-    for(i=eNR_NBKERNEL010; i<eNR_NBKERNEL_FREE_ENERGY; i++)
-    {
-        /* To get closer to the real timings, we half the count
-         * for the normal loops and again half it for water loops.
-         */
-        name = nrnb_str(i);
-        if (strstr(name,"W3") != NULL || strstr(name,"W4") != NULL)
-        {
-            sum += nrnb->n[i]*0.25*cost_nrnb(i);
-        }
-        else
-        {
-            sum += nrnb->n[i]*0.50*cost_nrnb(i);
-        }
-    }
-    for(i=eNR_NBKERNEL_FREE_ENERGY; i<=eNR_NB14; i++)
-    {
-        name = nrnb_str(i);
-        if (strstr(name,"W3") != NULL || strstr(name,"W4") != NULL)
-        sum += nrnb->n[i]*cost_nrnb(i);
-    }
-    for(i=eNR_BONDS; i<=eNR_WALLS; i++)
-    {
-        sum += nrnb->n[i]*cost_nrnb(i);
-    }
-
-    return sum;
-}
-
-void dd_force_flop_start(gmx_domdec_t *dd,t_nrnb *nrnb)
-{
-    if (dd->comm->eFlop)
-    {
-        dd->comm->flop -= force_flop_count(nrnb);
-    }
-}
-void dd_force_flop_stop(gmx_domdec_t *dd,t_nrnb *nrnb)
-{
-    if (dd->comm->eFlop)
-    {
-        dd->comm->flop += force_flop_count(nrnb);
-        dd->comm->flop_n++;
-    }
-}  
-
-static void clear_dd_cycle_counts(gmx_domdec_t *dd)
-{
-    int i;
-    
-    for(i=0; i<ddCyclNr; i++)
-    {
-        dd->comm->cycl[i] = 0;
-        dd->comm->cycl_n[i] = 0;
-        dd->comm->cycl_max[i] = 0;
-    }
-    dd->comm->flop = 0;
-    dd->comm->flop_n = 0;
-}
-
-static void get_load_distribution(gmx_domdec_t *dd,gmx_wallcycle_t wcycle)
-{
-    gmx_domdec_comm_t *comm;
-    gmx_domdec_load_t *load;
-    gmx_domdec_root_t *root=NULL;
-    int  d,dim,cid,i,pos;
-    float cell_frac=0,sbuf[DD_NLOAD_MAX];
-    gmx_bool bSepPME;
-    
-    if (debug)
-    {
-        fprintf(debug,"get_load_distribution start\n");
-    }
-
-    wallcycle_start(wcycle,ewcDDCOMMLOAD);
-    
-    comm = dd->comm;
-    
-    bSepPME = (dd->pme_nodeid >= 0);
-    
-    for(d=dd->ndim-1; d>=0; d--)
-    {
-        dim = dd->dim[d];
-        /* Check if we participate in the communication in this dimension */
-        if (d == dd->ndim-1 || 
-            (dd->ci[dd->dim[d+1]]==0 && dd->ci[dd->dim[dd->ndim-1]]==0))
-        {
-            load = &comm->load[d];
-            if (dd->bGridJump)
-            {
-                cell_frac = comm->cell_f1[d] - comm->cell_f0[d];
-            }
-            pos = 0;
-            if (d == dd->ndim-1)
-            {
-                sbuf[pos++] = dd_force_load(comm);
-                sbuf[pos++] = sbuf[0];
-                if (dd->bGridJump)
-                {
-                    sbuf[pos++] = sbuf[0];
-                    sbuf[pos++] = cell_frac;
-                    if (d > 0)
-                    {
-                        sbuf[pos++] = comm->cell_f_max0[d];
-                        sbuf[pos++] = comm->cell_f_min1[d];
-                    }
-                }
-                if (bSepPME)
-                {
-                    sbuf[pos++] = comm->cycl[ddCyclPPduringPME];
-                    sbuf[pos++] = comm->cycl[ddCyclPME];
-                }
-            }
-            else
-            {
-                sbuf[pos++] = comm->load[d+1].sum;
-                sbuf[pos++] = comm->load[d+1].max;
-                if (dd->bGridJump)
-                {
-                    sbuf[pos++] = comm->load[d+1].sum_m;
-                    sbuf[pos++] = comm->load[d+1].cvol_min*cell_frac;
-                    sbuf[pos++] = comm->load[d+1].flags;
-                    if (d > 0)
-                    {
-                        sbuf[pos++] = comm->cell_f_max0[d];
-                        sbuf[pos++] = comm->cell_f_min1[d];
-                    }
-                }
-                if (bSepPME)
-                {
-                    sbuf[pos++] = comm->load[d+1].mdf;
-                    sbuf[pos++] = comm->load[d+1].pme;
-                }
-            }
-            load->nload = pos;
-            /* Communicate a row in DD direction d.
-             * The communicators are setup such that the root always has rank 0.
-             */
-#ifdef GMX_MPI
-            MPI_Gather(sbuf      ,load->nload*sizeof(float),MPI_BYTE,
-                       load->load,load->nload*sizeof(float),MPI_BYTE,
-                       0,comm->mpi_comm_load[d]);
-#endif
-            if (dd->ci[dim] == dd->master_ci[dim])
-            {
-                /* We are the root, process this row */
-                if (comm->bDynLoadBal)
-                {
-                    root = comm->root[d];
-                }
-                load->sum = 0;
-                load->max = 0;
-                load->sum_m = 0;
-                load->cvol_min = 1;
-                load->flags = 0;
-                load->mdf = 0;
-                load->pme = 0;
-                pos = 0;
-                for(i=0; i<dd->nc[dim]; i++)
-                {
-                    load->sum += load->load[pos++];
-                    load->max = max(load->max,load->load[pos]);
-                    pos++;
-                    if (dd->bGridJump)
-                    {
-                        if (root->bLimited)
-                        {
-                            /* This direction could not be load balanced properly,
-                             * therefore we need to use the maximum iso the average load.
-                             */
-                            load->sum_m = max(load->sum_m,load->load[pos]);
-                        }
-                        else
-                        {
-                            load->sum_m += load->load[pos];
-                        }
-                        pos++;
-                        load->cvol_min = min(load->cvol_min,load->load[pos]);
-                        pos++;
-                        if (d < dd->ndim-1)
-                        {
-                            load->flags = (int)(load->load[pos++] + 0.5);
-                        }
-                        if (d > 0)
-                        {
-                            root->cell_f_max0[i] = load->load[pos++];
-                            root->cell_f_min1[i] = load->load[pos++];
-                        }
-                    }
-                    if (bSepPME)
-                    {
-                        load->mdf = max(load->mdf,load->load[pos]);
-                        pos++;
-                        load->pme = max(load->pme,load->load[pos]);
-                        pos++;
-                    }
-                }
-                if (comm->bDynLoadBal && root->bLimited)
-                {
-                    load->sum_m *= dd->nc[dim];
-                    load->flags |= (1<<d);
-                }
-            }
-        }
-    }
-
-    if (DDMASTER(dd))
-    {
-        comm->nload      += dd_load_count(comm);
-        comm->load_step  += comm->cycl[ddCyclStep];
-        comm->load_sum   += comm->load[0].sum;
-        comm->load_max   += comm->load[0].max;
-        if (comm->bDynLoadBal)
-        {
-            for(d=0; d<dd->ndim; d++)
-            {
-                if (comm->load[0].flags & (1<<d))
-                {
-                    comm->load_lim[d]++;
-                }
-            }
-        }
-        if (bSepPME)
-        {
-            comm->load_mdf += comm->load[0].mdf;
-            comm->load_pme += comm->load[0].pme;
-        }
-    }
-
-    wallcycle_stop(wcycle,ewcDDCOMMLOAD);
-    
-    if (debug)
-    {
-        fprintf(debug,"get_load_distribution finished\n");
-    }
-}
-
-static float dd_force_imb_perf_loss(gmx_domdec_t *dd)
-{
-    /* Return the relative performance loss on the total run time
-     * due to the force calculation load imbalance.
-     */
-    if (dd->comm->nload > 0)
-    {
-        return
-            (dd->comm->load_max*dd->nnodes - dd->comm->load_sum)/
-            (dd->comm->load_step*dd->nnodes);
-    }
-    else
-    {
-        return 0;
-    }
-}
-
-static void print_dd_load_av(FILE *fplog,gmx_domdec_t *dd)
-{
-    char  buf[STRLEN];
-    int   npp,npme,nnodes,d,limp;
-    float imbal,pme_f_ratio,lossf,lossp=0;
-    gmx_bool  bLim;
-    gmx_domdec_comm_t *comm;
-
-    comm = dd->comm;
-    if (DDMASTER(dd) && comm->nload > 0)
-    {
-        npp    = dd->nnodes;
-        npme   = (dd->pme_nodeid >= 0) ? comm->npmenodes : 0;
-        nnodes = npp + npme;
-        imbal = comm->load_max*npp/comm->load_sum - 1;
-        lossf = dd_force_imb_perf_loss(dd);
-        sprintf(buf," Average load imbalance: %.1f %%\n",imbal*100);
-        fprintf(fplog,"%s",buf);
-        fprintf(stderr,"\n");
-        fprintf(stderr,"%s",buf);
-        sprintf(buf," Part of the total run time spent waiting due to load imbalance: %.1f %%\n",lossf*100);
-        fprintf(fplog,"%s",buf);
-        fprintf(stderr,"%s",buf);
-        bLim = FALSE;
-        if (comm->bDynLoadBal)
-        {
-            sprintf(buf," Steps where the load balancing was limited by -rdd, -rcon and/or -dds:");
-            for(d=0; d<dd->ndim; d++)
-            {
-                limp = (200*comm->load_lim[d]+1)/(2*comm->nload);
-                sprintf(buf+strlen(buf)," %c %d %%",dim2char(dd->dim[d]),limp);
-                if (limp >= 50)
-                {
-                    bLim = TRUE;
-                }
-            }
-            sprintf(buf+strlen(buf),"\n");
-            fprintf(fplog,"%s",buf);
-            fprintf(stderr,"%s",buf);
-        }
-        if (npme > 0)
-        {
-            pme_f_ratio = comm->load_pme/comm->load_mdf;
-            lossp = (comm->load_pme -comm->load_mdf)/comm->load_step;
-            if (lossp <= 0)
-            {
-                lossp *= (float)npme/(float)nnodes;
-            }
-            else
-            {
-                lossp *= (float)npp/(float)nnodes;
-            }
-            sprintf(buf," Average PME mesh/force load: %5.3f\n",pme_f_ratio);
-            fprintf(fplog,"%s",buf);
-            fprintf(stderr,"%s",buf);
-            sprintf(buf," Part of the total run time spent waiting due to PP/PME imbalance: %.1f %%\n",fabs(lossp)*100);
-            fprintf(fplog,"%s",buf);
-            fprintf(stderr,"%s",buf);
-        }
-        fprintf(fplog,"\n");
-        fprintf(stderr,"\n");
-        
-        if (lossf >= DD_PERF_LOSS)
-        {
-            sprintf(buf,
-                    "NOTE: %.1f %% performance was lost due to load imbalance\n"
-                    "      in the domain decomposition.\n",lossf*100);
-            if (!comm->bDynLoadBal)
-            {
-                sprintf(buf+strlen(buf),"      You might want to use dynamic load balancing (option -dlb.)\n");
-            }
-            else if (bLim)
-            {
-                sprintf(buf+strlen(buf),"      You might want to decrease the cell size limit (options -rdd, -rcon and/or -dds).\n");
-            }
-            fprintf(fplog,"%s\n",buf);
-            fprintf(stderr,"%s\n",buf);
-        }
-        if (npme > 0 && fabs(lossp) >= DD_PERF_LOSS)
-        {
-            sprintf(buf,
-                    "NOTE: %.1f %% performance was lost because the PME nodes\n"
-                    "      had %s work to do than the PP nodes.\n"
-                    "      You might want to %s the number of PME nodes\n"
-                    "      or %s the cut-off and the grid spacing.\n",
-                    fabs(lossp*100),
-                    (lossp < 0) ? "less"     : "more",
-                    (lossp < 0) ? "decrease" : "increase",
-                    (lossp < 0) ? "decrease" : "increase");
-            fprintf(fplog,"%s\n",buf);
-            fprintf(stderr,"%s\n",buf);
-        }
-    }
-}
-
-static float dd_vol_min(gmx_domdec_t *dd)
-{
-    return dd->comm->load[0].cvol_min*dd->nnodes;
-}
-
-static gmx_bool dd_load_flags(gmx_domdec_t *dd)
-{
-    return dd->comm->load[0].flags;
-}
-
-static float dd_f_imbal(gmx_domdec_t *dd)
-{
-    return dd->comm->load[0].max*dd->nnodes/dd->comm->load[0].sum - 1;
-}
-
-static float dd_pme_f_ratio(gmx_domdec_t *dd)
-{
-    return dd->comm->load[0].pme/dd->comm->load[0].mdf;
-}
-
-static void dd_print_load(FILE *fplog,gmx_domdec_t *dd,gmx_large_int_t step)
-{
-    int flags,d;
-    char buf[22];
-    
-    flags = dd_load_flags(dd);
-    if (flags)
-    {
-        fprintf(fplog,
-                "DD  load balancing is limited by minimum cell size in dimension");
-        for(d=0; d<dd->ndim; d++)
-        {
-            if (flags & (1<<d))
-            {
-                fprintf(fplog," %c",dim2char(dd->dim[d]));
-            }
-        }
-        fprintf(fplog,"\n");
-    }
-    fprintf(fplog,"DD  step %s",gmx_step_str(step,buf));
-    if (dd->comm->bDynLoadBal)
-    {
-        fprintf(fplog,"  vol min/aver %5.3f%c",
-                dd_vol_min(dd),flags ? '!' : ' ');
-    }
-    fprintf(fplog," load imb.: force %4.1f%%",dd_f_imbal(dd)*100);
-    if (dd->comm->cycl_n[ddCyclPME])
-    {
-        fprintf(fplog,"  pme mesh/force %5.3f",dd_pme_f_ratio(dd));
-    }
-    fprintf(fplog,"\n\n");
-}
-
-static void dd_print_load_verbose(gmx_domdec_t *dd)
-{
-    if (dd->comm->bDynLoadBal)
-    {
-        fprintf(stderr,"vol %4.2f%c ",
-                dd_vol_min(dd),dd_load_flags(dd) ? '!' : ' ');
-    }
-    fprintf(stderr,"imb F %2d%% ",(int)(dd_f_imbal(dd)*100+0.5));
-    if (dd->comm->cycl_n[ddCyclPME])
-    {
-        fprintf(stderr,"pme/F %4.2f ",dd_pme_f_ratio(dd));
-    }
-}
-
-#ifdef GMX_MPI
-static void make_load_communicator(gmx_domdec_t *dd,MPI_Group g_all,
-                                   int dim_ind,ivec loc)
-{
-    MPI_Group g_row;
-    MPI_Comm  c_row;
-    int  dim,i,*rank;
-    ivec loc_c;
-    gmx_domdec_root_t *root;
-    
-    dim = dd->dim[dim_ind];
-    copy_ivec(loc,loc_c);
-    snew(rank,dd->nc[dim]);
-    for(i=0; i<dd->nc[dim]; i++)
-    {
-        loc_c[dim] = i;
-        rank[i] = dd_index(dd->nc,loc_c);
-    }
-    /* Here we create a new group, that does not necessarily
-     * include our process. But MPI_Comm_create needs to be
-     * called by all the processes in the original communicator.
-     * Calling MPI_Group_free afterwards gives errors, so I assume
-     * also the group is needed by all processes. (B. Hess)
-     */
-    MPI_Group_incl(g_all,dd->nc[dim],rank,&g_row);
-    MPI_Comm_create(dd->mpi_comm_all,g_row,&c_row);
-    if (c_row != MPI_COMM_NULL)
-    {
-        /* This process is part of the group */
-        dd->comm->mpi_comm_load[dim_ind] = c_row;
-        if (dd->comm->eDLB != edlbNO)
-        {
-            if (dd->ci[dim] == dd->master_ci[dim])
-            {
-                /* This is the root process of this row */
-                snew(dd->comm->root[dim_ind],1);
-                root = dd->comm->root[dim_ind];
-                snew(root->cell_f,DD_CELL_F_SIZE(dd,dim_ind));
-                snew(root->old_cell_f,dd->nc[dim]+1);
-                snew(root->bCellMin,dd->nc[dim]);
-                if (dim_ind > 0)
-                {
-                    snew(root->cell_f_max0,dd->nc[dim]);
-                    snew(root->cell_f_min1,dd->nc[dim]);
-                    snew(root->bound_min,dd->nc[dim]);
-                    snew(root->bound_max,dd->nc[dim]);
-                }
-                snew(root->buf_ncd,dd->nc[dim]);
-            }
-            else
-            {
-                /* This is not a root process, we only need to receive cell_f */
-                snew(dd->comm->cell_f_row,DD_CELL_F_SIZE(dd,dim_ind));
-            }
-        }
-        if (dd->ci[dim] == dd->master_ci[dim])
-        {
-            snew(dd->comm->load[dim_ind].load,dd->nc[dim]*DD_NLOAD_MAX);
-        }
-    }
-    sfree(rank);
-}
-#endif
-
-static void make_load_communicators(gmx_domdec_t *dd)
-{
-#ifdef GMX_MPI
-  MPI_Group g_all;
-  int  dim0,dim1,i,j;
-  ivec loc;
-
-  if (debug)
-    fprintf(debug,"Making load communicators\n");
-
-  MPI_Comm_group(dd->mpi_comm_all,&g_all);
-  
-  snew(dd->comm->load,dd->ndim);
-  snew(dd->comm->mpi_comm_load,dd->ndim);
-  
-  clear_ivec(loc);
-  make_load_communicator(dd,g_all,0,loc);
-  if (dd->ndim > 1) {
-    dim0 = dd->dim[0];
-    for(i=0; i<dd->nc[dim0]; i++) {
-      loc[dim0] = i;
-      make_load_communicator(dd,g_all,1,loc);
-    }
-  }
-  if (dd->ndim > 2) {
-    dim0 = dd->dim[0];
-    for(i=0; i<dd->nc[dim0]; i++) {
-      loc[dim0] = i;
-      dim1 = dd->dim[1];
-      for(j=0; j<dd->nc[dim1]; j++) {
-         loc[dim1] = j;
-         make_load_communicator(dd,g_all,2,loc);
-      }
-    }
-  }
-
-  MPI_Group_free(&g_all);
-
-  if (debug)
-    fprintf(debug,"Finished making load communicators\n");
-#endif
-}
-
-void setup_dd_grid(FILE *fplog,gmx_domdec_t *dd)
-{
-    gmx_bool bZYX;
-    int  d,dim,i,j,m;
-    ivec tmp,s;
-    int  nzone,nzonep;
-    ivec dd_zp[DD_MAXIZONE];
-    gmx_domdec_zones_t *zones;
-    gmx_domdec_ns_ranges_t *izone;
-    
-    for(d=0; d<dd->ndim; d++)
-    {
-        dim = dd->dim[d];
-        copy_ivec(dd->ci,tmp);
-        tmp[dim] = (tmp[dim] + 1) % dd->nc[dim];
-        dd->neighbor[d][0] = ddcoord2ddnodeid(dd,tmp);
-        copy_ivec(dd->ci,tmp);
-        tmp[dim] = (tmp[dim] - 1 + dd->nc[dim]) % dd->nc[dim];
-        dd->neighbor[d][1] = ddcoord2ddnodeid(dd,tmp);
-        if (debug)
-        {
-            fprintf(debug,"DD rank %d neighbor ranks in dir %d are + %d - %d\n",
-                    dd->rank,dim,
-                    dd->neighbor[d][0],
-                    dd->neighbor[d][1]);
-        }
-    }
-    
-    if (DDMASTER(dd))
-    {
-        fprintf(stderr,"Making %dD domain decomposition %d x %d x %d\n",
-           dd->ndim,dd->nc[XX],dd->nc[YY],dd->nc[ZZ]);
-    }
-    if (fplog)
-    {
-        fprintf(fplog,"\nMaking %dD domain decomposition grid %d x %d x %d, home cell index %d %d %d\n\n",
-                dd->ndim,
-                dd->nc[XX],dd->nc[YY],dd->nc[ZZ],
-                dd->ci[XX],dd->ci[YY],dd->ci[ZZ]);
-    }
-    switch (dd->ndim)
-    {
-    case 3:
-        nzone  = dd_z3n;
-        nzonep = dd_zp3n;
-        for(i=0; i<nzonep; i++)
-        {
-            copy_ivec(dd_zp3[i],dd_zp[i]);
-        }
-        break;
-    case 2:
-        nzone  = dd_z2n;
-        nzonep = dd_zp2n;
-        for(i=0; i<nzonep; i++)
-        {
-            copy_ivec(dd_zp2[i],dd_zp[i]);
-        }
-        break;
-    case 1:
-        nzone  = dd_z1n;
-        nzonep = dd_zp1n;
-        for(i=0; i<nzonep; i++)
-        {
-            copy_ivec(dd_zp1[i],dd_zp[i]);
-        }
-        break;
-    default:
-        gmx_fatal(FARGS,"Can only do 1, 2 or 3D domain decomposition");
-        nzone = 0;
-        nzonep = 0;
-    }
-
-    zones = &dd->comm->zones;
-
-    for(i=0; i<nzone; i++)
-    {
-        m = 0;
-        clear_ivec(zones->shift[i]);
-        for(d=0; d<dd->ndim; d++)
-        {
-            zones->shift[i][dd->dim[d]] = dd_zo[i][m++];
-        }
-    }
-    
-    zones->n = nzone;
-    for(i=0; i<nzone; i++)
-    {
-        for(d=0; d<DIM; d++)
-        {
-            s[d] = dd->ci[d] - zones->shift[i][d];
-            if (s[d] < 0)
-            {
-                s[d] += dd->nc[d];
-            }
-            else if (s[d] >= dd->nc[d])
-            {
-                s[d] -= dd->nc[d];
-            }
-        }
-    }
-    zones->nizone = nzonep;
-    for(i=0; i<zones->nizone; i++)
-    {
-        if (dd_zp[i][0] != i)
-        {
-            gmx_fatal(FARGS,"Internal inconsistency in the dd grid setup");
-        }
-        izone = &zones->izone[i];
-        izone->j0 = dd_zp[i][1];
-        izone->j1 = dd_zp[i][2];
-        for(dim=0; dim<DIM; dim++)
-        {
-            if (dd->nc[dim] == 1)
-            {
-                /* All shifts should be allowed */
-                izone->shift0[dim] = -1;
-                izone->shift1[dim] = 1;
-            }
-            else
-            {
-                /*
-                  izone->shift0[d] = 0;
-                  izone->shift1[d] = 0;
-                  for(j=izone->j0; j<izone->j1; j++) {
-                  if (dd->shift[j][d] > dd->shift[i][d])
-                  izone->shift0[d] = -1;
-                  if (dd->shift[j][d] < dd->shift[i][d])
-                  izone->shift1[d] = 1;
-                  }
-                */
-                
-                int shift_diff;
-                
-                /* Assume the shift are not more than 1 cell */
-                izone->shift0[dim] = 1;
-                izone->shift1[dim] = -1;
-                for(j=izone->j0; j<izone->j1; j++)
-                {
-                    shift_diff = zones->shift[j][dim] - zones->shift[i][dim];
-                    if (shift_diff < izone->shift0[dim])
-                    {
-                        izone->shift0[dim] = shift_diff;
-                    }
-                    if (shift_diff > izone->shift1[dim])
-                    {
-                        izone->shift1[dim] = shift_diff;
-                    }
-                }
-            }
-        }
-    }
-    
-    if (dd->comm->eDLB != edlbNO)
-    {
-        snew(dd->comm->root,dd->ndim);
-    }
-    
-    if (dd->comm->bRecordLoad)
-    {
-        make_load_communicators(dd);
-    }
-}
-
-static void make_pp_communicator(FILE *fplog,t_commrec *cr,int reorder)
-{
-    gmx_domdec_t *dd;
-    gmx_domdec_comm_t *comm;
-    int  i,rank,*buf;
-    ivec periods;
-#ifdef GMX_MPI
-    MPI_Comm comm_cart;
-#endif
-    
-    dd = cr->dd;
-    comm = dd->comm;
-    
-#ifdef GMX_MPI
-    if (comm->bCartesianPP)
-    {
-        /* Set up cartesian communication for the particle-particle part */
-        if (fplog)
-        {
-            fprintf(fplog,"Will use a Cartesian communicator: %d x %d x %d\n",
-                    dd->nc[XX],dd->nc[YY],dd->nc[ZZ]);
-        }
-        
-        for(i=0; i<DIM; i++)
-        {
-            periods[i] = TRUE;
-        }
-        MPI_Cart_create(cr->mpi_comm_mygroup,DIM,dd->nc,periods,reorder,
-                        &comm_cart);
-        /* We overwrite the old communicator with the new cartesian one */
-        cr->mpi_comm_mygroup = comm_cart;
-    }
-    
-    dd->mpi_comm_all = cr->mpi_comm_mygroup;
-    MPI_Comm_rank(dd->mpi_comm_all,&dd->rank);
-    
-    if (comm->bCartesianPP_PME)
-    {
-        /* Since we want to use the original cartesian setup for sim,
-         * and not the one after split, we need to make an index.
-         */
-        snew(comm->ddindex2ddnodeid,dd->nnodes);
-        comm->ddindex2ddnodeid[dd_index(dd->nc,dd->ci)] = dd->rank;
-        gmx_sumi(dd->nnodes,comm->ddindex2ddnodeid,cr);
-        /* Get the rank of the DD master,
-         * above we made sure that the master node is a PP node.
-         */
-        if (MASTER(cr))
-        {
-            rank = dd->rank;
-        }
-        else
-        {
-            rank = 0;
-        }
-        MPI_Allreduce(&rank,&dd->masterrank,1,MPI_INT,MPI_SUM,dd->mpi_comm_all);
-    }
-    else if (comm->bCartesianPP)
-    {
-        if (cr->npmenodes == 0)
-        {
-            /* The PP communicator is also
-             * the communicator for this simulation
-             */
-            cr->mpi_comm_mysim = cr->mpi_comm_mygroup;
-        }
-        cr->nodeid = dd->rank;
-        
-        MPI_Cart_coords(dd->mpi_comm_all,dd->rank,DIM,dd->ci);
-        
-        /* We need to make an index to go from the coordinates
-         * to the nodeid of this simulation.
-         */
-        snew(comm->ddindex2simnodeid,dd->nnodes);
-        snew(buf,dd->nnodes);
-        if (cr->duty & DUTY_PP)
-        {
-            buf[dd_index(dd->nc,dd->ci)] = cr->sim_nodeid;
-        }
-        /* Communicate the ddindex to simulation nodeid index */
-        MPI_Allreduce(buf,comm->ddindex2simnodeid,dd->nnodes,MPI_INT,MPI_SUM,
-                      cr->mpi_comm_mysim);
-        sfree(buf);
-        
-        /* Determine the master coordinates and rank.
-         * The DD master should be the same node as the master of this sim.
-         */
-        for(i=0; i<dd->nnodes; i++)
-        {
-            if (comm->ddindex2simnodeid[i] == 0)
-            {
-                ddindex2xyz(dd->nc,i,dd->master_ci);
-                MPI_Cart_rank(dd->mpi_comm_all,dd->master_ci,&dd->masterrank);
-            }
-        }
-        if (debug)
-        {
-            fprintf(debug,"The master rank is %d\n",dd->masterrank);
-        }
-    }
-    else
-    {
-        /* No Cartesian communicators */
-        /* We use the rank in dd->comm->all as DD index */
-        ddindex2xyz(dd->nc,dd->rank,dd->ci);
-        /* The simulation master nodeid is 0, so the DD master rank is also 0 */
-        dd->masterrank = 0;
-        clear_ivec(dd->master_ci);
-    }
-#endif
-  
-    if (fplog)
-    {
-        fprintf(fplog,
-                "Domain decomposition nodeid %d, coordinates %d %d %d\n\n",
-                dd->rank,dd->ci[XX],dd->ci[YY],dd->ci[ZZ]);
-    }
-    if (debug)
-    {
-        fprintf(debug,
-                "Domain decomposition nodeid %d, coordinates %d %d %d\n\n",
-                dd->rank,dd->ci[XX],dd->ci[YY],dd->ci[ZZ]);
-    }
-}
-
-static void receive_ddindex2simnodeid(t_commrec *cr)
-{
-    gmx_domdec_t *dd;
-    
-    gmx_domdec_comm_t *comm;
-    int  *buf;
-    
-    dd = cr->dd;
-    comm = dd->comm;
-    
-#ifdef GMX_MPI
-    if (!comm->bCartesianPP_PME && comm->bCartesianPP)
-    {
-        snew(comm->ddindex2simnodeid,dd->nnodes);
-        snew(buf,dd->nnodes);
-        if (cr->duty & DUTY_PP)
-        {
-            buf[dd_index(dd->nc,dd->ci)] = cr->sim_nodeid;
-        }
-#ifdef GMX_MPI
-        /* Communicate the ddindex to simulation nodeid index */
-        MPI_Allreduce(buf,comm->ddindex2simnodeid,dd->nnodes,MPI_INT,MPI_SUM,
-                      cr->mpi_comm_mysim);
-#endif
-        sfree(buf);
-    }
-#endif
-}
-
-static gmx_domdec_master_t *init_gmx_domdec_master_t(gmx_domdec_t *dd,
-                                                     int ncg,int natoms)
-{
-    gmx_domdec_master_t *ma;
-    int i;
-
-    snew(ma,1);
-    
-    snew(ma->ncg,dd->nnodes);
-    snew(ma->index,dd->nnodes+1);
-    snew(ma->cg,ncg);
-    snew(ma->nat,dd->nnodes);
-    snew(ma->ibuf,dd->nnodes*2);
-    snew(ma->cell_x,DIM);
-    for(i=0; i<DIM; i++)
-    {
-        snew(ma->cell_x[i],dd->nc[i]+1);
-    }
-
-    if (dd->nnodes <= GMX_DD_NNODES_SENDRECV)
-    {
-        ma->vbuf = NULL;
-    }
-    else
-    {
-        snew(ma->vbuf,natoms);
-    }
-
-    return ma;
-}
-
-static void split_communicator(FILE *fplog,t_commrec *cr,int dd_node_order,
-                               int reorder)
-{
-    gmx_domdec_t *dd;
-    gmx_domdec_comm_t *comm;
-    int  i,rank;
-    gmx_bool bDiv[DIM];
-    ivec periods;
-#ifdef GMX_MPI
-    MPI_Comm comm_cart;
-#endif
-    
-    dd = cr->dd;
-    comm = dd->comm;
-    
-    if (comm->bCartesianPP)
-    {
-        for(i=1; i<DIM; i++)
-        {
-            bDiv[i] = ((cr->npmenodes*dd->nc[i]) % (dd->nnodes) == 0);
-        }
-        if (bDiv[YY] || bDiv[ZZ])
-        {
-            comm->bCartesianPP_PME = TRUE;
-            /* If we have 2D PME decomposition, which is always in x+y,
-             * we stack the PME only nodes in z.
-             * Otherwise we choose the direction that provides the thinnest slab
-             * of PME only nodes as this will have the least effect
-             * on the PP communication.
-             * But for the PME communication the opposite might be better.
-             */
-            if (bDiv[ZZ] && (comm->npmenodes_y > 1 ||
-                             !bDiv[YY] ||
-                             dd->nc[YY] > dd->nc[ZZ]))
-            {
-                comm->cartpmedim = ZZ;
-            }
-            else
-            {
-                comm->cartpmedim = YY;
-            }
-            comm->ntot[comm->cartpmedim]
-                += (cr->npmenodes*dd->nc[comm->cartpmedim])/dd->nnodes;
-        }
-        else if (fplog)
-        {
-            fprintf(fplog,"#pmenodes (%d) is not a multiple of nx*ny (%d*%d) or nx*nz (%d*%d)\n",cr->npmenodes,dd->nc[XX],dd->nc[YY],dd->nc[XX],dd->nc[ZZ]);
-            fprintf(fplog,
-                    "Will not use a Cartesian communicator for PP <-> PME\n\n");
-        }
-    }
-    
-#ifdef GMX_MPI
-    if (comm->bCartesianPP_PME)
-    {
-        if (fplog)
-        {
-            fprintf(fplog,"Will use a Cartesian communicator for PP <-> PME: %d x %d x %d\n",comm->ntot[XX],comm->ntot[YY],comm->ntot[ZZ]);
-        }
-        
-        for(i=0; i<DIM; i++)
-        {
-            periods[i] = TRUE;
-        }
-        MPI_Cart_create(cr->mpi_comm_mysim,DIM,comm->ntot,periods,reorder,
-                        &comm_cart);
-        
-        MPI_Comm_rank(comm_cart,&rank);
-        if (MASTERNODE(cr) && rank != 0)
-        {
-            gmx_fatal(FARGS,"MPI rank 0 was renumbered by MPI_Cart_create, we do not allow this");
-        }
-        
-        /* With this assigment we loose the link to the original communicator
-         * which will usually be MPI_COMM_WORLD, unless have multisim.
-         */
-        cr->mpi_comm_mysim = comm_cart;
-        cr->sim_nodeid = rank;
-        
-        MPI_Cart_coords(cr->mpi_comm_mysim,cr->sim_nodeid,DIM,dd->ci);
-        
-        if (fplog)
-        {
-            fprintf(fplog,"Cartesian nodeid %d, coordinates %d %d %d\n\n",
-                    cr->sim_nodeid,dd->ci[XX],dd->ci[YY],dd->ci[ZZ]);
-        }
-        
-        if (dd->ci[comm->cartpmedim] < dd->nc[comm->cartpmedim])
-        {
-            cr->duty = DUTY_PP;
-        }
-        if (cr->npmenodes == 0 ||
-            dd->ci[comm->cartpmedim] >= dd->nc[comm->cartpmedim])
-        {
-            cr->duty = DUTY_PME;
-        }
-        
-        /* Split the sim communicator into PP and PME only nodes */
-        MPI_Comm_split(cr->mpi_comm_mysim,
-                       cr->duty,
-                       dd_index(comm->ntot,dd->ci),
-                       &cr->mpi_comm_mygroup);
-    }
-    else
-    {
-        switch (dd_node_order)
-        {
-        case ddnoPP_PME:
-            if (fplog)
-            {
-                fprintf(fplog,"Order of the nodes: PP first, PME last\n");
-            }
-            break;
-        case ddnoINTERLEAVE:
-            /* Interleave the PP-only and PME-only nodes,
-             * as on clusters with dual-core machines this will double
-             * the communication bandwidth of the PME processes
-             * and thus speed up the PP <-> PME and inter PME communication.
-             */
-            if (fplog)
-            {
-                fprintf(fplog,"Interleaving PP and PME nodes\n");
-            }
-            comm->pmenodes = dd_pmenodes(cr);
-            break;
-        case ddnoCARTESIAN:
-            break;
-        default:
-            gmx_fatal(FARGS,"Unknown dd_node_order=%d",dd_node_order);
-        }
-    
-        if (dd_simnode2pmenode(cr,cr->sim_nodeid) == -1)
-        {
-            cr->duty = DUTY_PME;
-        }
-        else
-        {
-            cr->duty = DUTY_PP;
-        }
-        
-        /* Split the sim communicator into PP and PME only nodes */
-        MPI_Comm_split(cr->mpi_comm_mysim,
-                       cr->duty,
-                       cr->nodeid,
-                       &cr->mpi_comm_mygroup);
-        MPI_Comm_rank(cr->mpi_comm_mygroup,&cr->nodeid);
-    }
-#endif
-
-    if (fplog)
-    {
-        fprintf(fplog,"This is a %s only node\n\n",
-                (cr->duty & DUTY_PP) ? "particle-particle" : "PME-mesh");
-    }
-}
-
-void make_dd_communicators(FILE *fplog,t_commrec *cr,int dd_node_order)
-{
-    gmx_domdec_t *dd;
-    gmx_domdec_comm_t *comm;
-    int CartReorder;
-    
-    dd = cr->dd;
-    comm = dd->comm;
-    
-    copy_ivec(dd->nc,comm->ntot);
-    
-    comm->bCartesianPP = (dd_node_order == ddnoCARTESIAN);
-    comm->bCartesianPP_PME = FALSE;
-    
-    /* Reorder the nodes by default. This might change the MPI ranks.
-     * Real reordering is only supported on very few architectures,
-     * Blue Gene is one of them.
-     */
-    CartReorder = (getenv("GMX_NO_CART_REORDER") == NULL);
-    
-    if (cr->npmenodes > 0)
-    {
-        /* Split the communicator into a PP and PME part */
-        split_communicator(fplog,cr,dd_node_order,CartReorder);
-        if (comm->bCartesianPP_PME)
-        {
-            /* We (possibly) reordered the nodes in split_communicator,
-             * so it is no longer required in make_pp_communicator.
-             */
-            CartReorder = FALSE;
-        }
-    }
-    else
-    {
-        /* All nodes do PP and PME */
-#ifdef GMX_MPI    
-        /* We do not require separate communicators */
-        cr->mpi_comm_mygroup = cr->mpi_comm_mysim;
-#endif
-    }
-    
-    if (cr->duty & DUTY_PP)
-    {
-        /* Copy or make a new PP communicator */
-        make_pp_communicator(fplog,cr,CartReorder);
-    }
-    else
-    {
-        receive_ddindex2simnodeid(cr);
-    }
-    
-    if (!(cr->duty & DUTY_PME))
-    {
-        /* Set up the commnuication to our PME node */
-        dd->pme_nodeid = dd_simnode2pmenode(cr,cr->sim_nodeid);
-        dd->pme_receive_vir_ener = receive_vir_ener(cr);
-        if (debug)
-        {
-            fprintf(debug,"My pme_nodeid %d receive ener %d\n",
-                    dd->pme_nodeid,dd->pme_receive_vir_ener);
-        }
-    }
-    else
-    {
-        dd->pme_nodeid = -1;
-    }
-
-    if (DDMASTER(dd))
-    {
-        dd->ma = init_gmx_domdec_master_t(dd,
-                                          comm->cgs_gl.nr,
-                                          comm->cgs_gl.index[comm->cgs_gl.nr]);
-    }
-}
-
-static real *get_slb_frac(FILE *fplog,const char *dir,int nc,const char *size_string)
-{
-    real *slb_frac,tot;
-    int  i,n;
-    double dbl;
-    
-    slb_frac = NULL;
-    if (nc > 1 && size_string != NULL)
-    {
-        if (fplog)
-        {
-            fprintf(fplog,"Using static load balancing for the %s direction\n",
-                    dir);
-        }
-        snew(slb_frac,nc);
-        tot = 0;
-        for (i=0; i<nc; i++)
-        {
-            dbl = 0;
-            sscanf(size_string,"%lf%n",&dbl,&n);
-            if (dbl == 0)
-            {
-                gmx_fatal(FARGS,"Incorrect or not enough DD cell size entries for direction %s: '%s'",dir,size_string);
-            }
-            slb_frac[i] = dbl;
-            size_string += n;
-            tot += slb_frac[i];
-        }
-        /* Normalize */
-        if (fplog)
-        {
-            fprintf(fplog,"Relative cell sizes:");
-        }
-        for (i=0; i<nc; i++)
-        {
-            slb_frac[i] /= tot;
-            if (fplog)
-            {
-                fprintf(fplog," %5.3f",slb_frac[i]);
-            }
-        }
-        if (fplog)
-        {
-            fprintf(fplog,"\n");
-        }
-    }
-    
-    return slb_frac;
-}
-
-static int multi_body_bondeds_count(gmx_mtop_t *mtop)
-{
-    int n,nmol,ftype;
-    gmx_mtop_ilistloop_t iloop;
-    t_ilist *il;
-    
-    n = 0;
-    iloop = gmx_mtop_ilistloop_init(mtop);
-    while (gmx_mtop_ilistloop_next(iloop,&il,&nmol))
-    {
-        for(ftype=0; ftype<F_NRE; ftype++)
-        {
-            if ((interaction_function[ftype].flags & IF_BOND) &&
-                NRAL(ftype) >  2)
-            {
-                n += nmol*il[ftype].nr/(1 + NRAL(ftype));
-            }
-        }
-  }
-
-  return n;
-}
-
-static int dd_nst_env(FILE *fplog,const char *env_var,int def)
-{
-    char *val;
-    int  nst;
-    
-    nst = def;
-    val = getenv(env_var);
-    if (val)
-    {
-        if (sscanf(val,"%d",&nst) <= 0)
-        {
-            nst = 1;
-        }
-        if (fplog)
-        {
-            fprintf(fplog,"Found env.var. %s = %s, using value %d\n",
-                    env_var,val,nst);
-        }
-    }
-    
-    return nst;
-}
-
-static void dd_warning(t_commrec *cr,FILE *fplog,const char *warn_string)
-{
-    if (MASTER(cr))
-    {
-        fprintf(stderr,"\n%s\n",warn_string);
-    }
-    if (fplog)
-    {
-        fprintf(fplog,"\n%s\n",warn_string);
-    }
-}
-
-static void check_dd_restrictions(t_commrec *cr,gmx_domdec_t *dd,
-                                  t_inputrec *ir,FILE *fplog)
-{
-    if (ir->ePBC == epbcSCREW &&
-        (dd->nc[XX] == 1 || dd->nc[YY] > 1 || dd->nc[ZZ] > 1))
-    {
-        gmx_fatal(FARGS,"With pbc=%s can only do domain decomposition in the x-direction",epbc_names[ir->ePBC]);
-    }
-
-    if (ir->ns_type == ensSIMPLE)
-    {
-        gmx_fatal(FARGS,"Domain decomposition does not support simple neighbor searching, use grid searching or use particle decomposition");
-    }
-
-    if (ir->nstlist == 0)
-    {
-        gmx_fatal(FARGS,"Domain decomposition does not work with nstlist=0");
-    }
-
-    if (ir->comm_mode == ecmANGULAR && ir->ePBC != epbcNONE)
-    {
-        dd_warning(cr,fplog,"comm-mode angular will give incorrect results when the comm group partially crosses a periodic boundary");
-    }
-}
-
-static real average_cellsize_min(gmx_domdec_t *dd,gmx_ddbox_t *ddbox)
-{
-    int  di,d;
-    real r;
-
-    r = ddbox->box_size[XX];
-    for(di=0; di<dd->ndim; di++)
-    {
-        d = dd->dim[di];
-        /* Check using the initial average cell size */
-        r = min(r,ddbox->box_size[d]*ddbox->skew_fac[d]/dd->nc[d]);
-    }
-
-    return r;
-}
-
-static int check_dlb_support(FILE *fplog,t_commrec *cr,
-                             const char *dlb_opt,gmx_bool bRecordLoad,
-                             unsigned long Flags,t_inputrec *ir)
-{
-    gmx_domdec_t *dd;
-    int  eDLB=-1;
-    char buf[STRLEN];
-
-    switch (dlb_opt[0])
-    {
-    case 'a': eDLB = edlbAUTO; break;
-    case 'n': eDLB = edlbNO;   break;
-    case 'y': eDLB = edlbYES;  break;
-    default: gmx_incons("Unknown dlb_opt");
-    }
-
-    if (Flags & MD_RERUN)
-    {
-        return edlbNO;
-    }
-
-    if (!EI_DYNAMICS(ir->eI))
-    {
-        if (eDLB == edlbYES)
-        {
-            sprintf(buf,"NOTE: dynamic load balancing is only supported with dynamics, not with integrator '%s'\n",EI(ir->eI));
-            dd_warning(cr,fplog,buf);
-        }
-            
-        return edlbNO;
-    }
-
-    if (!bRecordLoad)
-    {
-        dd_warning(cr,fplog,"NOTE: Cycle counting is not supported on this architecture, will not use dynamic load balancing\n");
-
-        return edlbNO;
-    }
-
-    if (Flags & MD_REPRODUCIBLE)
-    {
-        switch (eDLB)
-        {
-                       case edlbNO: 
-                               break;
-                       case edlbAUTO:
-                               dd_warning(cr,fplog,"NOTE: reproducability requested, will not use dynamic load balancing\n");
-                               eDLB = edlbNO;
-                               break;
-                       case edlbYES:
-                               dd_warning(cr,fplog,"WARNING: reproducability requested with dynamic load balancing, the simulation will NOT be binary reproducable\n");
-                               break;
-                       default:
-                               gmx_fatal(FARGS,"Death horror: undefined case (%d) for load balancing choice",eDLB);
-                               break;
-        }
-    }
-
-    return eDLB;
-}
-
-static void set_dd_dim(FILE *fplog,gmx_domdec_t *dd)
-{
-    int dim;
-
-    dd->ndim = 0;
-    if (getenv("GMX_DD_ORDER_ZYX") != NULL)
-    {
-        /* Decomposition order z,y,x */
-        if (fplog)
-        {
-            fprintf(fplog,"Using domain decomposition order z, y, x\n");
-        }
-        for(dim=DIM-1; dim>=0; dim--)
-        {
-            if (dd->nc[dim] > 1)
-            {
-                dd->dim[dd->ndim++] = dim;
-            }
-        }
-    }
-    else
-    {
-        /* Decomposition order x,y,z */
-        for(dim=0; dim<DIM; dim++)
-        {
-            if (dd->nc[dim] > 1)
-            {
-                dd->dim[dd->ndim++] = dim;
-            }
-        }
-    }
-}
-
-static gmx_domdec_comm_t *init_dd_comm()
-{
-    gmx_domdec_comm_t *comm;
-    int  i;
-
-    snew(comm,1);
-    snew(comm->cggl_flag,DIM*2);
-    snew(comm->cgcm_state,DIM*2);
-    for(i=0; i<DIM*2; i++)
-    {
-        comm->cggl_flag_nalloc[i]  = 0;
-        comm->cgcm_state_nalloc[i] = 0;
-    }
-    
-    comm->nalloc_int = 0;
-    comm->buf_int    = NULL;
-
-    vec_rvec_init(&comm->vbuf);
-
-    comm->n_load_have    = 0;
-    comm->n_load_collect = 0;
-
-    for(i=0; i<ddnatNR-ddnatZONE; i++)
-    {
-        comm->sum_nat[i] = 0;
-    }
-    comm->ndecomp = 0;
-    comm->nload   = 0;
-    comm->load_step = 0;
-    comm->load_sum  = 0;
-    comm->load_max  = 0;
-    clear_ivec(comm->load_lim);
-    comm->load_mdf  = 0;
-    comm->load_pme  = 0;
-
-    return comm;
-}
-
-gmx_domdec_t *init_domain_decomposition(FILE *fplog,t_commrec *cr,
-                                        unsigned long Flags,
-                                        ivec nc,
-                                        real comm_distance_min,real rconstr,
-                                        const char *dlb_opt,real dlb_scale,
-                                        const char *sizex,const char *sizey,const char *sizez,
-                                        gmx_mtop_t *mtop,t_inputrec *ir,
-                                        matrix box,rvec *x,
-                                        gmx_ddbox_t *ddbox,
-                                        int *npme_x,int *npme_y)
-{
-    gmx_domdec_t *dd;
-    gmx_domdec_comm_t *comm;
-    int  recload;
-    int  d,i,j;
-    real r_2b,r_mb,r_bonded=-1,r_bonded_limit=-1,limit,acs;
-    gmx_bool bC;
-    char buf[STRLEN];
-    
-    if (fplog)
-    {
-        fprintf(fplog,
-                "\nInitializing Domain Decomposition on %d nodes\n",cr->nnodes);
-    }
-    
-    snew(dd,1);
-
-    dd->comm = init_dd_comm();
-    comm = dd->comm;
-    snew(comm->cggl_flag,DIM*2);
-    snew(comm->cgcm_state,DIM*2);
-
-    dd->npbcdim   = ePBC2npbcdim(ir->ePBC);
-    dd->bScrewPBC = (ir->ePBC == epbcSCREW);
-    
-    dd->bSendRecv2      = dd_nst_env(fplog,"GMX_DD_SENDRECV2",0);
-    comm->eFlop         = dd_nst_env(fplog,"GMX_DLB_FLOP",0);
-    recload             = dd_nst_env(fplog,"GMX_DD_LOAD",1);
-    comm->nstSortCG     = dd_nst_env(fplog,"GMX_DD_SORT",1);
-    comm->nstDDDump     = dd_nst_env(fplog,"GMX_DD_DUMP",0);
-    comm->nstDDDumpGrid = dd_nst_env(fplog,"GMX_DD_DUMP_GRID",0);
-    comm->DD_debug      = dd_nst_env(fplog,"GMX_DD_DEBUG",0);
-
-    dd->pme_recv_f_alloc = 0;
-    dd->pme_recv_f_buf = NULL;
-
-    if (dd->bSendRecv2 && fplog)
-    {
-        fprintf(fplog,"Will use two sequential MPI_Sendrecv calls instead of two simultaneous non-blocking MPI_Irecv and MPI_Isend pairs for constraint and vsite communication\n");
-    }
-    if (comm->eFlop)
-    {
-        if (fplog)
-        {
-            fprintf(fplog,"Will load balance based on FLOP count\n");
-        }
-        if (comm->eFlop > 1)
-        {
-            srand(1+cr->nodeid);
-        }
-        comm->bRecordLoad = TRUE;
-    }
-    else
-    {
-        comm->bRecordLoad = (wallcycle_have_counter() && recload > 0);
-                             
-    }
-    
-    comm->eDLB = check_dlb_support(fplog,cr,dlb_opt,comm->bRecordLoad,Flags,ir);
-    
-    comm->bDynLoadBal = (comm->eDLB == edlbYES);
-    if (fplog)
-    {
-        fprintf(fplog,"Dynamic load balancing: %s\n",edlb_names[comm->eDLB]);
-    }
-    dd->bGridJump = comm->bDynLoadBal;
-    
-    if (comm->nstSortCG)
-    {
-        if (fplog)
-        {
-            if (comm->nstSortCG == 1)
-            {
-                fprintf(fplog,"Will sort the charge groups at every domain (re)decomposition\n");
-            }
-            else
-            {
-                fprintf(fplog,"Will sort the charge groups every %d steps\n",
-                        comm->nstSortCG);
-            }
-        }
-        snew(comm->sort,1);
-    }
-    else
-    {
-        if (fplog)
-        {
-            fprintf(fplog,"Will not sort the charge groups\n");
-        }
-    }
-    
-    comm->bInterCGBondeds = (ncg_mtop(mtop) > mtop->mols.nr);
-    if (comm->bInterCGBondeds)
-    {
-        comm->bInterCGMultiBody = (multi_body_bondeds_count(mtop) > 0);
-    }
-    else
-    {
-        comm->bInterCGMultiBody = FALSE;
-    }
-    
-    dd->bInterCGcons = inter_charge_group_constraints(mtop);
-
-    if (ir->rlistlong == 0)
-    {
-        /* Set the cut-off to some very large value,
-         * so we don't need if statements everywhere in the code.
-         * We use sqrt, since the cut-off is squared in some places.
-         */
-        comm->cutoff   = GMX_CUTOFF_INF;
-    }
-    else
-    {
-        comm->cutoff   = ir->rlistlong;
-    }
-    comm->cutoff_mbody = 0;
-    
-    comm->cellsize_limit = 0;
-    comm->bBondComm = FALSE;
-
-    if (comm->bInterCGBondeds)
-    {
-        if (comm_distance_min > 0)
-        {
-            comm->cutoff_mbody = comm_distance_min;
-            if (Flags & MD_DDBONDCOMM)
-            {
-                comm->bBondComm = (comm->cutoff_mbody > comm->cutoff);
-            }
-            else
-            {
-                comm->cutoff = max(comm->cutoff,comm->cutoff_mbody);
-            }
-            r_bonded_limit = comm->cutoff_mbody;
-        }
-        else if (ir->bPeriodicMols)
-        {
-            /* Can not easily determine the required cut-off */
-            dd_warning(cr,fplog,"NOTE: Periodic molecules: can not easily determine the required minimum bonded cut-off, using half the non-bonded cut-off\n");
-            comm->cutoff_mbody = comm->cutoff/2;
-            r_bonded_limit = comm->cutoff_mbody;
-        }
-        else
-        {
-            if (MASTER(cr))
-            {
-                dd_bonded_cg_distance(fplog,dd,mtop,ir,x,box,
-                                      Flags & MD_DDBONDCHECK,&r_2b,&r_mb);
-            }
-            gmx_bcast(sizeof(r_2b),&r_2b,cr);
-            gmx_bcast(sizeof(r_mb),&r_mb,cr);
-
-            /* We use an initial margin of 10% for the minimum cell size,
-             * except when we are just below the non-bonded cut-off.
-             */
-            if (Flags & MD_DDBONDCOMM)
-            {
-                if (max(r_2b,r_mb) > comm->cutoff)
-                {
-                    r_bonded       = max(r_2b,r_mb);
-                    r_bonded_limit = 1.1*r_bonded;
-                    comm->bBondComm = TRUE;
-                }
-                else
-                {
-                    r_bonded       = r_mb;
-                    r_bonded_limit = min(1.1*r_bonded,comm->cutoff);
-                }
-                /* We determine cutoff_mbody later */
-            }
-            else
-            {
-                /* No special bonded communication,
-                 * simply increase the DD cut-off.
-                 */
-                r_bonded_limit     = 1.1*max(r_2b,r_mb);
-                comm->cutoff_mbody = r_bonded_limit;
-                comm->cutoff       = max(comm->cutoff,comm->cutoff_mbody);
-            }
-        }
-        comm->cellsize_limit = max(comm->cellsize_limit,r_bonded_limit);
-        if (fplog)
-        {
-            fprintf(fplog,
-                    "Minimum cell size due to bonded interactions: %.3f nm\n",
-                    comm->cellsize_limit);
-        }
-    }
-
-    if (dd->bInterCGcons && rconstr <= 0)
-    {
-        /* There is a cell size limit due to the constraints (P-LINCS) */
-        rconstr = constr_r_max(fplog,mtop,ir);
-        if (fplog)
-        {
-            fprintf(fplog,
-                    "Estimated maximum distance required for P-LINCS: %.3f nm\n",
-                    rconstr);
-            if (rconstr > comm->cellsize_limit)
-            {
-                fprintf(fplog,"This distance will limit the DD cell size, you can override this with -rcon\n");
-            }
-        }
-    }
-    else if (rconstr > 0 && fplog)
-    {
-        /* Here we do not check for dd->bInterCGcons,
-         * because one can also set a cell size limit for virtual sites only
-         * and at this point we don't know yet if there are intercg v-sites.
-         */
-        fprintf(fplog,
-                "User supplied maximum distance required for P-LINCS: %.3f nm\n",
-                rconstr);
-    }
-    comm->cellsize_limit = max(comm->cellsize_limit,rconstr);
-
-    comm->cgs_gl = gmx_mtop_global_cgs(mtop);
-
-    if (nc[XX] > 0)
-    {
-        copy_ivec(nc,dd->nc);
-        set_dd_dim(fplog,dd);
-        set_ddbox_cr(cr,&dd->nc,ir,box,&comm->cgs_gl,x,ddbox);
-
-        if (cr->npmenodes == -1)
-        {
-            cr->npmenodes = 0;
-        }
-        acs = average_cellsize_min(dd,ddbox);
-        if (acs < comm->cellsize_limit)
-        {
-            if (fplog)
-            {
-                fprintf(fplog,"ERROR: The initial cell size (%f) is smaller than the cell size limit (%f)\n",acs,comm->cellsize_limit);
-            }
-            gmx_fatal_collective(FARGS,cr,NULL,
-                                 "The initial cell size (%f) is smaller than the cell size limit (%f), change options -dd, -rdd or -rcon, see the log file for details",
-                                 acs,comm->cellsize_limit);
-        }
-    }
-    else
-    {
-        set_ddbox_cr(cr,NULL,ir,box,&comm->cgs_gl,x,ddbox);
-
-        /* We need to choose the optimal DD grid and possibly PME nodes */
-        limit = dd_choose_grid(fplog,cr,dd,ir,mtop,box,ddbox,
-                               comm->eDLB!=edlbNO,dlb_scale,
-                               comm->cellsize_limit,comm->cutoff,
-                               comm->bInterCGBondeds,comm->bInterCGMultiBody);
-        
-        if (dd->nc[XX] == 0)
-        {
-            bC = (dd->bInterCGcons && rconstr > r_bonded_limit);
-            sprintf(buf,"Change the number of nodes or mdrun option %s%s%s",
-                    !bC ? "-rdd" : "-rcon",
-                    comm->eDLB!=edlbNO ? " or -dds" : "",
-                    bC ? " or your LINCS settings" : "");
-
-            gmx_fatal_collective(FARGS,cr,NULL,
-                                 "There is no domain decomposition for %d nodes that is compatible with the given box and a minimum cell size of %g nm\n"
-                                 "%s\n"
-                                 "Look in the log file for details on the domain decomposition",
-                                 cr->nnodes-cr->npmenodes,limit,buf);
-        }
-        set_dd_dim(fplog,dd);
-    }
-
-    if (fplog)
-    {
-        fprintf(fplog,
-                "Domain decomposition grid %d x %d x %d, separate PME nodes %d\n",
-                dd->nc[XX],dd->nc[YY],dd->nc[ZZ],cr->npmenodes);
-    }
-    
-    dd->nnodes = dd->nc[XX]*dd->nc[YY]*dd->nc[ZZ];
-    if (cr->nnodes - dd->nnodes != cr->npmenodes)
-    {
-        gmx_fatal_collective(FARGS,cr,NULL,
-                             "The size of the domain decomposition grid (%d) does not match the number of nodes (%d). The total number of nodes is %d",
-                             dd->nnodes,cr->nnodes - cr->npmenodes,cr->nnodes);
-    }
-    if (cr->npmenodes > dd->nnodes)
-    {
-        gmx_fatal_collective(FARGS,cr,NULL,
-                             "The number of separate PME node (%d) is larger than the number of PP nodes (%d), this is not supported.",cr->npmenodes,dd->nnodes);
-    }
-    if (cr->npmenodes > 0)
-    {
-        comm->npmenodes = cr->npmenodes;
-    }
-    else
-    {
-        comm->npmenodes = dd->nnodes;
-    }
-
-    if (EEL_PME(ir->coulombtype))
-    {
-        /* The following choices should match those
-         * in comm_cost_est in domdec_setup.c.
-         * Note that here the checks have to take into account
-         * that the decomposition might occur in a different order than xyz
-         * (for instance through the env.var. GMX_DD_ORDER_ZYX),
-         * in which case they will not match those in comm_cost_est,
-         * but since that is mainly for testing purposes that's fine.
-         */
-        if (dd->ndim >= 2 && dd->dim[0] == XX && dd->dim[1] == YY &&
-            comm->npmenodes > dd->nc[XX] && comm->npmenodes % dd->nc[XX] == 0 &&
-            getenv("GMX_PMEONEDD") == NULL)
-        {
-            comm->npmedecompdim = 2;
-            comm->npmenodes_x   = dd->nc[XX];
-            comm->npmenodes_y   = comm->npmenodes/comm->npmenodes_x;
-        }
-        else
-        {
-            /* In case nc is 1 in both x and y we could still choose to
-             * decompose pme in y instead of x, but we use x for simplicity.
-             */
-            comm->npmedecompdim = 1;
-            if (dd->dim[0] == YY)
-            {
-                comm->npmenodes_x = 1;
-                comm->npmenodes_y = comm->npmenodes;
-            }
-            else
-            {
-                comm->npmenodes_x = comm->npmenodes;
-                comm->npmenodes_y = 1;
-            }
-        }    
-        if (fplog)
-        {
-            fprintf(fplog,"PME domain decomposition: %d x %d x %d\n",
-                    comm->npmenodes_x,comm->npmenodes_y,1);
-        }
-    }
-    else
-    {
-        comm->npmedecompdim = 0;
-        comm->npmenodes_x   = 0;
-        comm->npmenodes_y   = 0;
-    }
-    
-    /* Technically we don't need both of these,
-     * but it simplifies code not having to recalculate it.
-     */
-    *npme_x = comm->npmenodes_x;
-    *npme_y = comm->npmenodes_y;
-        
-    snew(comm->slb_frac,DIM);
-    if (comm->eDLB == edlbNO)
-    {
-        comm->slb_frac[XX] = get_slb_frac(fplog,"x",dd->nc[XX],sizex);
-        comm->slb_frac[YY] = get_slb_frac(fplog,"y",dd->nc[YY],sizey);
-        comm->slb_frac[ZZ] = get_slb_frac(fplog,"z",dd->nc[ZZ],sizez);
-    }
-
-    if (comm->bInterCGBondeds && comm->cutoff_mbody == 0)
-    {
-        if (comm->bBondComm || comm->eDLB != edlbNO)
-        {
-            /* Set the bonded communication distance to halfway
-             * the minimum and the maximum,
-             * since the extra communication cost is nearly zero.
-             */
-            acs = average_cellsize_min(dd,ddbox);
-            comm->cutoff_mbody = 0.5*(r_bonded + acs);
-            if (comm->eDLB != edlbNO)
-            {
-                /* Check if this does not limit the scaling */
-                comm->cutoff_mbody = min(comm->cutoff_mbody,dlb_scale*acs);
-            }
-            if (!comm->bBondComm)
-            {
-                /* Without bBondComm do not go beyond the n.b. cut-off */
-                comm->cutoff_mbody = min(comm->cutoff_mbody,comm->cutoff);
-                if (comm->cellsize_limit >= comm->cutoff)
-                {
-                    /* We don't loose a lot of efficieny
-                     * when increasing it to the n.b. cut-off.
-                     * It can even be slightly faster, because we need
-                     * less checks for the communication setup.
-                     */
-                    comm->cutoff_mbody = comm->cutoff;
-                }
-            }
-            /* Check if we did not end up below our original limit */
-            comm->cutoff_mbody = max(comm->cutoff_mbody,r_bonded_limit);
-
-            if (comm->cutoff_mbody > comm->cellsize_limit)
-            {
-                comm->cellsize_limit = comm->cutoff_mbody;
-            }
-        }
-        /* Without DLB and cutoff_mbody<cutoff, cutoff_mbody is dynamic */
-    }
-
-    if (debug)
-    {
-        fprintf(debug,"Bonded atom communication beyond the cut-off: %d\n"
-                "cellsize limit %f\n",
-                comm->bBondComm,comm->cellsize_limit);
-    }
-    
-    if (MASTER(cr))
-    {
-        check_dd_restrictions(cr,dd,ir,fplog);
-    }
-
-    comm->partition_step = INT_MIN;
-    dd->ddp_count = 0;
-
-    clear_dd_cycle_counts(dd);
-
-    return dd;
-}
-
-static void set_dlb_limits(gmx_domdec_t *dd)
-
-{
-    int d;
-
-    for(d=0; d<dd->ndim; d++)
-    {
-        dd->comm->cd[d].np = dd->comm->cd[d].np_dlb;
-        dd->comm->cellsize_min[dd->dim[d]] =
-            dd->comm->cellsize_min_dlb[dd->dim[d]];
-    }
-}
-
-
-static void turn_on_dlb(FILE *fplog,t_commrec *cr,gmx_large_int_t step)
-{
-    gmx_domdec_t *dd;
-    gmx_domdec_comm_t *comm;
-    real cellsize_min;
-    int  d,nc,i;
-    char buf[STRLEN];
-    
-    dd = cr->dd;
-    comm = dd->comm;
-    
-    if (fplog)
-    {
-        fprintf(fplog,"At step %s the performance loss due to force load imbalance is %.1f %%\n",gmx_step_str(step,buf),dd_force_imb_perf_loss(dd)*100);
-    }
-
-    cellsize_min = comm->cellsize_min[dd->dim[0]];
-    for(d=1; d<dd->ndim; d++)
-    {
-        cellsize_min = min(cellsize_min,comm->cellsize_min[dd->dim[d]]);
-    }
-
-    if (cellsize_min < comm->cellsize_limit*1.05)
-    {
-        dd_warning(cr,fplog,"NOTE: the minimum cell size is smaller than 1.05 times the cell size limit, will not turn on dynamic load balancing\n");
-
-        /* Change DLB from "auto" to "no". */
-        comm->eDLB = edlbNO;
-
-        return;
-    }
-
-    dd_warning(cr,fplog,"NOTE: Turning on dynamic load balancing\n");
-    comm->bDynLoadBal = TRUE;
-    dd->bGridJump = TRUE;
-    
-    set_dlb_limits(dd);
-
-    /* We can set the required cell size info here,
-     * so we do not need to communicate this.
-     * The grid is completely uniform.
-     */
-    for(d=0; d<dd->ndim; d++)
-    {
-        if (comm->root[d])
-        {
-            comm->load[d].sum_m = comm->load[d].sum;
-
-            nc = dd->nc[dd->dim[d]];
-            for(i=0; i<nc; i++)
-            {
-                comm->root[d]->cell_f[i]    = i/(real)nc;
-                if (d > 0)
-                {
-                    comm->root[d]->cell_f_max0[i] =  i   /(real)nc;
-                    comm->root[d]->cell_f_min1[i] = (i+1)/(real)nc;
-                }
-            }
-            comm->root[d]->cell_f[nc] = 1.0;
-        }
-    }
-}
-
-static char *init_bLocalCG(gmx_mtop_t *mtop)
-{
-    int  ncg,cg;
-    char *bLocalCG;
-    
-    ncg = ncg_mtop(mtop);
-    snew(bLocalCG,ncg);
-    for(cg=0; cg<ncg; cg++)
-    {
-        bLocalCG[cg] = FALSE;
-    }
-
-    return bLocalCG;
-}
-
-void dd_init_bondeds(FILE *fplog,
-                     gmx_domdec_t *dd,gmx_mtop_t *mtop,
-                     gmx_vsite_t *vsite,gmx_constr_t constr,
-                     t_inputrec *ir,gmx_bool bBCheck,cginfo_mb_t *cginfo_mb)
-{
-    gmx_domdec_comm_t *comm;
-    gmx_bool bBondComm;
-    int  d;
-
-    dd_make_reverse_top(fplog,dd,mtop,vsite,constr,ir,bBCheck);
-
-    comm = dd->comm;
-
-    if (comm->bBondComm)
-    {
-        /* Communicate atoms beyond the cut-off for bonded interactions */
-        comm = dd->comm;
-
-        comm->cglink = make_charge_group_links(mtop,dd,cginfo_mb);
-
-        comm->bLocalCG = init_bLocalCG(mtop);
-    }
-    else
-    {
-        /* Only communicate atoms based on cut-off */
-        comm->cglink   = NULL;
-        comm->bLocalCG = NULL;
-    }
-}
-
-static void print_dd_settings(FILE *fplog,gmx_domdec_t *dd,
-                              t_inputrec *ir,
-                              gmx_bool bDynLoadBal,real dlb_scale,
-                              gmx_ddbox_t *ddbox)
-{
-    gmx_domdec_comm_t *comm;
-    int  d;
-    ivec np;
-    real limit,shrink;
-    char buf[64];
-
-    if (fplog == NULL)
-    {
-        return;
-    }
-
-    comm = dd->comm;
-
-    if (bDynLoadBal)
-    {
-        fprintf(fplog,"The maximum number of communication pulses is:");
-        for(d=0; d<dd->ndim; d++)
-        {
-            fprintf(fplog," %c %d",dim2char(dd->dim[d]),comm->cd[d].np_dlb);
-        }
-        fprintf(fplog,"\n");
-        fprintf(fplog,"The minimum size for domain decomposition cells is %.3f nm\n",comm->cellsize_limit);
-        fprintf(fplog,"The requested allowed shrink of DD cells (option -dds) is: %.2f\n",dlb_scale);
-        fprintf(fplog,"The allowed shrink of domain decomposition cells is:");
-        for(d=0; d<DIM; d++)
-        {
-            if (dd->nc[d] > 1)
-            {
-                if (d >= ddbox->npbcdim && dd->nc[d] == 2)
-                {
-                    shrink = 0;
-                }
-                else
-                {
-                    shrink =
-                        comm->cellsize_min_dlb[d]/
-                        (ddbox->box_size[d]*ddbox->skew_fac[d]/dd->nc[d]);
-                }
-                fprintf(fplog," %c %.2f",dim2char(d),shrink);
-            }
-        }
-        fprintf(fplog,"\n");
-    }
-    else
-    {
-        set_dd_cell_sizes_slb(dd,ddbox,FALSE,np);
-        fprintf(fplog,"The initial number of communication pulses is:");
-        for(d=0; d<dd->ndim; d++)
-        {
-            fprintf(fplog," %c %d",dim2char(dd->dim[d]),np[dd->dim[d]]);
-        }
-        fprintf(fplog,"\n");
-        fprintf(fplog,"The initial domain decomposition cell size is:");
-        for(d=0; d<DIM; d++) {
-            if (dd->nc[d] > 1)
-            {
-                fprintf(fplog," %c %.2f nm",
-                        dim2char(d),dd->comm->cellsize_min[d]);
-            }
-        }
-        fprintf(fplog,"\n\n");
-    }
-    
-    if (comm->bInterCGBondeds || dd->vsite_comm || dd->constraint_comm)
-    {
-        fprintf(fplog,"The maximum allowed distance for charge groups involved in interactions is:\n");
-        fprintf(fplog,"%40s  %-7s %6.3f nm\n",
-                "non-bonded interactions","",comm->cutoff);
-
-        if (bDynLoadBal)
-        {
-            limit = dd->comm->cellsize_limit;
-        }
-        else
-        {
-            if (dynamic_dd_box(ddbox,ir))
-            {
-                fprintf(fplog,"(the following are initial values, they could change due to box deformation)\n");
-            }
-            limit = dd->comm->cellsize_min[XX];
-            for(d=1; d<DIM; d++)
-            {
-                limit = min(limit,dd->comm->cellsize_min[d]);
-            }
-        }
-
-        if (comm->bInterCGBondeds)
-        {
-            fprintf(fplog,"%40s  %-7s %6.3f nm\n",
-                    "two-body bonded interactions","(-rdd)",
-                    max(comm->cutoff,comm->cutoff_mbody));
-            fprintf(fplog,"%40s  %-7s %6.3f nm\n",
-                    "multi-body bonded interactions","(-rdd)",
-                    (comm->bBondComm || dd->bGridJump) ? comm->cutoff_mbody : min(comm->cutoff,limit));
-        }
-        if (dd->vsite_comm)
-        {
-            fprintf(fplog,"%40s  %-7s %6.3f nm\n",
-                    "virtual site constructions","(-rcon)",limit);
-        }
-        if (dd->constraint_comm)
-        {
-            sprintf(buf,"atoms separated by up to %d constraints",
-                    1+ir->nProjOrder);
-            fprintf(fplog,"%40s  %-7s %6.3f nm\n",
-                    buf,"(-rcon)",limit);
-        }
-        fprintf(fplog,"\n");
-    }
-    
-    fflush(fplog);
-}
-
-void set_dd_parameters(FILE *fplog,gmx_domdec_t *dd,real dlb_scale,
-                       t_inputrec *ir,t_forcerec *fr,
-                       gmx_ddbox_t *ddbox)
-{
-    gmx_domdec_comm_t *comm;
-    int  d,dim,npulse,npulse_d_max,npulse_d;
-    gmx_bool bNoCutOff;
-    int  natoms_tot;
-    real vol_frac;
-
-    comm = dd->comm;
-
-    bNoCutOff = (ir->rvdw == 0 || ir->rcoulomb == 0);
-
-    if (EEL_PME(ir->coulombtype))
-    {
-        init_ddpme(dd,&comm->ddpme[0],0);
-        if (comm->npmedecompdim >= 2)
-        {
-            init_ddpme(dd,&comm->ddpme[1],1);
-        }
-    }
-    else
-    {
-        comm->npmenodes = 0;
-        if (dd->pme_nodeid >= 0)
-        {
-            gmx_fatal_collective(FARGS,NULL,dd,
-                                 "Can not have separate PME nodes without PME electrostatics");
-        }
-    }
-    
-    /* If each molecule is a single charge group
-     * or we use domain decomposition for each periodic dimension,
-     * we do not need to take pbc into account for the bonded interactions.
-     */
-    if (fr->ePBC == epbcNONE || !comm->bInterCGBondeds ||
-        (dd->nc[XX]>1 && dd->nc[YY]>1 && (dd->nc[ZZ]>1 || fr->ePBC==epbcXY)))
-    {
-        fr->bMolPBC = FALSE;
-    }
-    else
-    {
-        fr->bMolPBC = TRUE;
-    }
-        
-    if (debug)
-    {
-        fprintf(debug,"The DD cut-off is %f\n",comm->cutoff);
-    }
-    if (comm->eDLB != edlbNO)
-    {
-        /* Determine the maximum number of comm. pulses in one dimension */
-        
-        comm->cellsize_limit = max(comm->cellsize_limit,comm->cutoff_mbody);
-        
-        /* Determine the maximum required number of grid pulses */
-        if (comm->cellsize_limit >= comm->cutoff)
-        {
-            /* Only a single pulse is required */
-            npulse = 1;
-        }
-        else if (!bNoCutOff && comm->cellsize_limit > 0)
-        {
-            /* We round down slightly here to avoid overhead due to the latency
-             * of extra communication calls when the cut-off
-             * would be only slightly longer than the cell size.
-             * Later cellsize_limit is redetermined,
-             * so we can not miss interactions due to this rounding.
-             */
-            npulse = (int)(0.96 + comm->cutoff/comm->cellsize_limit);
-        }
-        else
-        {
-            /* There is no cell size limit */
-            npulse = max(dd->nc[XX]-1,max(dd->nc[YY]-1,dd->nc[ZZ]-1));
-        }
-
-        if (!bNoCutOff && npulse > 1)
-        {
-            /* See if we can do with less pulses, based on dlb_scale */
-            npulse_d_max = 0;
-            for(d=0; d<dd->ndim; d++)
-            {
-                dim = dd->dim[d];
-                npulse_d = (int)(1 + dd->nc[dim]*comm->cutoff
-                                 /(ddbox->box_size[dim]*ddbox->skew_fac[dim]*dlb_scale));
-                npulse_d_max = max(npulse_d_max,npulse_d);
-            }
-            npulse = min(npulse,npulse_d_max);
-        }
-        
-        /* This env var can override npulse */
-        d = dd_nst_env(fplog,"GMX_DD_NPULSE",0);
-        if (d > 0)
-        {
-            npulse = d;
-        }
-
-        comm->maxpulse = 1;
-        comm->bVacDLBNoLimit = (ir->ePBC == epbcNONE);
-        for(d=0; d<dd->ndim; d++)
-        {
-            comm->cd[d].np_dlb = min(npulse,dd->nc[dd->dim[d]]-1);
-            comm->cd[d].np_nalloc = comm->cd[d].np_dlb;
-            snew(comm->cd[d].ind,comm->cd[d].np_nalloc);
-            comm->maxpulse = max(comm->maxpulse,comm->cd[d].np_dlb);
-            if (comm->cd[d].np_dlb < dd->nc[dd->dim[d]]-1)
-            {
-                comm->bVacDLBNoLimit = FALSE;
-            }
-        }
-        
-        /* cellsize_limit is set for LINCS in init_domain_decomposition */
-        if (!comm->bVacDLBNoLimit)
-        {
-            comm->cellsize_limit = max(comm->cellsize_limit,
-                                       comm->cutoff/comm->maxpulse);
-        }
-        comm->cellsize_limit = max(comm->cellsize_limit,comm->cutoff_mbody);
-        /* Set the minimum cell size for each DD dimension */
-        for(d=0; d<dd->ndim; d++)
-        {
-            if (comm->bVacDLBNoLimit ||
-                comm->cd[d].np_dlb*comm->cellsize_limit >= comm->cutoff)
-            {
-                comm->cellsize_min_dlb[dd->dim[d]] = comm->cellsize_limit;
-            }
-            else
-            {
-                comm->cellsize_min_dlb[dd->dim[d]] =
-                    comm->cutoff/comm->cd[d].np_dlb;
-            }
-        }
-        if (comm->cutoff_mbody <= 0)
-        {
-            comm->cutoff_mbody = min(comm->cutoff,comm->cellsize_limit);
-        }
-        if (comm->bDynLoadBal)
-        {
-            set_dlb_limits(dd);
-        }
-    }
-    
-    print_dd_settings(fplog,dd,ir,comm->bDynLoadBal,dlb_scale,ddbox);
-    if (comm->eDLB == edlbAUTO)
-    {
-        if (fplog)
-        {
-            fprintf(fplog,"When dynamic load balancing gets turned on, these settings will change to:\n");
-        }
-        print_dd_settings(fplog,dd,ir,TRUE,dlb_scale,ddbox);
-    }
-
-    if (ir->ePBC == epbcNONE)
-    {
-        vol_frac = 1 - 1/(double)dd->nnodes;
-    }
-    else
-    {
-        vol_frac =
-            (1 + comm_box_frac(dd->nc,comm->cutoff,ddbox))/(double)dd->nnodes;
-    }
-    if (debug)
-    {
-        fprintf(debug,"Volume fraction for all DD zones: %f\n",vol_frac);
-    }
-    natoms_tot = comm->cgs_gl.index[comm->cgs_gl.nr];
-   
-    dd->ga2la = ga2la_init(natoms_tot,vol_frac*natoms_tot);
-}
-
-static void merge_cg_buffers(int ncell,
-                             gmx_domdec_comm_dim_t *cd, int pulse,
-                             int  *ncg_cell,
-                             int  *index_gl, int  *recv_i,
-                             rvec *cg_cm,    rvec *recv_vr,
-                             int *cgindex,
-                             cginfo_mb_t *cginfo_mb,int *cginfo)
-{
-    gmx_domdec_ind_t *ind,*ind_p;
-    int p,cell,c,cg,cg0,cg1,cg_gl,nat;
-    int shift,shift_at;
-    
-    ind = &cd->ind[pulse];
-    
-    /* First correct the already stored data */
-    shift = ind->nrecv[ncell];
-    for(cell=ncell-1; cell>=0; cell--)
-    {
-        shift -= ind->nrecv[cell];
-        if (shift > 0)
-        {
-            /* Move the cg's present from previous grid pulses */
-            cg0 = ncg_cell[ncell+cell];
-            cg1 = ncg_cell[ncell+cell+1];
-            cgindex[cg1+shift] = cgindex[cg1];
-            for(cg=cg1-1; cg>=cg0; cg--)
-            {
-                index_gl[cg+shift] = index_gl[cg];
-                copy_rvec(cg_cm[cg],cg_cm[cg+shift]);
-                cgindex[cg+shift] = cgindex[cg];
-                cginfo[cg+shift] = cginfo[cg];
-            }
-            /* Correct the already stored send indices for the shift */
-            for(p=1; p<=pulse; p++)
-            {
-                ind_p = &cd->ind[p];
-                cg0 = 0;
-                for(c=0; c<cell; c++)
-                {
-                    cg0 += ind_p->nsend[c];
-                }
-                cg1 = cg0 + ind_p->nsend[cell];
-                for(cg=cg0; cg<cg1; cg++)
-                {
-                    ind_p->index[cg] += shift;
-                }
-            }
-        }
-    }
-
-    /* Merge in the communicated buffers */
-    shift = 0;
-    shift_at = 0;
-    cg0 = 0;
-    for(cell=0; cell<ncell; cell++)
-    {
-        cg1 = ncg_cell[ncell+cell+1] + shift;
-        if (shift_at > 0)
-        {
-            /* Correct the old cg indices */
-            for(cg=ncg_cell[ncell+cell]; cg<cg1; cg++)
-            {
-                cgindex[cg+1] += shift_at;
-            }
-        }
-        for(cg=0; cg<ind->nrecv[cell]; cg++)
-        {
-            /* Copy this charge group from the buffer */
-            index_gl[cg1] = recv_i[cg0];
-            copy_rvec(recv_vr[cg0],cg_cm[cg1]);
-            /* Add it to the cgindex */
-            cg_gl = index_gl[cg1];
-            cginfo[cg1] = ddcginfo(cginfo_mb,cg_gl);
-            nat = GET_CGINFO_NATOMS(cginfo[cg1]);
-            cgindex[cg1+1] = cgindex[cg1] + nat;
-            cg0++;
-            cg1++;
-            shift_at += nat;
-        }
-        shift += ind->nrecv[cell];
-        ncg_cell[ncell+cell+1] = cg1;
-    }
-}
-
-static void make_cell2at_index(gmx_domdec_comm_dim_t *cd,
-                               int nzone,int cg0,const int *cgindex)
-{
-    int cg,zone,p;
-    
-    /* Store the atom block boundaries for easy copying of communication buffers
-     */
-    cg = cg0;
-    for(zone=0; zone<nzone; zone++)
-    {
-        for(p=0; p<cd->np; p++) {
-            cd->ind[p].cell2at0[zone] = cgindex[cg];
-            cg += cd->ind[p].nrecv[zone];
-            cd->ind[p].cell2at1[zone] = cgindex[cg];
-        }
-    }
-}
-
-static gmx_bool missing_link(t_blocka *link,int cg_gl,char *bLocalCG)
-{
-    int  i;
-    gmx_bool bMiss;
-
-    bMiss = FALSE;
-    for(i=link->index[cg_gl]; i<link->index[cg_gl+1]; i++)
-    {
-        if (!bLocalCG[link->a[i]])
-        {
-            bMiss = TRUE;
-        }
-    }
-
-    return bMiss;
-}
-
-static void setup_dd_communication(gmx_domdec_t *dd,
-                                   matrix box,gmx_ddbox_t *ddbox,t_forcerec *fr)
-{
-    int dim_ind,dim,dim0,dim1=-1,dim2=-1,dimd,p,nat_tot;
-    int nzone,nzone_send,zone,zonei,cg0,cg1;
-    int c,i,j,cg,cg_gl,nrcg;
-    int *zone_cg_range,pos_cg,*index_gl,*cgindex,*recv_i;
-    gmx_domdec_comm_t *comm;
-    gmx_domdec_zones_t *zones;
-    gmx_domdec_comm_dim_t *cd;
-    gmx_domdec_ind_t *ind;
-    cginfo_mb_t *cginfo_mb;
-    gmx_bool bBondComm,bDist2B,bDistMB,bDistMB_pulse,bDistBonded,bScrew;
-    real r_mb,r_comm2,r_scomm2,r_bcomm2,r,r_0,r_1,r2,rb2,r2inc,inv_ncg,tric_sh;
-    rvec rb,rn;
-    real corner[DIM][4],corner_round_0=0,corner_round_1[4];
-    real bcorner[DIM],bcorner_round_1=0;
-    ivec tric_dist;
-    rvec *cg_cm,*normal,*v_d,*v_0=NULL,*v_1=NULL,*recv_vr;
-    real skew_fac2_d,skew_fac_01;
-    rvec sf2_round;
-    int  nsend,nat;
-    
-    if (debug)
-    {
-        fprintf(debug,"Setting up DD communication\n");
-    }
-    
-    comm  = dd->comm;
-    cg_cm = fr->cg_cm;
-
-    for(dim_ind=0; dim_ind<dd->ndim; dim_ind++)
-    {
-        dim = dd->dim[dim_ind];
-
-        /* Check if we need to use triclinic distances */
-        tric_dist[dim_ind] = 0;
-        for(i=0; i<=dim_ind; i++)
-        {
-            if (ddbox->tric_dir[dd->dim[i]])
-            {
-                tric_dist[dim_ind] = 1;
-            }
-        }
-    }
-
-    bBondComm = comm->bBondComm;
-
-    /* Do we need to determine extra distances for multi-body bondeds? */
-    bDistMB = (comm->bInterCGMultiBody && dd->bGridJump && dd->ndim > 1);
-    
-    /* Do we need to determine extra distances for only two-body bondeds? */
-    bDist2B = (bBondComm && !bDistMB);
-
-    r_comm2  = sqr(comm->cutoff);
-    r_bcomm2 = sqr(comm->cutoff_mbody);
-
-    if (debug)
-    {
-        fprintf(debug,"bBondComm %d, r_bc %f\n",bBondComm,sqrt(r_bcomm2));
-    }
-
-    zones = &comm->zones;
-    
-    dim0 = dd->dim[0];
-    /* The first dimension is equal for all cells */
-    corner[0][0] = comm->cell_x0[dim0];
-    if (bDistMB)
-    {
-        bcorner[0] = corner[0][0];
-    }
-    if (dd->ndim >= 2)
-    {
-        dim1 = dd->dim[1];
-        /* This cell row is only seen from the first row */
-        corner[1][0] = comm->cell_x0[dim1];
-        /* All rows can see this row */
-        corner[1][1] = comm->cell_x0[dim1];
-        if (dd->bGridJump)
-        {
-            corner[1][1] = max(comm->cell_x0[dim1],comm->zone_d1[1].mch0);
-            if (bDistMB)
-            {
-                /* For the multi-body distance we need the maximum */
-                bcorner[1] = max(comm->cell_x0[dim1],comm->zone_d1[1].p1_0);
-            }
-        }
-        /* Set the upper-right corner for rounding */
-        corner_round_0 = comm->cell_x1[dim0];
-        
-        if (dd->ndim >= 3)
-        {
-            dim2 = dd->dim[2];
-            for(j=0; j<4; j++)
-            {
-                corner[2][j] = comm->cell_x0[dim2];
-            }
-            if (dd->bGridJump)
-            {
-                /* Use the maximum of the i-cells that see a j-cell */
-                for(i=0; i<zones->nizone; i++)
-                {
-                    for(j=zones->izone[i].j0; j<zones->izone[i].j1; j++)
-                    {
-                        if (j >= 4)
-                        {
-                            corner[2][j-4] =
-                                max(corner[2][j-4],
-                                    comm->zone_d2[zones->shift[i][dim0]][zones->shift[i][dim1]].mch0);
-                        }
-                    }
-                }
-                if (bDistMB)
-                {
-                    /* For the multi-body distance we need the maximum */
-                    bcorner[2] = comm->cell_x0[dim2];
-                    for(i=0; i<2; i++)
-                    {
-                        for(j=0; j<2; j++)
-                        {
-                            bcorner[2] = max(bcorner[2],
-                                             comm->zone_d2[i][j].p1_0);
-                        }
-                    }
-                }
-            }
-            
-            /* Set the upper-right corner for rounding */
-            /* Cell (0,0,0) and cell (1,0,0) can see cell 4 (0,1,1)
-             * Only cell (0,0,0) can see cell 7 (1,1,1)
-             */
-            corner_round_1[0] = comm->cell_x1[dim1];
-            corner_round_1[3] = comm->cell_x1[dim1];
-            if (dd->bGridJump)
-            {
-                corner_round_1[0] = max(comm->cell_x1[dim1],
-                                        comm->zone_d1[1].mch1);
-                if (bDistMB)
-                {
-                    /* For the multi-body distance we need the maximum */
-                    bcorner_round_1 = max(comm->cell_x1[dim1],
-                                          comm->zone_d1[1].p1_1);
-                }
-            }
-        }
-    }
-    
-    /* Triclinic stuff */
-    normal = ddbox->normal;
-    skew_fac_01 = 0;
-    if (dd->ndim >= 2)
-    {
-        v_0 = ddbox->v[dim0];
-        if (ddbox->tric_dir[dim0] && ddbox->tric_dir[dim1])
-        {
-            /* Determine the coupling coefficient for the distances
-             * to the cell planes along dim0 and dim1 through dim2.
-             * This is required for correct rounding.
-             */
-            skew_fac_01 =
-                ddbox->v[dim0][dim1+1][dim0]*ddbox->v[dim1][dim1+1][dim1];
-            if (debug)
-            {
-                fprintf(debug,"\nskew_fac_01 %f\n",skew_fac_01);
-            }
-        }
-    }
-    if (dd->ndim >= 3)
-    {
-        v_1 = ddbox->v[dim1];
-    }
-    
-    zone_cg_range = zones->cg_range;
-    index_gl = dd->index_gl;
-    cgindex  = dd->cgindex;
-    cginfo_mb = fr->cginfo_mb;
-    
-    zone_cg_range[0]   = 0;
-    zone_cg_range[1]   = dd->ncg_home;
-    comm->zone_ncg1[0] = dd->ncg_home;
-    pos_cg             = dd->ncg_home;
-    
-    nat_tot = dd->nat_home;
-    nzone = 1;
-    for(dim_ind=0; dim_ind<dd->ndim; dim_ind++)
-    {
-        dim = dd->dim[dim_ind];
-        cd = &comm->cd[dim_ind];
-        
-        if (dim >= ddbox->npbcdim && dd->ci[dim] == 0)
-        {
-            /* No pbc in this dimension, the first node should not comm. */
-            nzone_send = 0;
-        }
-        else
-        {
-            nzone_send = nzone;
-        }
-
-        bScrew = (dd->bScrewPBC && dim == XX);
-        
-        v_d = ddbox->v[dim];
-        skew_fac2_d = sqr(ddbox->skew_fac[dim]);
-
-        cd->bInPlace = TRUE;
-        for(p=0; p<cd->np; p++)
-        {
-            /* Only atoms communicated in the first pulse are used
-             * for multi-body bonded interactions or for bBondComm.
-             */
-            bDistBonded   = ((bDistMB || bDist2B) && p == 0);
-            bDistMB_pulse = (bDistMB && bDistBonded);
-
-            ind = &cd->ind[p];
-            nsend = 0;
-            nat = 0;
-            for(zone=0; zone<nzone_send; zone++)
-            {
-                if (tric_dist[dim_ind] && dim_ind > 0)
-                {
-                    /* Determine slightly more optimized skew_fac's
-                     * for rounding.
-                     * This reduces the number of communicated atoms
-                     * by about 10% for 3D DD of rhombic dodecahedra.
-                     */
-                    for(dimd=0; dimd<dim; dimd++)
-                    {
-                        sf2_round[dimd] = 1;
-                        if (ddbox->tric_dir[dimd])
-                        {
-                            for(i=dd->dim[dimd]+1; i<DIM; i++)
-                            {
-                                /* If we are shifted in dimension i
-                                 * and the cell plane is tilted forward
-                                 * in dimension i, skip this coupling.
-                                 */
-                                if (!(zones->shift[nzone+zone][i] &&
-                                      ddbox->v[dimd][i][dimd] >= 0))
-                                {
-                                    sf2_round[dimd] +=
-                                        sqr(ddbox->v[dimd][i][dimd]);
-                                }
-                            }
-                            sf2_round[dimd] = 1/sf2_round[dimd];
-                        }
-                    }
-                }
-
-                zonei = zone_perm[dim_ind][zone];
-                if (p == 0)
-                {
-                    /* Here we permutate the zones to obtain a convenient order
-                     * for neighbor searching
-                     */
-                    cg0 = zone_cg_range[zonei];
-                    cg1 = zone_cg_range[zonei+1];
-                }
-                else
-                {
-                    /* Look only at the cg's received in the previous grid pulse
-                     */
-                    cg1 = zone_cg_range[nzone+zone+1];
-                    cg0 = cg1 - cd->ind[p-1].nrecv[zone];
-                }
-                ind->nsend[zone] = 0;
-                for(cg=cg0; cg<cg1; cg++)
-                {
-                    r2  = 0;
-                    rb2 = 0;
-                    if (tric_dist[dim_ind] == 0)
-                    {
-                        /* Rectangular direction, easy */
-                        r = cg_cm[cg][dim] - corner[dim_ind][zone];
-                        if (r > 0)
-                        {
-                            r2 += r*r;
-                        }
-                        if (bDistMB_pulse)
-                        {
-                            r = cg_cm[cg][dim] - bcorner[dim_ind];
-                            if (r > 0)
-                            {
-                                rb2 += r*r;
-                            }
-                        }
-                        /* Rounding gives at most a 16% reduction
-                         * in communicated atoms
-                         */
-                        if (dim_ind >= 1 && (zonei == 1 || zonei == 2))
-                        {
-                            r = cg_cm[cg][dim0] - corner_round_0;
-                            /* This is the first dimension, so always r >= 0 */
-                            r2 += r*r;
-                            if (bDistMB_pulse)
-                            {
-                                rb2 += r*r;
-                            }
-                        }
-                        if (dim_ind == 2 && (zonei == 2 || zonei == 3))
-                        {
-                            r = cg_cm[cg][dim1] - corner_round_1[zone];
-                            if (r > 0)
-                            {
-                                r2 += r*r;
-                            }
-                            if (bDistMB_pulse)
-                            {
-                                r = cg_cm[cg][dim1] - bcorner_round_1;
-                                if (r > 0)
-                                {
-                                    rb2 += r*r;
-                                }
-                            }
-                        }
-                    }
-                    else
-                    {
-                        /* Triclinic direction, more complicated */
-                        clear_rvec(rn);
-                        clear_rvec(rb);
-                        /* Rounding, conservative as the skew_fac multiplication
-                         * will slightly underestimate the distance.
-                         */
-                        if (dim_ind >= 1 && (zonei == 1 || zonei == 2))
-                        {
-                            rn[dim0] = cg_cm[cg][dim0] - corner_round_0;
-                            for(i=dim0+1; i<DIM; i++)
-                            {
-                                rn[dim0] -= cg_cm[cg][i]*v_0[i][dim0];
-                            }
-                            r2 = rn[dim0]*rn[dim0]*sf2_round[dim0];
-                            if (bDistMB_pulse)
-                            {
-                                rb[dim0] = rn[dim0];
-                                rb2 = r2;
-                            }
-                            /* Take care that the cell planes along dim0 might not
-                             * be orthogonal to those along dim1 and dim2.
-                             */
-                            for(i=1; i<=dim_ind; i++)
-                            {
-                                dimd = dd->dim[i];
-                                if (normal[dim0][dimd] > 0)
-                                {
-                                    rn[dimd] -= rn[dim0]*normal[dim0][dimd];
-                                    if (bDistMB_pulse)
-                                    {
-                                        rb[dimd] -= rb[dim0]*normal[dim0][dimd];
-                                    }
-                                }
-                            }
-                        }
-                        if (dim_ind == 2 && (zonei == 2 || zonei == 3))
-                        {
-                            rn[dim1] += cg_cm[cg][dim1] - corner_round_1[zone];
-                            tric_sh = 0;
-                            for(i=dim1+1; i<DIM; i++)
-                            {
-                                tric_sh -= cg_cm[cg][i]*v_1[i][dim1];
-                            }
-                            rn[dim1] += tric_sh;
-                            if (rn[dim1] > 0)
-                            {
-                                r2 += rn[dim1]*rn[dim1]*sf2_round[dim1];
-                                /* Take care of coupling of the distances
-                                 * to the planes along dim0 and dim1 through dim2.
-                                 */
-                                r2 -= rn[dim0]*rn[dim1]*skew_fac_01;
-                                /* Take care that the cell planes along dim1
-                                 * might not be orthogonal to that along dim2.
-                                 */
-                                if (normal[dim1][dim2] > 0)
-                                {
-                                    rn[dim2] -= rn[dim1]*normal[dim1][dim2];
-                                }
-                            }
-                            if (bDistMB_pulse)
-                            {
-                                rb[dim1] +=
-                                    cg_cm[cg][dim1] - bcorner_round_1 + tric_sh;
-                                if (rb[dim1] > 0)
-                                {
-                                    rb2 += rb[dim1]*rb[dim1]*sf2_round[dim1];
-                                    /* Take care of coupling of the distances
-                                     * to the planes along dim0 and dim1 through dim2.
-                                     */
-                                    rb2 -= rb[dim0]*rb[dim1]*skew_fac_01;
-                                    /* Take care that the cell planes along dim1
-                                     * might not be orthogonal to that along dim2.
-                                     */
-                                    if (normal[dim1][dim2] > 0)
-                                    {
-                                        rb[dim2] -= rb[dim1]*normal[dim1][dim2];
-                                    }
-                                }
-                            }
-                        }
-                        /* The distance along the communication direction */
-                        rn[dim] += cg_cm[cg][dim] - corner[dim_ind][zone];
-                        tric_sh = 0;
-                        for(i=dim+1; i<DIM; i++)
-                        {
-                            tric_sh -= cg_cm[cg][i]*v_d[i][dim];
-                        }
-                        rn[dim] += tric_sh;
-                        if (rn[dim] > 0)
-                        {
-                            r2 += rn[dim]*rn[dim]*skew_fac2_d;
-                            /* Take care of coupling of the distances
-                             * to the planes along dim0 and dim1 through dim2.
-                             */
-                            if (dim_ind == 1 && zonei == 1)
-                            {
-                                r2 -= rn[dim0]*rn[dim]*skew_fac_01;
-                            }
-                        }
-                        if (bDistMB_pulse)
-                        {
-                            clear_rvec(rb);
-                            rb[dim] += cg_cm[cg][dim] - bcorner[dim_ind] + tric_sh;
-                            if (rb[dim] > 0)
-                            {
-                                rb2 += rb[dim]*rb[dim]*skew_fac2_d;
-                                /* Take care of coupling of the distances
-                                 * to the planes along dim0 and dim1 through dim2.
-                                 */
-                                if (dim_ind == 1 && zonei == 1)
-                                {
-                                    rb2 -= rb[dim0]*rb[dim]*skew_fac_01;
-                                }
-                            }
-                        }
-                    }
-                    
-                    if (r2 < r_comm2 ||
-                        (bDistBonded &&
-                         ((bDistMB && rb2 < r_bcomm2) ||
-                          (bDist2B && r2  < r_bcomm2)) &&
-                         (!bBondComm ||
-                          (GET_CGINFO_BOND_INTER(fr->cginfo[cg]) &&
-                           missing_link(comm->cglink,index_gl[cg],
-                                        comm->bLocalCG)))))
-                    {
-                        /* Make an index to the local charge groups */
-                        if (nsend+1 > ind->nalloc)
-                        {
-                            ind->nalloc = over_alloc_large(nsend+1);
-                            srenew(ind->index,ind->nalloc);
-                        }
-                        if (nsend+1 > comm->nalloc_int)
-                        {
-                            comm->nalloc_int = over_alloc_large(nsend+1);
-                            srenew(comm->buf_int,comm->nalloc_int);
-                        }
-                        ind->index[nsend] = cg;
-                        comm->buf_int[nsend] = index_gl[cg];
-                        ind->nsend[zone]++;
-                        vec_rvec_check_alloc(&comm->vbuf,nsend+1);
-
-                        if (dd->ci[dim] == 0)
-                        {
-                            /* Correct cg_cm for pbc */
-                            rvec_add(cg_cm[cg],box[dim],comm->vbuf.v[nsend]);
-                            if (bScrew)
-                            {
-                                comm->vbuf.v[nsend][YY] =
-                                    box[YY][YY]-comm->vbuf.v[nsend][YY];
-                                comm->vbuf.v[nsend][ZZ] =
-                                    box[ZZ][ZZ]-comm->vbuf.v[nsend][ZZ];
-                            }
-                        }
-                        else
-                        {
-                            copy_rvec(cg_cm[cg],comm->vbuf.v[nsend]);
-                        }
-                        nsend++;
-                        nat += cgindex[cg+1] - cgindex[cg];
-                    }
-                }
-            }
-            /* Clear the counts in case we do not have pbc */
-            for(zone=nzone_send; zone<nzone; zone++)
-            {
-                ind->nsend[zone] = 0;
-            }
-            ind->nsend[nzone]   = nsend;
-            ind->nsend[nzone+1] = nat;
-            /* Communicate the number of cg's and atoms to receive */
-            dd_sendrecv_int(dd, dim_ind, dddirBackward,
-                            ind->nsend, nzone+2,
-                            ind->nrecv, nzone+2);
-            
-            /* The rvec buffer is also required for atom buffers of size nsend
-             * in dd_move_x and dd_move_f.
-             */
-            vec_rvec_check_alloc(&comm->vbuf,ind->nsend[nzone+1]);
-
-            if (p > 0)
-            {
-                /* We can receive in place if only the last zone is not empty */
-                for(zone=0; zone<nzone-1; zone++)
-                {
-                    if (ind->nrecv[zone] > 0)
-                    {
-                        cd->bInPlace = FALSE;
-                    }
-                }
-                if (!cd->bInPlace)
-                {
-                    /* The int buffer is only required here for the cg indices */
-                    if (ind->nrecv[nzone] > comm->nalloc_int2)
-                    {
-                        comm->nalloc_int2 = over_alloc_dd(ind->nrecv[nzone]);
-                        srenew(comm->buf_int2,comm->nalloc_int2);
-                    }
-                    /* The rvec buffer is also required for atom buffers
-                     * of size nrecv in dd_move_x and dd_move_f.
-                     */
-                    i = max(cd->ind[0].nrecv[nzone+1],ind->nrecv[nzone+1]);
-                    vec_rvec_check_alloc(&comm->vbuf2,i);
-                }
-            }
-            
-            /* Make space for the global cg indices */
-            if (pos_cg + ind->nrecv[nzone] > dd->cg_nalloc
-                || dd->cg_nalloc == 0)
-            {
-                dd->cg_nalloc = over_alloc_dd(pos_cg + ind->nrecv[nzone]);
-                srenew(index_gl,dd->cg_nalloc);
-                srenew(cgindex,dd->cg_nalloc+1);
-            }
-            /* Communicate the global cg indices */
-            if (cd->bInPlace)
-            {
-                recv_i = index_gl + pos_cg;
-            }
-            else
-            {
-                recv_i = comm->buf_int2;
-            }
-            dd_sendrecv_int(dd, dim_ind, dddirBackward,
-                            comm->buf_int, nsend,
-                            recv_i,        ind->nrecv[nzone]);
-
-            /* Make space for cg_cm */
-            if (pos_cg + ind->nrecv[nzone] > fr->cg_nalloc)
-            {
-                dd_realloc_fr_cg(fr,pos_cg + ind->nrecv[nzone]);
-                cg_cm = fr->cg_cm;
-            }
-            /* Communicate cg_cm */
-            if (cd->bInPlace)
-            {
-                recv_vr = cg_cm + pos_cg;
-            }
-            else
-            {
-                recv_vr = comm->vbuf2.v;
-            }
-            dd_sendrecv_rvec(dd, dim_ind, dddirBackward,
-                             comm->vbuf.v, nsend,
-                             recv_vr,      ind->nrecv[nzone]);
-            
-            /* Make the charge group index */
-            if (cd->bInPlace)
-            {
-                zone = (p == 0 ? 0 : nzone - 1);
-                while (zone < nzone)
-                {
-                    for(cg=0; cg<ind->nrecv[zone]; cg++)
-                    {
-                        cg_gl = index_gl[pos_cg];
-                        fr->cginfo[pos_cg] = ddcginfo(cginfo_mb,cg_gl);
-                        nrcg = GET_CGINFO_NATOMS(fr->cginfo[pos_cg]);
-                        cgindex[pos_cg+1] = cgindex[pos_cg] + nrcg;
-                        if (bBondComm)
-                        {
-                            /* Update the charge group presence,
-                             * so we can use it in the next pass of the loop.
-                             */
-                            comm->bLocalCG[cg_gl] = TRUE;
-                        }
-                        pos_cg++;
-                    }
-                    if (p == 0)
-                    {
-                        comm->zone_ncg1[nzone+zone] = ind->nrecv[zone];
-                    }
-                    zone++;
-                    zone_cg_range[nzone+zone] = pos_cg;
-                }
-            }
-            else
-            {
-                /* This part of the code is never executed with bBondComm. */
-                merge_cg_buffers(nzone,cd,p,zone_cg_range,
-                                 index_gl,recv_i,cg_cm,recv_vr,
-                                 cgindex,fr->cginfo_mb,fr->cginfo);
-                pos_cg += ind->nrecv[nzone];
-            }
-            nat_tot += ind->nrecv[nzone+1];
-        }
-        if (!cd->bInPlace)
-        {
-            /* Store the atom block for easy copying of communication buffers */
-            make_cell2at_index(cd,nzone,zone_cg_range[nzone],cgindex);
-        }
-        nzone += nzone;
-    }
-    dd->index_gl = index_gl;
-    dd->cgindex  = cgindex;
-    
-    dd->ncg_tot = zone_cg_range[zones->n];
-    dd->nat_tot = nat_tot;
-    comm->nat[ddnatHOME] = dd->nat_home;
-    for(i=ddnatZONE; i<ddnatNR; i++)
-    {
-        comm->nat[i] = dd->nat_tot;
-    }
-
-    if (!bBondComm)
-    {
-        /* We don't need to update cginfo, since that was alrady done above.
-         * So we pass NULL for the forcerec.
-         */
-        dd_set_cginfo(dd->index_gl,dd->ncg_home,dd->ncg_tot,
-                      NULL,comm->bLocalCG);
-    }
-
-    if (debug)
-    {
-        fprintf(debug,"Finished setting up DD communication, zones:");
-        for(c=0; c<zones->n; c++)
-        {
-            fprintf(debug," %d",zones->cg_range[c+1]-zones->cg_range[c]);
-        }
-        fprintf(debug,"\n");
-    }
-}
-
-static void set_cg_boundaries(gmx_domdec_zones_t *zones)
-{
-    int c;
-    
-    for(c=0; c<zones->nizone; c++)
-    {
-        zones->izone[c].cg1  = zones->cg_range[c+1];
-        zones->izone[c].jcg0 = zones->cg_range[zones->izone[c].j0];
-        zones->izone[c].jcg1 = zones->cg_range[zones->izone[c].j1];
-    }
-}
-
-static int comp_cgsort(const void *a,const void *b)
-{
-    int comp;
-    
-    gmx_cgsort_t *cga,*cgb;
-    cga = (gmx_cgsort_t *)a;
-    cgb = (gmx_cgsort_t *)b;
-    
-    comp = cga->nsc - cgb->nsc;
-    if (comp == 0)
-    {
-        comp = cga->ind_gl - cgb->ind_gl;
-    }
-    
-    return comp;
-}
-
-static void order_int_cg(int n,gmx_cgsort_t *sort,
-                         int *a,int *buf)
-{
-    int i;
-    
-    /* Order the data */
-    for(i=0; i<n; i++)
-    {
-        buf[i] = a[sort[i].ind];
-    }
-    
-    /* Copy back to the original array */
-    for(i=0; i<n; i++)
-    {
-        a[i] = buf[i];
-    }
-}
-
-static void order_vec_cg(int n,gmx_cgsort_t *sort,
-                         rvec *v,rvec *buf)
-{
-    int i;
-    
-    /* Order the data */
-    for(i=0; i<n; i++)
-    {
-        copy_rvec(v[sort[i].ind],buf[i]);
-    }
-    
-    /* Copy back to the original array */
-    for(i=0; i<n; i++)
-    {
-        copy_rvec(buf[i],v[i]);
-    }
-}
-
-static void order_vec_atom(int ncg,int *cgindex,gmx_cgsort_t *sort,
-                           rvec *v,rvec *buf)
-{
-    int a,atot,cg,cg0,cg1,i;
-    
-    /* Order the data */
-    a = 0;
-    for(cg=0; cg<ncg; cg++)
-    {
-        cg0 = cgindex[sort[cg].ind];
-        cg1 = cgindex[sort[cg].ind+1];
-        for(i=cg0; i<cg1; i++)
-        {
-            copy_rvec(v[i],buf[a]);
-            a++;
-        }
-    }
-    atot = a;
-    
-    /* Copy back to the original array */
-    for(a=0; a<atot; a++)
-    {
-        copy_rvec(buf[a],v[a]);
-    }
-}
-
-static void ordered_sort(int nsort2,gmx_cgsort_t *sort2,
-                         int nsort_new,gmx_cgsort_t *sort_new,
-                         gmx_cgsort_t *sort1)
-{
-    int i1,i2,i_new;
-    
-    /* The new indices are not very ordered, so we qsort them */
-    qsort_threadsafe(sort_new,nsort_new,sizeof(sort_new[0]),comp_cgsort);
-    
-    /* sort2 is already ordered, so now we can merge the two arrays */
-    i1 = 0;
-    i2 = 0;
-    i_new = 0;
-    while(i2 < nsort2 || i_new < nsort_new)
-    {
-        if (i2 == nsort2)
-        {
-            sort1[i1++] = sort_new[i_new++];
-        }
-        else if (i_new == nsort_new)
-        {
-            sort1[i1++] = sort2[i2++];
-        }
-        else if (sort2[i2].nsc < sort_new[i_new].nsc ||
-                 (sort2[i2].nsc == sort_new[i_new].nsc &&
-                  sort2[i2].ind_gl < sort_new[i_new].ind_gl))
-        {
-            sort1[i1++] = sort2[i2++];
-        }
-        else
-        {
-            sort1[i1++] = sort_new[i_new++];
-        }
-    }
-}
-
-static void dd_sort_state(gmx_domdec_t *dd,int ePBC,
-                          rvec *cgcm,t_forcerec *fr,t_state *state,
-                          int ncg_home_old)
-{
-    gmx_domdec_sort_t *sort;
-    gmx_cgsort_t *cgsort,*sort_i;
-    int  ncg_new,nsort2,nsort_new,i,cell_index,*ibuf,cgsize;
-    rvec *vbuf;
-    
-    sort = dd->comm->sort;
-    
-    if (dd->ncg_home > sort->sort_nalloc)
-    {
-        sort->sort_nalloc = over_alloc_dd(dd->ncg_home);
-        srenew(sort->sort1,sort->sort_nalloc);
-        srenew(sort->sort2,sort->sort_nalloc);
-    }
-    
-    if (ncg_home_old >= 0)
-    {
-        /* The charge groups that remained in the same ns grid cell
-         * are completely ordered. So we can sort efficiently by sorting
-         * the charge groups that did move into the stationary list.
-         */
-        ncg_new = 0;
-        nsort2 = 0;
-        nsort_new = 0;
-        for(i=0; i<dd->ncg_home; i++)
-        {
-            /* Check if this cg did not move to another node */
-            cell_index = fr->ns.grid->cell_index[i];
-            if (cell_index !=  4*fr->ns.grid->ncells)
-            {
-                if (i >= ncg_home_old || cell_index != sort->sort1[i].nsc)
-                {
-                    /* This cg is new on this node or moved ns grid cell */
-                    if (nsort_new >= sort->sort_new_nalloc)
-                    {
-                        sort->sort_new_nalloc = over_alloc_dd(nsort_new+1);
-                        srenew(sort->sort_new,sort->sort_new_nalloc);
-                    }
-                    sort_i = &(sort->sort_new[nsort_new++]);
-                }
-                else
-                {
-                    /* This cg did not move */
-                    sort_i = &(sort->sort2[nsort2++]);
-                }
-                /* Sort on the ns grid cell indices
-                 * and the global topology index
-                 */
-                sort_i->nsc    = cell_index;
-                sort_i->ind_gl = dd->index_gl[i];
-                sort_i->ind    = i;
-                ncg_new++;
-            }
-        }
-        if (debug)
-        {
-            fprintf(debug,"ordered sort cgs: stationary %d moved %d\n",
-                    nsort2,nsort_new);
-        }
-        /* Sort efficiently */
-        ordered_sort(nsort2,sort->sort2,nsort_new,sort->sort_new,sort->sort1);
-    }
-    else
-    {
-        cgsort = sort->sort1;
-        ncg_new = 0;
-        for(i=0; i<dd->ncg_home; i++)
-        {
-            /* Sort on the ns grid cell indices
-             * and the global topology index
-             */
-            cgsort[i].nsc    = fr->ns.grid->cell_index[i];
-            cgsort[i].ind_gl = dd->index_gl[i];
-            cgsort[i].ind    = i;
-            if (cgsort[i].nsc != 4*fr->ns.grid->ncells)
-            {
-                ncg_new++;
-            }
-        }
-        if (debug)
-        {
-            fprintf(debug,"qsort cgs: %d new home %d\n",dd->ncg_home,ncg_new);
-        }
-        /* Determine the order of the charge groups using qsort */
-        qsort_threadsafe(cgsort,dd->ncg_home,sizeof(cgsort[0]),comp_cgsort);
-    }
-    cgsort = sort->sort1;
-    
-    /* We alloc with the old size, since cgindex is still old */
-    vec_rvec_check_alloc(&dd->comm->vbuf,dd->cgindex[dd->ncg_home]);
-    vbuf = dd->comm->vbuf.v;
-    
-    /* Remove the charge groups which are no longer at home here */
-    dd->ncg_home = ncg_new;
-    
-    /* Reorder the state */
-    for(i=0; i<estNR; i++)
-    {
-        if (EST_DISTR(i) && state->flags & (1<<i))
-        {
-            switch (i)
-            {
-            case estX:
-                order_vec_atom(dd->ncg_home,dd->cgindex,cgsort,state->x,vbuf);
-                break;
-            case estV:
-                order_vec_atom(dd->ncg_home,dd->cgindex,cgsort,state->v,vbuf);
-                break;
-            case estSDX:
-                order_vec_atom(dd->ncg_home,dd->cgindex,cgsort,state->sd_X,vbuf);
-                break;
-            case estCGP:
-                order_vec_atom(dd->ncg_home,dd->cgindex,cgsort,state->cg_p,vbuf);
-                break;
-            case estLD_RNG:
-            case estLD_RNGI:
-            case estDISRE_INITF:
-            case estDISRE_RM3TAV:
-            case estORIRE_INITF:
-            case estORIRE_DTAV:
-                /* No ordering required */
-                break;
-            default:
-                gmx_incons("Unknown state entry encountered in dd_sort_state");
-                break;
-            }
-        }
-    }
-    /* Reorder cgcm */
-    order_vec_cg(dd->ncg_home,cgsort,cgcm,vbuf);
-    
-    if (dd->ncg_home+1 > sort->ibuf_nalloc)
-    {
-        sort->ibuf_nalloc = over_alloc_dd(dd->ncg_home+1);
-        srenew(sort->ibuf,sort->ibuf_nalloc);
-    }
-    ibuf = sort->ibuf;
-    /* Reorder the global cg index */
-    order_int_cg(dd->ncg_home,cgsort,dd->index_gl,ibuf);
-    /* Reorder the cginfo */
-    order_int_cg(dd->ncg_home,cgsort,fr->cginfo,ibuf);
-    /* Rebuild the local cg index */
-    ibuf[0] = 0;
-    for(i=0; i<dd->ncg_home; i++)
-    {
-        cgsize = dd->cgindex[cgsort[i].ind+1] - dd->cgindex[cgsort[i].ind];
-        ibuf[i+1] = ibuf[i] + cgsize;
-    }
-    for(i=0; i<dd->ncg_home+1; i++)
-    {
-        dd->cgindex[i] = ibuf[i];
-    }
-    /* Set the home atom number */
-    dd->nat_home = dd->cgindex[dd->ncg_home];
-    
-    /* Copy the sorted ns cell indices back to the ns grid struct */
-    for(i=0; i<dd->ncg_home; i++)
-    {
-        fr->ns.grid->cell_index[i] = cgsort[i].nsc;
-    }
-    fr->ns.grid->nr = dd->ncg_home;
-}
-
-static void add_dd_statistics(gmx_domdec_t *dd)
-{
-    gmx_domdec_comm_t *comm;
-    int ddnat;
-    
-    comm = dd->comm;
-    
-    for(ddnat=ddnatZONE; ddnat<ddnatNR; ddnat++)
-    {
-        comm->sum_nat[ddnat-ddnatZONE] +=
-            comm->nat[ddnat] - comm->nat[ddnat-1];
-    }
-    comm->ndecomp++;
-}
-
-void reset_dd_statistics_counters(gmx_domdec_t *dd)
-{
-    gmx_domdec_comm_t *comm;
-    int ddnat;
-    
-    comm = dd->comm;
-
-    /* Reset all the statistics and counters for total run counting */
-    for(ddnat=ddnatZONE; ddnat<ddnatNR; ddnat++)
-    {
-        comm->sum_nat[ddnat-ddnatZONE] = 0;
-    }
-    comm->ndecomp = 0;
-    comm->nload = 0;
-    comm->load_step = 0;
-    comm->load_sum = 0;
-    comm->load_max = 0;
-    clear_ivec(comm->load_lim);
-    comm->load_mdf = 0;
-    comm->load_pme = 0;
-}
-
-void print_dd_statistics(t_commrec *cr,t_inputrec *ir,FILE *fplog)
-{
-    gmx_domdec_comm_t *comm;
-    int ddnat;
-    double av;
-   
-    comm = cr->dd->comm;
-    
-    gmx_sumd(ddnatNR-ddnatZONE,comm->sum_nat,cr);
-    
-    if (fplog == NULL)
-    {
-        return;
-    }
-    
-    fprintf(fplog,"\n    D O M A I N   D E C O M P O S I T I O N   S T A T I S T I C S\n\n");
-            
-    for(ddnat=ddnatZONE; ddnat<ddnatNR; ddnat++)
-    {
-        av = comm->sum_nat[ddnat-ddnatZONE]/comm->ndecomp;
-        switch(ddnat)
-        {
-        case ddnatZONE:
-            fprintf(fplog,
-                    " av. #atoms communicated per step for force:  %d x %.1f\n",
-                    2,av);
-            break;
-        case ddnatVSITE:
-            if (cr->dd->vsite_comm)
-            {
-                fprintf(fplog,
-                        " av. #atoms communicated per step for vsites: %d x %.1f\n",
-                        (EEL_PME(ir->coulombtype) || ir->coulombtype==eelEWALD) ? 3 : 2,
-                        av);
-            }
-            break;
-        case ddnatCON:
-            if (cr->dd->constraint_comm)
-            {
-                fprintf(fplog,
-                        " av. #atoms communicated per step for LINCS:  %d x %.1f\n",
-                        1 + ir->nLincsIter,av);
-            }
-            break;
-        default:
-            gmx_incons(" Unknown type for DD statistics");
-        }
-    }
-    fprintf(fplog,"\n");
-    
-    if (comm->bRecordLoad && EI_DYNAMICS(ir->eI))
-    {
-        print_dd_load_av(fplog,cr->dd);
-    }
-}
-
-void dd_partition_system(FILE            *fplog,
-                         gmx_large_int_t      step,
-                         t_commrec       *cr,
-                         gmx_bool            bMasterState,
-                         int             nstglobalcomm,
-                         t_state         *state_global,
-                         gmx_mtop_t      *top_global,
-                         t_inputrec      *ir,
-                         t_state         *state_local,
-                         rvec            **f,
-                         t_mdatoms       *mdatoms,
-                         gmx_localtop_t  *top_local,
-                         t_forcerec      *fr,
-                         gmx_vsite_t     *vsite,
-                         gmx_shellfc_t   shellfc,
-                         gmx_constr_t    constr,
-                         t_nrnb          *nrnb,
-                         gmx_wallcycle_t wcycle,
-                         gmx_bool            bVerbose)
-{
-    gmx_domdec_t *dd;
-    gmx_domdec_comm_t *comm;
-    gmx_ddbox_t ddbox={0};
-    t_block *cgs_gl;
-    gmx_large_int_t step_pcoupl;
-    rvec cell_ns_x0,cell_ns_x1;
-    int  i,j,n,cg0=0,ncg_home_old=-1,nat_f_novirsum;
-    gmx_bool bBoxChanged,bNStGlobalComm,bDoDLB,bCheckDLB,bTurnOnDLB,bLogLoad;
-    gmx_bool bRedist,bSortCG,bResortAll;
-    ivec ncells_old,np;
-    real grid_density;
-    char sbuf[22];
-       
-    dd = cr->dd;
-    comm = dd->comm;
-
-    bBoxChanged = (bMasterState || DEFORM(*ir));
-    if (ir->epc != epcNO)
-    {
-        /* With nstcalcenery > 1 pressure coupling happens.
-         * one step after calculating the energies.
-         * Box scaling happens at the end of the MD step,
-         * after the DD partitioning.
-         * We therefore have to do DLB in the first partitioning
-         * after an MD step where P-coupling occured.
-         * We need to determine the last step in which p-coupling occurred.
-         * MRS -- need to validate this for vv?
-         */
-        n = ir->nstcalcenergy;
-        if (n == 1)
-        {
-            step_pcoupl = step - 1;
-        }
-        else
-        {
-            step_pcoupl = ((step - 1)/n)*n + 1;
-        }
-        if (step_pcoupl >= comm->partition_step)
-        {
-            bBoxChanged = TRUE;
-        }
-    }
-
-    bNStGlobalComm = (step >= comm->partition_step + nstglobalcomm);
-
-    if (!comm->bDynLoadBal)
-    {
-        bDoDLB = FALSE;
-    }
-    else
-    {
-        /* Should we do dynamic load balacing this step?
-         * Since it requires (possibly expensive) global communication,
-         * we might want to do DLB less frequently.
-         */
-        if (bBoxChanged || ir->epc != epcNO)
-        {
-            bDoDLB = bBoxChanged;
-        }
-        else
-        {
-            bDoDLB = bNStGlobalComm;
-        }
-    }
-
-    /* Check if we have recorded loads on the nodes */
-    if (comm->bRecordLoad && dd_load_count(comm))
-    {
-        if (comm->eDLB == edlbAUTO && !comm->bDynLoadBal)
-        {
-            /* Check if we should use DLB at the second partitioning
-             * and every 100 partitionings,
-             * so the extra communication cost is negligible.
-             */
-            n = max(100,nstglobalcomm);
-            bCheckDLB = (comm->n_load_collect == 0 ||
-                         comm->n_load_have % n == n-1);
-        }
-        else
-        {
-            bCheckDLB = FALSE;
-        }
-        
-        /* Print load every nstlog, first and last step to the log file */
-        bLogLoad = ((ir->nstlog > 0 && step % ir->nstlog == 0) ||
-                    comm->n_load_collect == 0 ||
-                    (step + ir->nstlist > ir->init_step + ir->nsteps));
-
-        /* Avoid extra communication due to verbose screen output
-         * when nstglobalcomm is set.
-         */
-        if (bDoDLB || bLogLoad || bCheckDLB ||
-            (bVerbose && (ir->nstlist == 0 || nstglobalcomm <= ir->nstlist)))
-        {
-            get_load_distribution(dd,wcycle);
-            if (DDMASTER(dd))
-            {
-                if (bLogLoad)
-                {
-                    dd_print_load(fplog,dd,step-1);
-                }
-                if (bVerbose)
-                {
-                    dd_print_load_verbose(dd);
-                }
-            }
-            comm->n_load_collect++;
-
-            if (bCheckDLB) {
-                /* Since the timings are node dependent, the master decides */
-                if (DDMASTER(dd))
-                {
-                    bTurnOnDLB =
-                        (dd_force_imb_perf_loss(dd) >= DD_PERF_LOSS);
-                    if (debug)
-                    {
-                        fprintf(debug,"step %s, imb loss %f\n",
-                                gmx_step_str(step,sbuf),
-                                dd_force_imb_perf_loss(dd));
-                    }
-                }
-                dd_bcast(dd,sizeof(bTurnOnDLB),&bTurnOnDLB);
-                if (bTurnOnDLB)
-                {
-                    turn_on_dlb(fplog,cr,step);
-                    bDoDLB = TRUE;
-                }
-            }
-        }
-        comm->n_load_have++;
-    }
-
-    cgs_gl = &comm->cgs_gl;
-
-    bRedist = FALSE;
-    if (bMasterState)
-    {
-        /* Clear the old state */
-        clear_dd_indices(dd,0,0);
-
-        set_ddbox(dd,bMasterState,cr,ir,state_global->box,
-                  TRUE,cgs_gl,state_global->x,&ddbox);
-    
-        get_cg_distribution(fplog,step,dd,cgs_gl,
-                            state_global->box,&ddbox,state_global->x);
-        
-        dd_distribute_state(dd,cgs_gl,
-                            state_global,state_local,f);
-        
-        dd_make_local_cgs(dd,&top_local->cgs);
-        
-        if (dd->ncg_home > fr->cg_nalloc)
-        {
-            dd_realloc_fr_cg(fr,dd->ncg_home);
-        }
-        calc_cgcm(fplog,0,dd->ncg_home,
-                  &top_local->cgs,state_local->x,fr->cg_cm);
-        
-        inc_nrnb(nrnb,eNR_CGCM,dd->nat_home);
-        
-        dd_set_cginfo(dd->index_gl,0,dd->ncg_home,fr,comm->bLocalCG);
-
-        cg0 = 0;
-    }
-    else if (state_local->ddp_count != dd->ddp_count)
-    {
-        if (state_local->ddp_count > dd->ddp_count)
-        {
-            gmx_fatal(FARGS,"Internal inconsistency state_local->ddp_count (%d) > dd->ddp_count (%d)",state_local->ddp_count,dd->ddp_count);
-        }
-        
-        if (state_local->ddp_count_cg_gl != state_local->ddp_count)
-        {
-            gmx_fatal(FARGS,"Internal inconsistency state_local->ddp_count_cg_gl (%d) != state_local->ddp_count (%d)",state_local->ddp_count_cg_gl,state_local->ddp_count);
-        }
-        
-        /* Clear the old state */
-        clear_dd_indices(dd,0,0);
-        
-        /* Build the new indices */
-        rebuild_cgindex(dd,cgs_gl->index,state_local);
-        make_dd_indices(dd,cgs_gl->index,0);
-        
-        /* Redetermine the cg COMs */
-        calc_cgcm(fplog,0,dd->ncg_home,
-                  &top_local->cgs,state_local->x,fr->cg_cm);
-        
-        inc_nrnb(nrnb,eNR_CGCM,dd->nat_home);
-
-        dd_set_cginfo(dd->index_gl,0,dd->ncg_home,fr,comm->bLocalCG);
-
-        set_ddbox(dd,bMasterState,cr,ir,state_local->box,
-                  TRUE,&top_local->cgs,state_local->x,&ddbox);
-
-        bRedist = comm->bDynLoadBal;
-    }
-    else
-    {
-        /* We have the full state, only redistribute the cgs */
-
-        /* Clear the non-home indices */
-        clear_dd_indices(dd,dd->ncg_home,dd->nat_home);
-
-        /* Avoid global communication for dim's without pbc and -gcom */
-        if (!bNStGlobalComm)
-        {
-            copy_rvec(comm->box0    ,ddbox.box0    );
-            copy_rvec(comm->box_size,ddbox.box_size);
-        }
-        set_ddbox(dd,bMasterState,cr,ir,state_local->box,
-                  bNStGlobalComm,&top_local->cgs,state_local->x,&ddbox);
-
-        bBoxChanged = TRUE;
-        bRedist = TRUE;
-    }
-    /* For dim's without pbc and -gcom */
-    copy_rvec(ddbox.box0    ,comm->box0    );
-    copy_rvec(ddbox.box_size,comm->box_size);
-    
-    set_dd_cell_sizes(dd,&ddbox,dynamic_dd_box(&ddbox,ir),bMasterState,bDoDLB,
-                      step,wcycle);
-    
-    if (comm->nstDDDumpGrid > 0 && step % comm->nstDDDumpGrid == 0)
-    {
-        write_dd_grid_pdb("dd_grid",step,dd,state_local->box,&ddbox);
-    }
-    
-    /* Check if we should sort the charge groups */
-    if (comm->nstSortCG > 0)
-    {
-        bSortCG = (bMasterState ||
-                   (bRedist && (step % comm->nstSortCG == 0)));
-    }
-    else
-    {
-        bSortCG = FALSE;
-    }
-
-    ncg_home_old = dd->ncg_home;
-
-    if (bRedist)
-    {
-        cg0 = dd_redistribute_cg(fplog,step,dd,ddbox.tric_dir,
-                                 state_local,f,fr,mdatoms,
-                                 !bSortCG,nrnb);
-    }
-    
-    get_nsgrid_boundaries(fr->ns.grid,dd,
-                          state_local->box,&ddbox,&comm->cell_x0,&comm->cell_x1,
-                          dd->ncg_home,fr->cg_cm,
-                          cell_ns_x0,cell_ns_x1,&grid_density);
-
-    if (bBoxChanged)
-    {
-        comm_dd_ns_cell_sizes(dd,&ddbox,cell_ns_x0,cell_ns_x1,step);
-    }
-
-    copy_ivec(fr->ns.grid->n,ncells_old);
-    grid_first(fplog,fr->ns.grid,dd,&ddbox,fr->ePBC,
-               state_local->box,cell_ns_x0,cell_ns_x1,
-               fr->rlistlong,grid_density);
-    /* We need to store tric_dir for dd_get_ns_ranges called from ns.c */
-    copy_ivec(ddbox.tric_dir,comm->tric_dir);
-
-    if (bSortCG)
-    {
-        /* Sort the state on charge group position.
-         * This enables exact restarts from this step.
-         * It also improves performance by about 15% with larger numbers
-         * of atoms per node.
-         */
-        
-        /* Fill the ns grid with the home cell,
-         * so we can sort with the indices.
-         */
-        set_zones_ncg_home(dd);
-        fill_grid(fplog,&comm->zones,fr->ns.grid,dd->ncg_home,
-                  0,dd->ncg_home,fr->cg_cm);
-        
-        /* Check if we can user the old order and ns grid cell indices
-         * of the charge groups to sort the charge groups efficiently.
-         */
-        bResortAll = (bMasterState ||
-                      fr->ns.grid->n[XX] != ncells_old[XX] ||
-                      fr->ns.grid->n[YY] != ncells_old[YY] ||
-                      fr->ns.grid->n[ZZ] != ncells_old[ZZ]);
-
-        if (debug)
-        {
-            fprintf(debug,"Step %s, sorting the %d home charge groups\n",
-                    gmx_step_str(step,sbuf),dd->ncg_home);
-        }
-        dd_sort_state(dd,ir->ePBC,fr->cg_cm,fr,state_local,
-                      bResortAll ? -1 : ncg_home_old);
-        /* Rebuild all the indices */
-        cg0 = 0;
-        ga2la_clear(dd->ga2la);
-    }
-    
-    /* Setup up the communication and communicate the coordinates */
-    setup_dd_communication(dd,state_local->box,&ddbox,fr);
-    
-    /* Set the indices */
-    make_dd_indices(dd,cgs_gl->index,cg0);
-
-    /* Set the charge group boundaries for neighbor searching */
-    set_cg_boundaries(&comm->zones);
-    
-    /*
-    write_dd_pdb("dd_home",step,"dump",top_global,cr,
-                 -1,state_local->x,state_local->box);
-    */
-    
-    /* Extract a local topology from the global topology */
-    for(i=0; i<dd->ndim; i++)
-    {
-        np[dd->dim[i]] = comm->cd[i].np;
-    }
-    dd_make_local_top(fplog,dd,&comm->zones,dd->npbcdim,state_local->box,
-                      comm->cellsize_min,np,
-                      fr,vsite,top_global,top_local);
-    
-    /* Set up the special atom communication */
-    n = comm->nat[ddnatZONE];
-    for(i=ddnatZONE+1; i<ddnatNR; i++)
-    {
-        switch(i)
-        {
-        case ddnatVSITE:
-            if (vsite && vsite->n_intercg_vsite)
-            {
-                n = dd_make_local_vsites(dd,n,top_local->idef.il);
-            }
-            break;
-        case ddnatCON:
-            if (dd->bInterCGcons)
-            {
-                /* Only for inter-cg constraints we need special code */
-                n = dd_make_local_constraints(dd,n,top_global,
-                                              constr,ir->nProjOrder,
-                                              &top_local->idef.il[F_CONSTR]);
-            }
-            break;
-        default:
-            gmx_incons("Unknown special atom type setup");
-        }
-        comm->nat[i] = n;
-    }
-    
-    /* Make space for the extra coordinates for virtual site
-     * or constraint communication.
-     */
-    state_local->natoms = comm->nat[ddnatNR-1];
-    if (state_local->natoms > state_local->nalloc)
-    {
-        dd_realloc_state(state_local,f,state_local->natoms);
-    }
-
-    if (fr->bF_NoVirSum)
-    {
-        if (vsite && vsite->n_intercg_vsite)
-        {
-            nat_f_novirsum = comm->nat[ddnatVSITE];
-        }
-        else
-        {
-            if (EEL_FULL(ir->coulombtype) && dd->n_intercg_excl > 0)
-            {
-                nat_f_novirsum = dd->nat_tot;
-            }
-            else
-            {
-                nat_f_novirsum = dd->nat_home;
-            }
-        }
-    }
-    else
-    {
-        nat_f_novirsum = 0;
-    }
-
-    /* Set the number of atoms required for the force calculation.
-     * Forces need to be constrained when using a twin-range setup
-     * or with energy minimization. For simple simulations we could
-     * avoid some allocation, zeroing and copying, but this is
-     * probably not worth the complications ande checking.
-     */
-    forcerec_set_ranges(fr,dd->ncg_home,dd->ncg_tot,
-                        dd->nat_tot,comm->nat[ddnatCON],nat_f_novirsum);
-
-    /* We make the all mdatoms up to nat_tot_con.
-     * We could save some work by only setting invmass
-     * between nat_tot and nat_tot_con.
-     */
-    /* This call also sets the new number of home particles to dd->nat_home */
-    atoms2md(top_global,ir,
-             comm->nat[ddnatCON],dd->gatindex,0,dd->nat_home,mdatoms);
-
-    /* Now we have the charges we can sort the FE interactions */
-    dd_sort_local_top(dd,mdatoms,top_local);
-
-    if (shellfc)
-    {
-        /* Make the local shell stuff, currently no communication is done */
-        make_local_shells(cr,mdatoms,shellfc);
-    }
-    
-       if (ir->implicit_solvent)
-    {
-        make_local_gb(cr,fr->born,ir->gb_algorithm);
-    }
-       
-    if (!(cr->duty & DUTY_PME))
-    {
-        /* Send the charges to our PME only node */
-        gmx_pme_send_q(cr,mdatoms->nChargePerturbed,
-                       mdatoms->chargeA,mdatoms->chargeB,
-                       dd_pme_maxshift_x(dd),dd_pme_maxshift_y(dd));
-    }
-    
-    if (constr)
-    {
-        set_constraints(constr,top_local,ir,mdatoms,cr);
-    }
-    
-    if (ir->ePull != epullNO)
-    {
-        /* Update the local pull groups */
-        dd_make_local_pull_groups(dd,ir->pull,mdatoms);
-    }
-
-    add_dd_statistics(dd);
-    
-    /* Make sure we only count the cycles for this DD partitioning */
-    clear_dd_cycle_counts(dd);
-    
-    /* Because the order of the atoms might have changed since
-     * the last vsite construction, we need to communicate the constructing
-     * atom coordinates again (for spreading the forces this MD step).
-     */
-    dd_move_x_vsites(dd,state_local->box,state_local->x);
-    
-    if (comm->nstDDDump > 0 && step % comm->nstDDDump == 0)
-    {
-        dd_move_x(dd,state_local->box,state_local->x);
-        write_dd_pdb("dd_dump",step,"dump",top_global,cr,
-                     -1,state_local->x,state_local->box);
-    }
-
-    /* Store the partitioning step */
-    comm->partition_step = step;
-    
-    /* Increase the DD partitioning counter */
-    dd->ddp_count++;
-    /* The state currently matches this DD partitioning count, store it */
-    state_local->ddp_count = dd->ddp_count;
-    if (bMasterState)
-    {
-        /* The DD master node knows the complete cg distribution,
-         * store the count so we can possibly skip the cg info communication.
-         */
-        comm->master_cg_ddp_count = (bSortCG ? 0 : dd->ddp_count);
-    }
-
-    if (comm->DD_debug > 0)
-    {
-        /* Set the env var GMX_DD_DEBUG if you suspect corrupted indices */
-        check_index_consistency(dd,top_global->natoms,ncg_mtop(top_global),
-                                "after partitioning");
-    }
-}
diff --git a/src/mdlib/gmx_wallcycle.c b/src/mdlib/gmx_wallcycle.c
deleted file mode 100644 (file)
index 8224baf..0000000
+++ /dev/null
@@ -1,474 +0,0 @@
-/*  -*- mode: c; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; c-file-style: "stroustrup"; -*-
- *
- * 
- *                This source code is part of
- * 
- *                 G   R   O   M   A   C   S
- * 
- *          GROningen MAchine for Chemical Simulations
- * 
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
- * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
- * Copyright (c) 2001-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
- */
-
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <string.h>
-#include "gmx_wallcycle.h"
-#include "gmx_cyclecounter.h"
-#include "smalloc.h"
-#include "gmx_fatal.h"
-
-#ifdef GMX_LIB_MPI
-#include <mpi.h>
-#endif
-#ifdef GMX_THREADS
-#include "tmpi.h"
-#endif
-
-typedef struct
-{
-    int          n;
-    gmx_cycles_t c;
-    gmx_cycles_t start;
-    gmx_cycles_t last;
-} wallcc_t;
-
-typedef struct gmx_wallcycle
-{
-    wallcc_t     *wcc;
-    /* variables for testing/debugging */
-    gmx_bool         wc_barrier;
-    wallcc_t     *wcc_all;
-    int          wc_depth;
-    int          ewc_prev;
-    gmx_cycles_t cycle_prev;
-    gmx_large_int_t   reset_counters;
-#ifdef GMX_MPI
-    MPI_Comm     mpi_comm_mygroup;
-#endif
-} gmx_wallcycle_t_t;
-
-/* Each name should not exceed 19 characters */
-static const char *wcn[ewcNR] =
-{ "Run", "Step", "PP during PME", "Domain decomp.", "DD comm. load", "DD comm. bounds", "Vsite constr.", "Send X to PME", "Comm. coord.", "Neighbor search", "Born radii", "Force", "Wait + Comm. F", "PME mesh", "PME redist. X/F", "PME spread/gather", "PME 3D-FFT", "PME solve", "Wait + Comm. X/F", "Wait + Recv. PME F", "Vsite spread", "Write traj.", "Update", "Constraints", "Comm. energies", "Test" };
-
-gmx_bool wallcycle_have_counter(void)
-{
-  return gmx_cycles_have_counter();
-}
-
-gmx_wallcycle_t wallcycle_init(FILE *fplog,int resetstep,t_commrec *cr)
-{
-    gmx_wallcycle_t wc;
-    
-    
-    if (!wallcycle_have_counter())
-    {
-        return NULL;
-    }
-
-    snew(wc,1);
-
-    wc->wc_barrier = FALSE;
-    wc->wcc_all    = NULL;
-    wc->wc_depth   = 0;
-    wc->ewc_prev   = -1;
-    wc->reset_counters = resetstep;
-
-#ifdef GMX_MPI
-    if (PAR(cr) && getenv("GMX_CYCLE_BARRIER") != NULL)
-    {
-        if (fplog) 
-        {
-            fprintf(fplog,"\nWill call MPI_Barrier before each cycle start/stop call\n\n");
-        }
-        wc->wc_barrier = TRUE;
-        wc->mpi_comm_mygroup = cr->mpi_comm_mygroup;
-    }
-#endif
-
-    snew(wc->wcc,ewcNR);
-    if (getenv("GMX_CYCLE_ALL") != NULL)
-    {
-/*#ifndef GMX_THREADS*/
-        if (fplog) 
-        {
-            fprintf(fplog,"\nWill time all the code during the run\n\n");
-        }
-        snew(wc->wcc_all,ewcNR*ewcNR);
-/*#else*/
-        gmx_fatal(FARGS, "GMX_CYCLE_ALL is incompatible with threaded code");
-/*#endif*/
-    }
-    
-    return wc;
-}
-
-void wallcycle_destroy(gmx_wallcycle_t wc)
-{
-    if (wc == NULL)
-    {
-        return;
-    }
-    
-    if (wc->wcc != NULL)
-    {
-        sfree(wc->wcc);
-    }
-    if (wc->wcc_all != NULL)
-    {
-        sfree(wc->wcc_all);
-    }
-    sfree(wc);
-}
-
-static void wallcycle_all_start(gmx_wallcycle_t wc,int ewc,gmx_cycles_t cycle)
-{
-    wc->ewc_prev = ewc;
-    wc->cycle_prev = cycle;
-}
-
-static void wallcycle_all_stop(gmx_wallcycle_t wc,int ewc,gmx_cycles_t cycle)
-{
-    wc->wcc_all[wc->ewc_prev*ewcNR+ewc].n += 1;
-    wc->wcc_all[wc->ewc_prev*ewcNR+ewc].c += cycle - wc->cycle_prev;
-}
-
-void wallcycle_start(gmx_wallcycle_t wc, int ewc)
-{
-    gmx_cycles_t cycle;
-
-    if (wc == NULL)
-    {
-        return;
-    }
-
-#ifdef GMX_MPI
-    if (wc->wc_barrier)
-    {
-        MPI_Barrier(wc->mpi_comm_mygroup);
-    }
-#endif
-
-    cycle = gmx_cycles_read();
-    wc->wcc[ewc].start = cycle;
-    if (wc->wcc_all != NULL)
-    {
-        wc->wc_depth++;
-        if (ewc == ewcRUN)
-        {
-            wallcycle_all_start(wc,ewc,cycle);
-        }
-        else if (wc->wc_depth == 3)
-        {
-            wallcycle_all_stop(wc,ewc,cycle);
-        }
-    }
-}
-
-double wallcycle_stop(gmx_wallcycle_t wc, int ewc)
-{
-    gmx_cycles_t cycle,last;
-    
-    if (wc == NULL)
-    {
-        return 0;
-    }
-    
-#ifdef GMX_MPI
-    if (wc->wc_barrier)
-    {
-        MPI_Barrier(wc->mpi_comm_mygroup);
-    }
-#endif
-    
-    cycle = gmx_cycles_read();
-    last = cycle - wc->wcc[ewc].start;
-    wc->wcc[ewc].c += last;
-    wc->wcc[ewc].n++;
-    if (wc->wcc_all)
-    {
-        wc->wc_depth--;
-        if (ewc == ewcRUN)
-        {
-            wallcycle_all_stop(wc,ewc,cycle);
-        }
-        else if (wc->wc_depth == 2)
-        {
-            wallcycle_all_start(wc,ewc,cycle);
-        }
-    }
-
-    return last;
-}
-
-void wallcycle_reset_all(gmx_wallcycle_t wc)
-{
-    int i;
-
-    if (wc == NULL)
-    {
-        return;
-    }
-
-    for(i=0; i<ewcNR; i++)
-    {
-        wc->wcc[i].n = 0;
-        wc->wcc[i].c = 0;
-        wc->wcc[i].start = 0;
-        wc->wcc[i].last = 0;
-    }
-}
-
-void wallcycle_sum(t_commrec *cr, gmx_wallcycle_t wc,double cycles[])
-{
-    wallcc_t *wcc;
-    double cycles_n[ewcNR],buf[ewcNR],*cyc_all,*buf_all;
-    int    i;
-
-    if (wc == NULL)
-    {
-        return;
-    }
-
-    wcc = wc->wcc;
-
-    if (wcc[ewcDDCOMMLOAD].n > 0)
-    {
-        wcc[ewcDOMDEC].c -= wcc[ewcDDCOMMLOAD].c;
-    }
-    if (wcc[ewcDDCOMMBOUND].n > 0)
-    {
-        wcc[ewcDOMDEC].c -= wcc[ewcDDCOMMBOUND].c;
-    }
-    if (cr->npmenodes == 0)
-    {
-        /* All nodes do PME (or no PME at all) */
-        if (wcc[ewcPMEMESH].n > 0)
-        {
-            wcc[ewcFORCE].c -= wcc[ewcPMEMESH].c;
-        }
-    }
-    else
-    {
-        /* The are PME-only nodes */
-        if (wcc[ewcPMEMESH].n > 0)
-        {
-            /* This must be a PME only node, calculate the Wait + Comm. time */
-            wcc[ewcPMEWAITCOMM].c = wcc[ewcRUN].c - wcc[ewcPMEMESH].c;
-        }
-    }
-    
-    /* Store the cycles in a double buffer for summing */
-    for(i=0; i<ewcNR; i++)
-    {
-        cycles_n[i] = (double)wcc[i].n;
-        cycles[i]   = (double)wcc[i].c;
-    }
-    
-#ifdef GMX_MPI
-    if (cr->nnodes > 1)
-    {
-        MPI_Allreduce(cycles_n,buf,ewcNR,MPI_DOUBLE,MPI_MAX,
-                      cr->mpi_comm_mysim);
-        for(i=0; i<ewcNR; i++)
-        {
-            wcc[i].n = (int)(buf[i] + 0.5);
-        }
-        MPI_Allreduce(cycles,buf,ewcNR,MPI_DOUBLE,MPI_SUM,
-                      cr->mpi_comm_mysim);
-        for(i=0; i<ewcNR; i++)
-        {
-            cycles[i] = buf[i];
-        }
-
-        if (wc->wcc_all != NULL)
-        {
-            snew(cyc_all,ewcNR*ewcNR);
-            snew(buf_all,ewcNR*ewcNR);
-            for(i=0; i<ewcNR*ewcNR; i++)
-            {
-                cyc_all[i] = wc->wcc_all[i].c;
-            }
-            MPI_Allreduce(cyc_all,buf_all,ewcNR*ewcNR,MPI_DOUBLE,MPI_SUM,
-                          cr->mpi_comm_mysim);
-            for(i=0; i<ewcNR*ewcNR; i++)
-            {
-                wc->wcc_all[i].c = buf_all[i];
-            }
-            sfree(buf_all);
-            sfree(cyc_all);
-        }
-    }
-#endif
-}
-
-static void print_cycles(FILE *fplog, double c2t, const char *name, int nnodes,
-                         int n, double c, double tot)
-{
-    char num[11];
-  
-    if (c > 0)
-    {
-        if (n > 0)
-        {
-            sprintf(num,"%10d",n);
-        }
-        else
-        {
-            sprintf(num,"          ");
-        }
-        fprintf(fplog," %-19s %4d %10s %12.3f %10.1f   %5.1f\n",
-                name,nnodes,num,c*1e-9,c*c2t,100*c/tot);
-    }
-}
-
-static gmx_bool subdivision(int ewc)
-{
-    return (ewc >= ewcPME_REDISTXF && ewc <= ewcPME_SOLVE);
-}
-
-void wallcycle_print(FILE *fplog, int nnodes, int npme, double realtime,
-                     gmx_wallcycle_t wc, double cycles[])
-{
-    double c2t,tot,sum;
-    int    i,j,npp;
-    char   buf[STRLEN];
-    const char *myline = "-----------------------------------------------------------------------";
-    
-    if (wc == NULL)
-    {
-        return;
-    }
-
-    if (npme > 0)
-    {
-        npp = nnodes - npme;
-    }
-    else
-    {
-        npp  = nnodes;
-        npme = nnodes;
-    }
-    tot = cycles[ewcRUN];
-    /* Conversion factor from cycles to seconds */
-    if (tot > 0)
-    {
-      c2t = nnodes*realtime/tot;
-    }
-    else
-    {
-      c2t = 0;
-    }
-
-    fprintf(fplog,"\n     R E A L   C Y C L E   A N D   T I M E   A C C O U N T I N G\n\n");
-
-    fprintf(fplog," Computing:         Nodes     Number     G-Cycles    Seconds     %c\n",'%');
-    fprintf(fplog,"%s\n",myline);
-    sum = 0;
-    for(i=ewcPPDURINGPME+1; i<ewcNR; i++)
-    {
-        if (!subdivision(i))
-        {
-            print_cycles(fplog,c2t,wcn[i],
-                         (i==ewcPMEMESH || i==ewcPMEWAITCOMM) ? npme : npp,
-                         wc->wcc[i].n,cycles[i],tot);
-            sum += cycles[i];
-        }
-    }
-    if (wc->wcc_all != NULL)
-    {
-        for(i=0; i<ewcNR; i++)
-        {
-            for(j=0; j<ewcNR; j++)
-            {
-                sprintf(buf,"%-9s",wcn[i]);
-                buf[9] = ' ';
-                sprintf(buf+10,"%-9s",wcn[j]);
-                buf[19] = '\0';
-                print_cycles(fplog,c2t,buf,
-                             (i==ewcPMEMESH || i==ewcPMEWAITCOMM) ? npme : npp,
-                             wc->wcc_all[i*ewcNR+j].n,
-                             wc->wcc_all[i*ewcNR+j].c,
-                             tot);
-            }
-        }
-    }
-    print_cycles(fplog,c2t,"Rest",npp,0,tot-sum,tot);
-    fprintf(fplog,"%s\n",myline);
-    print_cycles(fplog,c2t,"Total",nnodes,0,tot,tot);
-    fprintf(fplog,"%s\n",myline);
-    
-    if (wc->wcc[ewcPMEMESH].n > 0)
-    {
-        fprintf(fplog,"%s\n",myline);
-        for(i=ewcPPDURINGPME+1; i<ewcNR; i++)
-        {
-            if (subdivision(i))
-            {
-                print_cycles(fplog,c2t,wcn[i],
-                             (i>=ewcPMEMESH || i<=ewcPME_SOLVE) ? npme : npp,
-                             wc->wcc[i].n,cycles[i],tot);
-            }
-        }
-        fprintf(fplog,"%s\n",myline);
-    }
-
-    if (cycles[ewcMoveE] > tot*0.05)
-    {
-        sprintf(buf,
-                "NOTE: %d %% of the run time was spent communicating energies,\n"
-                "      you might want to use the -gcom option of mdrun\n",
-                (int)(100*cycles[ewcMoveE]/tot+0.5));
-        if (fplog)
-        {
-            fprintf(fplog,"\n%s\n",buf);
-        }
-        /* Only the sim master calls this function, so always print to stderr */
-        fprintf(stderr,"\n%s\n",buf);
-    }
-}
-
-extern gmx_large_int_t wcycle_get_reset_counters(gmx_wallcycle_t wc)
-{
-    if (wc == NULL)
-    {
-        return -1;
-    }
-    
-    return wc->reset_counters;
-}
-
-extern void wcycle_set_reset_counters(gmx_wallcycle_t wc, gmx_large_int_t reset_counters)
-{
-    if (wc == NULL)
-        return;
-
-    wc->reset_counters = reset_counters;
-}
diff --git a/src/mdlib/libmd.pc.cmakein b/src/mdlib/libmd.pc.cmakein
deleted file mode 100644 (file)
index a89035f..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-libdir=@LIB_INSTALL_DIR@
-includedir=@INCL_INSTALL_DIR@
-
-Name: libmd
-Description: Gromacs md lib
-URL: http://www.gromacs.org
-Version: @PROJECT_VERSION@
-Requires: libgmx@LIBSUFFIX@ @PKG_FFT@ @PKG_XML@
-Libs.private: -lm @CMAKE_THREAD_LIBS_INIT@
-Libs: -L${libdir} -lmd@LIBSUFFIX@ @PKG_FFT_LIBS@
-Cflags: -I${includedir} @PKG_CFLAGS@
-
diff --git a/src/mdlib/libmd.pc.in b/src/mdlib/libmd.pc.in
deleted file mode 100644 (file)
index 64eced3..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-prefix=@prefix@
-exec_prefix=@exec_prefix@
-libdir=@libdir@
-includedir=@includedir@
-
-Name: libmd
-Description: Gromacs md lib
-URL: http://www.gromacs.org
-Version: @VERSION@
-Requires: libgmx@LIBSUFFIX@ @PKG_FFT@ @PKG_XML@
-Libs: -L${libdir} -lmd@LIBSUFFIX@ @PKG_FFT_LIBS@ @PTHREAD_CFLAGS@ @PTHREAD_LIBS@ -lm
-Cflags: -I${includedir} @PTHREAD_CFLAGS@ @PKG_CFLAGS@
-
diff --git a/src/mdlib/mdebin.c b/src/mdlib/mdebin.c
deleted file mode 100644 (file)
index 7db45ab..0000000
+++ /dev/null
@@ -1,1254 +0,0 @@
-/* -*- mode: c; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; c-file-style: "stroustrup"; -*-
- *
- * 
- *                This source code is part of
- * 
- *                 G   R   O   M   A   C   S
- * 
- *          GROningen MAchine for Chemical Simulations
- * 
- *                        VERSION 3.2.0
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
- * 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.
-
- * 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:
- * GROwing Monsters And Cloning Shrimps
- */
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <string.h>
-#include <float.h>
-#include "typedefs.h"
-#include "string2.h"
-#include "mdebin.h"
-#include "smalloc.h"
-#include "physics.h"
-#include "enxio.h"
-#include "vec.h"
-#include "disre.h"
-#include "main.h"
-#include "network.h"
-#include "names.h"
-#include "orires.h"
-#include "constr.h"
-#include "mtop_util.h"
-#include "xvgr.h"
-#include "gmxfio.h"
-
-#include "mdebin_bar.h"
-
-
-static const char *conrmsd_nm[] = { "Constr. rmsd", "Constr.2 rmsd" };
-
-static const char *boxs_nm[] = { "Box-X", "Box-Y", "Box-Z" };
-
-static const char *tricl_boxs_nm[] = { 
-    "Box-XX", "Box-YY", "Box-ZZ",
-    "Box-YX", "Box-ZX", "Box-ZY" 
-};
-
-static const char *vol_nm[] = { "Volume" };
-
-static const char *dens_nm[] = {"Density" };
-
-static const char *pv_nm[] = {"pV" };
-
-static const char *enthalpy_nm[] = {"Enthalpy" };
-
-static const char *boxvel_nm[] = {
-    "Box-Vel-XX", "Box-Vel-YY", "Box-Vel-ZZ",
-    "Box-Vel-YX", "Box-Vel-ZX", "Box-Vel-ZY"
-};
-
-#define NBOXS asize(boxs_nm)
-#define NTRICLBOXS asize(tricl_boxs_nm)
-
-static gmx_bool bTricl,bDynBox;
-static int  f_nre=0,epc,etc,nCrmsd;
-
-
-
-
-
-t_mdebin *init_mdebin(ener_file_t fp_ene,
-                      const gmx_mtop_t *mtop,
-                      const t_inputrec *ir,
-                      FILE *fp_dhdl)
-{
-    const char *ener_nm[F_NRE];
-    static const char *vir_nm[] = {
-        "Vir-XX", "Vir-XY", "Vir-XZ",
-        "Vir-YX", "Vir-YY", "Vir-YZ",
-        "Vir-ZX", "Vir-ZY", "Vir-ZZ"
-    };
-    static const char *sv_nm[] = {
-        "ShakeVir-XX", "ShakeVir-XY", "ShakeVir-XZ",
-        "ShakeVir-YX", "ShakeVir-YY", "ShakeVir-YZ",
-        "ShakeVir-ZX", "ShakeVir-ZY", "ShakeVir-ZZ"
-    };
-    static const char *fv_nm[] = {
-        "ForceVir-XX", "ForceVir-XY", "ForceVir-XZ",
-        "ForceVir-YX", "ForceVir-YY", "ForceVir-YZ",
-        "ForceVir-ZX", "ForceVir-ZY", "ForceVir-ZZ"
-    };
-    static const char *pres_nm[] = {
-        "Pres-XX","Pres-XY","Pres-XZ",
-        "Pres-YX","Pres-YY","Pres-YZ",
-        "Pres-ZX","Pres-ZY","Pres-ZZ"
-    };
-    static const char *surft_nm[] = {
-        "#Surf*SurfTen"
-    };
-    static const char *mu_nm[] = {
-        "Mu-X", "Mu-Y", "Mu-Z"
-    };
-    static const char *vcos_nm[] = {
-        "2CosZ*Vel-X"
-    };
-    static const char *visc_nm[] = {
-        "1/Viscosity"
-    };
-    static const char *baro_nm[] = {
-        "Barostat"
-    };
-
-    char     **grpnms;
-    const gmx_groups_t *groups;
-    char     **gnm;
-    char     buf[256];
-    const char     *bufi;
-    t_mdebin *md;
-    int      i,j,ni,nj,n,nh,k,kk,ncon,nset;
-    gmx_bool     bBHAM,bNoseHoover,b14;
-
-    snew(md,1);
-
-    if (EI_DYNAMICS(ir->eI))
-    {
-        md->delta_t = ir->delta_t;
-    }
-    else
-    {
-        md->delta_t = 0;
-    }
-
-    groups = &mtop->groups;
-
-    bBHAM = (mtop->ffparams.functype[0] == F_BHAM);
-    b14   = (gmx_mtop_ftype_count(mtop,F_LJ14) > 0 ||
-             gmx_mtop_ftype_count(mtop,F_LJC14_Q) > 0);
-
-    ncon = gmx_mtop_ftype_count(mtop,F_CONSTR);
-    nset = gmx_mtop_ftype_count(mtop,F_SETTLE);
-    md->bConstr    = (ncon > 0 || nset > 0);
-    md->bConstrVir = FALSE;
-    if (md->bConstr) {
-        if (ncon > 0 && ir->eConstrAlg == econtLINCS) {
-            if (ir->eI == eiSD2)
-                md->nCrmsd = 2;
-            else
-                md->nCrmsd = 1;
-        }
-        md->bConstrVir = (getenv("GMX_CONSTRAINTVIR") != NULL);
-    } else {
-        md->nCrmsd = 0;
-    }
-
-    /* Energy monitoring */
-    for(i=0;i<egNR;i++)
-    {
-        md->bEInd[i]=FALSE;
-    }
-
-#ifndef GMX_OPENMM
-    for(i=0; i<F_NRE; i++)
-    {
-        md->bEner[i] = FALSE;
-        if (i == F_LJ)
-            md->bEner[i] = !bBHAM;
-        else if (i == F_BHAM)
-            md->bEner[i] = bBHAM;
-        else if (i == F_EQM)
-            md->bEner[i] = ir->bQMMM;
-        else if (i == F_COUL_LR)
-            md->bEner[i] = (ir->rcoulomb > ir->rlist);
-        else if (i == F_LJ_LR)
-            md->bEner[i] = (!bBHAM && ir->rvdw > ir->rlist);
-        else if (i == F_BHAM_LR)
-            md->bEner[i] = (bBHAM && ir->rvdw > ir->rlist);
-        else if (i == F_RF_EXCL)
-            md->bEner[i] = (EEL_RF(ir->coulombtype) && ir->coulombtype != eelRF_NEC);
-        else if (i == F_COUL_RECIP)
-            md->bEner[i] = EEL_FULL(ir->coulombtype);
-        else if (i == F_LJ14)
-            md->bEner[i] = b14;
-        else if (i == F_COUL14)
-            md->bEner[i] = b14;
-        else if (i == F_LJC14_Q || i == F_LJC_PAIRS_NB)
-            md->bEner[i] = FALSE;
-        else if ((i == F_DVDL) || (i == F_DKDL))
-            md->bEner[i] = (ir->efep != efepNO);
-        else if (i == F_DHDL_CON)
-            md->bEner[i] = (ir->efep != efepNO && md->bConstr);
-        else if ((interaction_function[i].flags & IF_VSITE) ||
-                 (i == F_CONSTR) || (i == F_CONSTRNC) || (i == F_SETTLE))
-            md->bEner[i] = FALSE;
-        else if ((i == F_COUL_SR) || (i == F_EPOT) || (i == F_PRES)  || (i==F_EQM))
-            md->bEner[i] = TRUE;
-        else if ((i == F_GBPOL) && ir->implicit_solvent==eisGBSA)
-            md->bEner[i] = TRUE;
-        else if ((i == F_NPSOLVATION) && ir->implicit_solvent==eisGBSA && (ir->sa_algorithm != esaNO))
-            md->bEner[i] = TRUE;
-        else if ((i == F_GB12) || (i == F_GB13) || (i == F_GB14))
-            md->bEner[i] = FALSE;
-        else if ((i == F_ETOT) || (i == F_EKIN) || (i == F_TEMP))
-            md->bEner[i] = EI_DYNAMICS(ir->eI);
-        else if (i==F_VTEMP) 
-            md->bEner[i] =  (EI_DYNAMICS(ir->eI) && getenv("GMX_VIRIAL_TEMPERATURE"));
-        else if (i == F_DISPCORR || i == F_PDISPCORR)
-            md->bEner[i] = (ir->eDispCorr != edispcNO);
-        else if (i == F_DISRESVIOL)
-            md->bEner[i] = (gmx_mtop_ftype_count(mtop,F_DISRES) > 0);
-        else if (i == F_ORIRESDEV)
-            md->bEner[i] = (gmx_mtop_ftype_count(mtop,F_ORIRES) > 0);
-        else if (i == F_CONNBONDS)
-            md->bEner[i] = FALSE;
-        else if (i == F_COM_PULL)
-            md->bEner[i] = (ir->ePull == epullUMBRELLA || ir->ePull == epullCONST_F);
-        else if (i == F_ECONSERVED)
-            md->bEner[i] = ((ir->etc == etcNOSEHOOVER || ir->etc == etcVRESCALE) &&
-                            (ir->epc == epcNO || ir->epc==epcMTTK));
-        else
-            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
-
-    md->f_nre=0;
-    for(i=0; i<F_NRE; i++)
-    {
-        if (md->bEner[i])
-        {
-            /* FIXME: The constness should not be cast away */
-            /*ener_nm[f_nre]=(char *)interaction_function[i].longname;*/
-            ener_nm[md->f_nre]=interaction_function[i].longname;
-            md->f_nre++;
-        }
-    }
-
-    md->epc = ir->epc;
-    for (i=0;i<DIM;i++) 
-    {
-        for (j=0;j<DIM;j++) 
-        {
-            md->ref_p[i][j] = ir->ref_p[i][j];
-        }
-    }
-    md->bTricl = TRICLINIC(ir->compress) || TRICLINIC(ir->deform);
-    md->bDynBox = DYNAMIC_BOX(*ir);
-    md->etc = ir->etc;
-    md->bNHC_trotter = IR_NVT_TROTTER(ir);
-    md->bMTTK = IR_NPT_TROTTER(ir);
-
-    md->ebin  = mk_ebin();
-    /* Pass NULL for unit to let get_ebin_space determine the units
-     * for interaction_function[i].longname
-     */
-    md->ie    = get_ebin_space(md->ebin,md->f_nre,ener_nm,NULL);
-    if (md->nCrmsd)
-    {
-        /* This should be called directly after the call for md->ie,
-         * such that md->iconrmsd follows directly in the list.
-         */
-        md->iconrmsd = get_ebin_space(md->ebin,md->nCrmsd,conrmsd_nm,"");
-    }
-    if (md->bDynBox)
-    {
-        md->ib    = get_ebin_space(md->ebin, 
-                                   md->bTricl ? NTRICLBOXS : NBOXS, 
-                                   md->bTricl ? tricl_boxs_nm : boxs_nm,
-                                   unit_length);
-        md->ivol  = get_ebin_space(md->ebin, 1, vol_nm,  unit_volume);
-        md->idens = get_ebin_space(md->ebin, 1, dens_nm, unit_density_SI);
-        md->ipv   = get_ebin_space(md->ebin, 1, pv_nm,   unit_energy);
-        md->ienthalpy = get_ebin_space(md->ebin, 1, enthalpy_nm,   unit_energy);
-    }
-    if (md->bConstrVir)
-    {
-        md->isvir = get_ebin_space(md->ebin,asize(sv_nm),sv_nm,unit_energy);
-        md->ifvir = get_ebin_space(md->ebin,asize(fv_nm),fv_nm,unit_energy);
-    }
-    md->ivir   = get_ebin_space(md->ebin,asize(vir_nm),vir_nm,unit_energy);
-    md->ipres  = get_ebin_space(md->ebin,asize(pres_nm),pres_nm,unit_pres_bar);
-    md->isurft = get_ebin_space(md->ebin,asize(surft_nm),surft_nm,
-                                unit_surft_bar);
-    if (md->epc == epcPARRINELLORAHMAN || md->epc == epcMTTK)
-    {
-        md->ipc = get_ebin_space(md->ebin,md->bTricl ? 6 : 3,
-                                 boxvel_nm,unit_vel);
-    }
-    md->imu    = get_ebin_space(md->ebin,asize(mu_nm),mu_nm,unit_dipole_D);
-    if (ir->cos_accel != 0)
-    {
-        md->ivcos = get_ebin_space(md->ebin,asize(vcos_nm),vcos_nm,unit_vel);
-        md->ivisc = get_ebin_space(md->ebin,asize(visc_nm),visc_nm,
-                                   unit_invvisc_SI);
-    }
-
-    /* Energy monitoring */
-    for(i=0;i<egNR;i++)
-    {
-        md->bEInd[i] = FALSE;
-    }
-    md->bEInd[egCOULSR] = TRUE;
-    md->bEInd[egLJSR  ] = TRUE;
-
-    if (ir->rcoulomb > ir->rlist)
-    {
-        md->bEInd[egCOULLR] = TRUE;
-    }
-    if (!bBHAM)
-    {
-        if (ir->rvdw > ir->rlist)
-        {
-            md->bEInd[egLJLR]   = TRUE;
-        }
-    }
-    else
-    {
-        md->bEInd[egLJSR]   = FALSE;
-        md->bEInd[egBHAMSR] = TRUE;
-        if (ir->rvdw > ir->rlist)
-        {
-            md->bEInd[egBHAMLR]   = TRUE;
-        }
-    }
-    if (b14)
-    {
-        md->bEInd[egLJ14] = TRUE;
-        md->bEInd[egCOUL14] = TRUE;
-    }
-    md->nEc=0;
-    for(i=0; (i<egNR); i++)
-    {
-        if (md->bEInd[i])
-        {
-            md->nEc++;
-        }
-    }
-
-    n=groups->grps[egcENER].nr;
-    md->nEg=n;
-    md->nE=(n*(n+1))/2;
-    snew(md->igrp,md->nE);
-    if (md->nE > 1)
-    {
-        n=0;
-        snew(gnm,md->nEc);
-        for(k=0; (k<md->nEc); k++)
-        {
-            snew(gnm[k],STRLEN);
-        }
-        for(i=0; (i<groups->grps[egcENER].nr); i++)
-        {
-            ni=groups->grps[egcENER].nm_ind[i];
-            for(j=i; (j<groups->grps[egcENER].nr); j++)
-            {
-                nj=groups->grps[egcENER].nm_ind[j];
-                for(k=kk=0; (k<egNR); k++)
-                {
-                    if (md->bEInd[k])
-                    {
-                        sprintf(gnm[kk],"%s:%s-%s",egrp_nm[k],
-                                *(groups->grpname[ni]),*(groups->grpname[nj]));
-                        kk++;
-                    }
-                }
-                md->igrp[n]=get_ebin_space(md->ebin,md->nEc,
-                                           (const char **)gnm,unit_energy);
-                n++;
-            }
-        }
-        for(k=0; (k<md->nEc); k++)
-        {
-            sfree(gnm[k]);
-        }
-        sfree(gnm);
-
-        if (n != md->nE)
-        {
-            gmx_incons("Number of energy terms wrong");
-        }
-    }
-
-    md->nTC=groups->grps[egcTC].nr;
-    md->nNHC = ir->opts.nhchainlength; /* shorthand for number of NH chains */ 
-    if (md->bMTTK)
-    {
-        md->nTCP = 1;  /* assume only one possible coupling system for barostat 
-                          for now */
-    } 
-    else 
-    {
-        md->nTCP = 0;
-    }
-
-    if (md->etc == etcNOSEHOOVER) {
-        if (md->bNHC_trotter) { 
-            md->mde_n = 2*md->nNHC*md->nTC;
-        }
-        else 
-        {
-            md->mde_n = 2*md->nTC;
-        }
-        if (md->epc == epcMTTK)
-        {
-            md->mdeb_n = 2*md->nNHC*md->nTCP;
-        }
-    } else { 
-        md->mde_n = md->nTC;
-        md->mdeb_n = 0;
-    }
-
-    snew(md->tmp_r,md->mde_n);
-    snew(md->tmp_v,md->mde_n);
-    snew(md->grpnms,md->mde_n);
-    grpnms = md->grpnms;
-
-    for(i=0; (i<md->nTC); i++)
-    {
-        ni=groups->grps[egcTC].nm_ind[i];
-        sprintf(buf,"T-%s",*(groups->grpname[ni]));
-        grpnms[i]=strdup(buf);
-    }
-    md->itemp=get_ebin_space(md->ebin,md->nTC,(const char **)grpnms,
-                             unit_temp_K);
-
-    bNoseHoover = (getenv("GMX_NOSEHOOVER_CHAINS") != NULL); /* whether to print Nose-Hoover chains */
-
-    if (md->etc == etcNOSEHOOVER)
-    {
-        if (bNoseHoover) 
-        {
-            if (md->bNHC_trotter) 
-            {
-                for(i=0; (i<md->nTC); i++) 
-                {
-                    ni=groups->grps[egcTC].nm_ind[i];
-                    bufi = *(groups->grpname[ni]);
-                    for(j=0; (j<md->nNHC); j++) 
-                    {
-                        sprintf(buf,"Xi-%d-%s",j,bufi);
-                        grpnms[2*(i*md->nNHC+j)]=strdup(buf);
-                        sprintf(buf,"vXi-%d-%s",j,bufi);
-                        grpnms[2*(i*md->nNHC+j)+1]=strdup(buf);
-                    }
-                }
-                md->itc=get_ebin_space(md->ebin,md->mde_n,
-                                       (const char **)grpnms,unit_invtime);
-                if (md->bMTTK) 
-                {
-                    for(i=0; (i<md->nTCP); i++) 
-                    {
-                        bufi = baro_nm[0];  /* All barostat DOF's together for now. */
-                        for(j=0; (j<md->nNHC); j++) 
-                        {
-                            sprintf(buf,"Xi-%d-%s",j,bufi);
-                            grpnms[2*(i*md->nNHC+j)]=strdup(buf);
-                            sprintf(buf,"vXi-%d-%s",j,bufi);
-                            grpnms[2*(i*md->nNHC+j)+1]=strdup(buf);
-                        }
-                    }
-                    md->itcb=get_ebin_space(md->ebin,md->mdeb_n,
-                                            (const char **)grpnms,unit_invtime);
-                }
-            } 
-            else
-            {
-                for(i=0; (i<md->nTC); i++) 
-                {
-                    ni=groups->grps[egcTC].nm_ind[i];
-                    bufi = *(groups->grpname[ni]);
-                    sprintf(buf,"Xi-%s",bufi);
-                    grpnms[2*i]=strdup(buf);
-                    sprintf(buf,"vXi-%s",bufi);
-                    grpnms[2*i+1]=strdup(buf);
-                }
-                md->itc=get_ebin_space(md->ebin,md->mde_n,
-                                       (const char **)grpnms,unit_invtime);
-            }
-        }
-    }
-    else if (md->etc == etcBERENDSEN || md->etc == etcYES || 
-             md->etc == etcVRESCALE)
-    {
-        for(i=0; (i<md->nTC); i++)
-        {
-            ni=groups->grps[egcTC].nm_ind[i];
-            sprintf(buf,"Lamb-%s",*(groups->grpname[ni]));
-            grpnms[i]=strdup(buf);
-        }
-        md->itc=get_ebin_space(md->ebin,md->mde_n,(const char **)grpnms,"");
-    }
-
-    sfree(grpnms);
-
-
-    md->nU=groups->grps[egcACC].nr;
-    if (md->nU > 1)
-    {
-        snew(grpnms,3*md->nU);
-        for(i=0; (i<md->nU); i++)
-        {
-            ni=groups->grps[egcACC].nm_ind[i];
-            sprintf(buf,"Ux-%s",*(groups->grpname[ni]));
-            grpnms[3*i+XX]=strdup(buf);
-            sprintf(buf,"Uy-%s",*(groups->grpname[ni]));
-            grpnms[3*i+YY]=strdup(buf);
-            sprintf(buf,"Uz-%s",*(groups->grpname[ni]));
-            grpnms[3*i+ZZ]=strdup(buf);
-        }
-        md->iu=get_ebin_space(md->ebin,3*md->nU,(const char **)grpnms,unit_vel);
-        sfree(grpnms);
-    }
-
-    if ( fp_ene )
-    {
-        do_enxnms(fp_ene,&md->ebin->nener,&md->ebin->enm);
-    }
-
-    md->print_grpnms=NULL;
-
-    /* check whether we're going to write dh histograms */
-    md->dhc=NULL; 
-    if (ir->separate_dhdl_file == sepdhdlfileNO )
-    {
-        int i;
-        snew(md->dhc, 1);
-
-        mde_delta_h_coll_init(md->dhc, ir);
-        md->fp_dhdl = NULL;
-    }
-    else
-    {
-        md->fp_dhdl = fp_dhdl;
-    }
-    md->dhdl_derivatives = (ir->dhdl_derivatives==dhdlderivativesYES);
-    return md;
-}
-
-FILE *open_dhdl(const char *filename,const t_inputrec *ir,
-                const output_env_t oenv)
-{
-    FILE *fp;
-    const char *dhdl="dH/d\\lambda",*deltag="\\DeltaH",*lambda="\\lambda";
-    char title[STRLEN],label_x[STRLEN],label_y[STRLEN];
-    char **setname;
-    char buf[STRLEN];
-
-    sprintf(label_x,"%s (%s)","Time",unit_time);
-    if (ir->n_flambda == 0)
-    {
-        sprintf(title,"%s",dhdl);
-        sprintf(label_y,"%s (%s %s)",
-                dhdl,unit_energy,"[\\lambda]\\S-1\\N");
-    }
-    else
-    {
-        sprintf(title,"%s, %s",dhdl,deltag);
-        sprintf(label_y,"(%s)",unit_energy);
-    }
-    fp = gmx_fio_fopen(filename,"w+");
-    xvgr_header(fp,title,label_x,label_y,exvggtXNY,oenv);
-
-    if (ir->delta_lambda == 0)
-    {
-        sprintf(buf,"T = %g (K), %s = %g",
-                ir->opts.ref_t[0],lambda,ir->init_lambda);
-    }
-    else
-    {
-        sprintf(buf,"T = %g (K)",
-                ir->opts.ref_t[0]);
-    }
-    xvgr_subtitle(fp,buf,oenv);
-
-    if (ir->n_flambda > 0)
-    {
-        int nsets,s,nsi=0;
-        /* g_bar has to determine the lambda values used in this simulation
-         * from this xvg legend.  */
-        nsets = ( (ir->dhdl_derivatives==dhdlderivativesYES) ? 1 : 0) + 
-                  ir->n_flambda;
-        snew(setname,nsets);
-        if (ir->dhdl_derivatives == dhdlderivativesYES)
-        {
-            sprintf(buf,"%s %s %g",dhdl,lambda,ir->init_lambda);
-            setname[nsi++] = strdup(buf);
-        }
-        for(s=0; s<ir->n_flambda; s++)
-        {
-            sprintf(buf,"%s %s %g",deltag,lambda,ir->flambda[s]);
-            setname[nsi++] = strdup(buf);
-        }
-        xvgr_legend(fp,nsets,(const char**)setname,oenv);
-
-        for(s=0; s<nsets; s++)
-        {
-            sfree(setname[s]);
-        }
-        sfree(setname);
-    }
-
-    return fp;
-}
-
-static void copy_energy(t_mdebin *md, real e[],real ecpy[])
-{
-    int i,j;
-
-    for(i=j=0; (i<F_NRE); i++)
-        if (md->bEner[i])
-            ecpy[j++] = e[i];
-    if (j != md->f_nre) 
-        gmx_incons("Number of energy terms wrong");
-}
-
-void upd_mdebin(t_mdebin *md, gmx_bool write_dhdl,
-                gmx_bool bSum,
-                double time,
-                real tmass,
-                gmx_enerdata_t *enerd,
-                t_state *state,
-                matrix  box,
-                tensor svir,
-                tensor fvir,
-                tensor vir,
-                tensor pres,
-                gmx_ekindata_t *ekind,
-                rvec mu_tot,
-                gmx_constr_t constr)
-{
-    int    i,j,k,kk,m,n,gid;
-    real   crmsd[2],tmp6[6];
-    real   bs[NTRICLBOXS],vol,dens,pv,enthalpy;
-    real   eee[egNR];
-    real   ecopy[F_NRE];
-    real   tmp;
-    gmx_bool   bNoseHoover;
-
-    /* Do NOT use the box in the state variable, but the separate box provided
-     * as an argument. This is because we sometimes need to write the box from
-     * the last timestep to match the trajectory frames.
-     */
-    copy_energy(md, enerd->term,ecopy);
-    add_ebin(md->ebin,md->ie,md->f_nre,ecopy,bSum);
-    if (md->nCrmsd)
-    {
-        crmsd[0] = constr_rmsd(constr,FALSE);
-        if (md->nCrmsd > 1)
-        {
-            crmsd[1] = constr_rmsd(constr,TRUE);
-        }
-        add_ebin(md->ebin,md->iconrmsd,md->nCrmsd,crmsd,FALSE);
-    }
-    if (md->bDynBox)
-    {
-        int nboxs;
-        if(md->bTricl)
-        {
-            bs[0] = box[XX][XX];
-            bs[1] = box[YY][YY];
-            bs[2] = box[ZZ][ZZ];
-            bs[3] = box[YY][XX];
-            bs[4] = box[ZZ][XX];
-            bs[5] = box[ZZ][YY];
-            nboxs=NTRICLBOXS;
-        }
-        else
-        {
-            bs[0] = box[XX][XX];
-            bs[1] = box[YY][YY];
-            bs[2] = box[ZZ][ZZ];
-            nboxs=NBOXS;
-        }
-        vol  = box[XX][XX]*box[YY][YY]*box[ZZ][ZZ];
-        dens = (tmass*AMU)/(vol*NANO*NANO*NANO);
-
-        /* This is pV (in kJ/mol).  The pressure is the reference pressure,
-           not the instantaneous pressure */  
-        pv = 0;
-        for (i=0;i<DIM;i++) 
-        {
-            for (j=0;j<DIM;j++) 
-            {
-                if (i>j) 
-                {
-                    pv += box[i][j]*md->ref_p[i][j]/PRESFAC;
-                } 
-                else 
-                {
-                    pv += box[j][i]*md->ref_p[j][i]/PRESFAC;
-                }
-            }
-        }
-
-        add_ebin(md->ebin,md->ib   ,nboxs,bs   ,bSum);
-        add_ebin(md->ebin,md->ivol ,1    ,&vol ,bSum);
-        add_ebin(md->ebin,md->idens,1    ,&dens,bSum);
-        add_ebin(md->ebin,md->ipv  ,1    ,&pv  ,bSum);
-        enthalpy = pv + enerd->term[F_ETOT];
-        add_ebin(md->ebin,md->ienthalpy  ,1    ,&enthalpy  ,bSum);
-    }
-    if (md->bConstrVir)
-    {
-        add_ebin(md->ebin,md->isvir,9,svir[0],bSum);
-        add_ebin(md->ebin,md->ifvir,9,fvir[0],bSum);
-    }
-    add_ebin(md->ebin,md->ivir,9,vir[0],bSum);
-    add_ebin(md->ebin,md->ipres,9,pres[0],bSum);
-    tmp = (pres[ZZ][ZZ]-(pres[XX][XX]+pres[YY][YY])*0.5)*box[ZZ][ZZ];
-    add_ebin(md->ebin,md->isurft,1,&tmp,bSum);
-    if (md->epc == epcPARRINELLORAHMAN || md->epc == epcMTTK)
-    {
-        tmp6[0] = state->boxv[XX][XX];
-        tmp6[1] = state->boxv[YY][YY];
-        tmp6[2] = state->boxv[ZZ][ZZ];
-        tmp6[3] = state->boxv[YY][XX];
-        tmp6[4] = state->boxv[ZZ][XX];
-        tmp6[5] = state->boxv[ZZ][YY];
-        add_ebin(md->ebin,md->ipc,md->bTricl ? 6 : 3,tmp6,bSum);
-    }
-    add_ebin(md->ebin,md->imu,3,mu_tot,bSum);
-    if (ekind && ekind->cosacc.cos_accel != 0)
-    {
-        vol  = box[XX][XX]*box[YY][YY]*box[ZZ][ZZ];
-        dens = (tmass*AMU)/(vol*NANO*NANO*NANO);
-        add_ebin(md->ebin,md->ivcos,1,&(ekind->cosacc.vcos),bSum);
-        /* 1/viscosity, unit 1/(kg m^-1 s^-1) */
-        tmp = 1/(ekind->cosacc.cos_accel/(ekind->cosacc.vcos*PICO)
-                 *vol*sqr(box[ZZ][ZZ]*NANO/(2*M_PI)));
-        add_ebin(md->ebin,md->ivisc,1,&tmp,bSum);    
-    }
-    if (md->nE > 1)
-    {
-        n=0;
-        for(i=0; (i<md->nEg); i++)
-        {
-            for(j=i; (j<md->nEg); j++)
-            {
-                gid=GID(i,j,md->nEg);
-                for(k=kk=0; (k<egNR); k++)
-                {
-                    if (md->bEInd[k])
-                    {
-                        eee[kk++] = enerd->grpp.ener[k][gid];
-                    }
-                }
-                add_ebin(md->ebin,md->igrp[n],md->nEc,eee,bSum);
-                n++;
-            }
-        }
-    }
-
-    if (ekind)
-    {
-        for(i=0; (i<md->nTC); i++)
-        {
-            md->tmp_r[i] = ekind->tcstat[i].T;
-        }
-        add_ebin(md->ebin,md->itemp,md->nTC,md->tmp_r,bSum);
-
-        /* whether to print Nose-Hoover chains: */
-        bNoseHoover = (getenv("GMX_NOSEHOOVER_CHAINS") != NULL); 
-
-        if (md->etc == etcNOSEHOOVER)
-        {
-            if (bNoseHoover) 
-            {
-                if (md->bNHC_trotter)
-                {
-                    for(i=0; (i<md->nTC); i++) 
-                    {
-                        for (j=0;j<md->nNHC;j++) 
-                        {
-                            k = i*md->nNHC+j;
-                            md->tmp_r[2*k] = state->nosehoover_xi[k];
-                            md->tmp_r[2*k+1] = state->nosehoover_vxi[k];
-                        }
-                    }
-                    add_ebin(md->ebin,md->itc,md->mde_n,md->tmp_r,bSum);      
-
-                    if (md->bMTTK) {
-                        for(i=0; (i<md->nTCP); i++) 
-                        {
-                            for (j=0;j<md->nNHC;j++) 
-                            {
-                                k = i*md->nNHC+j;
-                                md->tmp_r[2*k] = state->nhpres_xi[k];
-                                md->tmp_r[2*k+1] = state->nhpres_vxi[k];
-                            }
-                        }
-                        add_ebin(md->ebin,md->itcb,md->mdeb_n,md->tmp_r,bSum);      
-                    }
-
-                } 
-                else 
-                {
-                    for(i=0; (i<md->nTC); i++)
-                    {
-                        md->tmp_r[2*i] = state->nosehoover_xi[i];
-                        md->tmp_r[2*i+1] = state->nosehoover_vxi[i];
-                    }
-                    add_ebin(md->ebin,md->itc,md->mde_n,md->tmp_r,bSum);
-                }
-            }
-        }
-        else if (md->etc == etcBERENDSEN || md->etc == etcYES || 
-                 md->etc == etcVRESCALE)
-        {
-            for(i=0; (i<md->nTC); i++)
-            {
-                md->tmp_r[i] = ekind->tcstat[i].lambda;
-            }
-            add_ebin(md->ebin,md->itc,md->nTC,md->tmp_r,bSum);
-        }
-    }
-
-    if (ekind && md->nU > 1)
-    {
-        for(i=0; (i<md->nU); i++)
-        {
-            copy_rvec(ekind->grpstat[i].u,md->tmp_v[i]);
-        }
-        add_ebin(md->ebin,md->iu,3*md->nU,md->tmp_v[0],bSum);
-    }
-
-    ebin_increase_count(md->ebin,bSum);
-
-    /* BAR + thermodynamic integration values */
-    if (write_dhdl)
-    {
-        if (md->fp_dhdl)
-        {
-            fprintf(md->fp_dhdl,"%.4f", time);
-
-            if (md->dhdl_derivatives)
-            {
-                fprintf(md->fp_dhdl," %g", enerd->term[F_DVDL]+ 
-                                           enerd->term[F_DKDL]+
-                                           enerd->term[F_DHDL_CON]);
-            }
-            for(i=1; i<enerd->n_lambda; i++)
-            {
-                fprintf(md->fp_dhdl," %g",
-                        enerd->enerpart_lambda[i]-enerd->enerpart_lambda[0]);
-            }
-            fprintf(md->fp_dhdl,"\n");
-        }
-        /* and the binary BAR output */
-        if (md->dhc)
-        {
-            mde_delta_h_coll_add_dh(md->dhc, 
-                                    enerd->term[F_DVDL]+ enerd->term[F_DKDL]+
-                                    enerd->term[F_DHDL_CON],
-                                    enerd->enerpart_lambda, time, 
-                                    state->lambda);
-        }
-    }
-}
-
-void upd_mdebin_step(t_mdebin *md)
-{
-    ebin_increase_count(md->ebin,FALSE); 
-}
-
-static void npr(FILE *log,int n,char c)
-{
-    for(; (n>0); n--) fprintf(log,"%c",c);
-}
-
-static void pprint(FILE *log,const char *s,t_mdebin *md)
-{
-    char CHAR='#';
-    int  slen;
-    char buf1[22],buf2[22];
-
-    slen = strlen(s);
-    fprintf(log,"\t<======  ");
-    npr(log,slen,CHAR);
-    fprintf(log,"  ==>\n");
-    fprintf(log,"\t<====  %s  ====>\n",s);
-    fprintf(log,"\t<==  ");
-    npr(log,slen,CHAR);
-    fprintf(log,"  ======>\n\n");
-
-    fprintf(log,"\tStatistics over %s steps using %s frames\n",
-            gmx_step_str(md->ebin->nsteps_sim,buf1),
-            gmx_step_str(md->ebin->nsum_sim,buf2));
-    fprintf(log,"\n");
-}
-
-void print_ebin_header(FILE *log,gmx_large_int_t steps,double time,real lamb)
-{
-    char buf[22];
-
-    fprintf(log,"   %12s   %12s   %12s\n"
-            "   %12s   %12.5f   %12.5f\n\n",
-            "Step","Time","Lambda",gmx_step_str(steps,buf),time,lamb);
-}
-
-void print_ebin(ener_file_t fp_ene,gmx_bool bEne,gmx_bool bDR,gmx_bool bOR,
-                FILE *log,
-                gmx_large_int_t step,double time,
-                int mode,gmx_bool bCompact,
-                t_mdebin *md,t_fcdata *fcd,
-                gmx_groups_t *groups,t_grpopts *opts)
-{
-    /*static char **grpnms=NULL;*/
-    char        buf[246];
-    int         i,j,n,ni,nj,ndr,nor,b;
-    int         ndisre=0;
-    real        *disre_rm3tav, *disre_rt;
-
-    /* these are for the old-style blocks (1 subblock, only reals), because
-       there can be only one per ID for these */
-    int         nr[enxNR];
-    int         id[enxNR];
-    real        *block[enxNR];
-
-    /* temporary arrays for the lambda values to write out */
-    double      enxlambda_data[2]; 
-
-    t_enxframe  fr;
-
-    switch (mode)
-    {
-        case eprNORMAL:
-            init_enxframe(&fr);
-            fr.t            = time;
-            fr.step         = step;
-            fr.nsteps       = md->ebin->nsteps;
-            fr.dt           = md->delta_t;
-            fr.nsum         = md->ebin->nsum;
-            fr.nre          = (bEne) ? md->ebin->nener : 0;
-            fr.ener         = md->ebin->e;
-            ndisre          = bDR ? fcd->disres.npair : 0;
-            disre_rm3tav    = fcd->disres.rm3tav;
-            disre_rt        = fcd->disres.rt;
-            /* Optional additional old-style (real-only) blocks. */
-            for(i=0; i<enxNR; i++)
-            {
-                nr[i] = 0;
-            }
-            if (fcd->orires.nr > 0 && bOR)
-            {
-                diagonalize_orires_tensors(&(fcd->orires));
-                nr[enxOR]     = fcd->orires.nr;
-                block[enxOR]  = fcd->orires.otav;
-                id[enxOR]     = enxOR;
-                nr[enxORI]    = (fcd->orires.oinsl != fcd->orires.otav) ? 
-                          fcd->orires.nr : 0;
-                block[enxORI] = fcd->orires.oinsl;
-                id[enxORI]    = enxORI;
-                nr[enxORT]    = fcd->orires.nex*12;
-                block[enxORT] = fcd->orires.eig;
-                id[enxORT]    = enxORT;
-            }        
-
-            /* whether we are going to wrte anything out: */
-            if (fr.nre || ndisre || nr[enxOR] || nr[enxORI])
-            {
-
-                /* the old-style blocks go first */
-                fr.nblock = 0;
-                for(i=0; i<enxNR; i++)
-                {
-                    if (nr[i] > 0)
-                    {
-                        fr.nblock = i + 1;
-                    }
-                }
-                add_blocks_enxframe(&fr, fr.nblock);
-                for(b=0;b<fr.nblock;b++)
-                {
-                    add_subblocks_enxblock(&(fr.block[b]), 1);
-                    fr.block[b].id=id[b]; 
-                    fr.block[b].sub[0].nr = nr[b];
-#ifndef GMX_DOUBLE
-                    fr.block[b].sub[0].type = xdr_datatype_float;
-                    fr.block[b].sub[0].fval = block[b];
-#else
-                    fr.block[b].sub[0].type = xdr_datatype_double;
-                    fr.block[b].sub[0].dval = block[b];
-#endif
-                }
-
-                /* check for disre block & fill it. */
-                if (ndisre>0)
-                {
-                    int db = fr.nblock;
-                    fr.nblock+=1;
-                    add_blocks_enxframe(&fr, fr.nblock);
-
-                    add_subblocks_enxblock(&(fr.block[db]), 2);
-                    fr.block[db].id=enxDISRE;
-                    fr.block[db].sub[0].nr=ndisre;
-                    fr.block[db].sub[1].nr=ndisre;
-#ifndef GMX_DOUBLE
-                    fr.block[db].sub[0].type=xdr_datatype_float;
-                    fr.block[db].sub[1].type=xdr_datatype_float;
-                    fr.block[db].sub[0].fval=disre_rt;
-                    fr.block[db].sub[1].fval=disre_rm3tav;
-#else
-                    fr.block[db].sub[0].type=xdr_datatype_double;
-                    fr.block[db].sub[1].type=xdr_datatype_double;
-                    fr.block[db].sub[0].dval=disre_rt;
-                    fr.block[db].sub[1].dval=disre_rm3tav;
-#endif
-                }
-                /* here we can put new-style blocks */
-
-                /* Free energy perturbation blocks */
-                if (md->dhc)
-                {
-                    mde_delta_h_coll_handle_block(md->dhc, &fr, fr.nblock);
-                }
-
-                /* do the actual I/O */
-                do_enx(fp_ene,&fr);
-                gmx_fio_check_file_position(enx_file_pointer(fp_ene));
-                if (fr.nre)
-                {
-                    /* We have stored the sums, so reset the sum history */
-                    reset_ebin_sums(md->ebin);
-                }
-
-                /* we can now free & reset the data in the blocks */
-                if (md->dhc)
-                    mde_delta_h_coll_reset(md->dhc);
-            }
-            free_enxframe(&fr);
-            break;
-        case eprAVER:
-            if (log)
-            {
-                pprint(log,"A V E R A G E S",md);
-            }
-            break;
-        case eprRMS:
-            if (log)
-            {
-                pprint(log,"R M S - F L U C T U A T I O N S",md);
-            }
-            break;
-        default:
-            gmx_fatal(FARGS,"Invalid print mode (%d)",mode);
-    }
-
-    if (log)
-    {
-        for(i=0;i<opts->ngtc;i++)
-        {
-            if(opts->annealing[i]!=eannNO)
-            {
-                fprintf(log,"Current ref_t for group %s: %8.1f\n",
-                        *(groups->grpname[groups->grps[egcTC].nm_ind[i]]),
-                        opts->ref_t[i]);
-            }
-        }
-        if (mode==eprNORMAL && fcd->orires.nr>0)
-        {
-            print_orires_log(log,&(fcd->orires));
-        }
-        fprintf(log,"   Energies (%s)\n",unit_energy);
-        pr_ebin(log,md->ebin,md->ie,md->f_nre+md->nCrmsd,5,mode,TRUE);  
-        fprintf(log,"\n");
-
-        if (!bCompact)
-        {
-            if (md->bDynBox)
-            {
-                pr_ebin(log,md->ebin,md->ib, md->bTricl ? NTRICLBOXS : NBOXS,5,
-                        mode,TRUE);      
-                fprintf(log,"\n");
-            }
-            if (md->bConstrVir)
-            {
-                fprintf(log,"   Constraint Virial (%s)\n",unit_energy);
-                pr_ebin(log,md->ebin,md->isvir,9,3,mode,FALSE);  
-                fprintf(log,"\n");
-                fprintf(log,"   Force Virial (%s)\n",unit_energy);
-                pr_ebin(log,md->ebin,md->ifvir,9,3,mode,FALSE);  
-                fprintf(log,"\n");
-            }
-            fprintf(log,"   Total Virial (%s)\n",unit_energy);
-            pr_ebin(log,md->ebin,md->ivir,9,3,mode,FALSE);   
-            fprintf(log,"\n");
-            fprintf(log,"   Pressure (%s)\n",unit_pres_bar);
-            pr_ebin(log,md->ebin,md->ipres,9,3,mode,FALSE);  
-            fprintf(log,"\n");
-            fprintf(log,"   Total Dipole (%s)\n",unit_dipole_D);
-            pr_ebin(log,md->ebin,md->imu,3,3,mode,FALSE);    
-            fprintf(log,"\n");
-
-            if (md->nE > 1)
-            {
-                if (md->print_grpnms==NULL)
-                {
-                    snew(md->print_grpnms,md->nE);
-                    n=0;
-                    for(i=0; (i<md->nEg); i++)
-                    {
-                        ni=groups->grps[egcENER].nm_ind[i];
-                        for(j=i; (j<md->nEg); j++)
-                        {
-                            nj=groups->grps[egcENER].nm_ind[j];
-                            sprintf(buf,"%s-%s",*(groups->grpname[ni]),
-                                    *(groups->grpname[nj]));
-                            md->print_grpnms[n++]=strdup(buf);
-                        }
-                    }
-                }
-                sprintf(buf,"Epot (%s)",unit_energy);
-                fprintf(log,"%15s   ",buf);
-                for(i=0; (i<egNR); i++)
-                {
-                    if (md->bEInd[i])
-                    {
-                        fprintf(log,"%12s   ",egrp_nm[i]);
-                    }
-                }
-                fprintf(log,"\n");
-                for(i=0; (i<md->nE); i++)
-                {
-                    fprintf(log,"%15s",md->print_grpnms[i]);
-                    pr_ebin(log,md->ebin,md->igrp[i],md->nEc,md->nEc,mode,
-                            FALSE);
-                }
-                fprintf(log,"\n");
-            }
-            if (md->nTC > 1)
-            {
-                pr_ebin(log,md->ebin,md->itemp,md->nTC,4,mode,TRUE);
-                fprintf(log,"\n");
-            }
-            if (md->nU > 1)
-            {
-                fprintf(log,"%15s   %12s   %12s   %12s\n",
-                        "Group","Ux","Uy","Uz");
-                for(i=0; (i<md->nU); i++)
-                {
-                    ni=groups->grps[egcACC].nm_ind[i];
-                    fprintf(log,"%15s",*groups->grpname[ni]);
-                    pr_ebin(log,md->ebin,md->iu+3*i,3,3,mode,FALSE);
-                }
-                fprintf(log,"\n");
-            }
-        }
-    }
-
-}
-
-void update_energyhistory(energyhistory_t * enerhist,t_mdebin * mdebin)
-{
-    int i;
-
-    enerhist->nsteps     = mdebin->ebin->nsteps;
-    enerhist->nsum       = mdebin->ebin->nsum;
-    enerhist->nsteps_sim = mdebin->ebin->nsteps_sim;
-    enerhist->nsum_sim   = mdebin->ebin->nsum_sim;
-    enerhist->nener      = mdebin->ebin->nener;
-
-    if (mdebin->ebin->nsum > 0)
-    {
-        /* Check if we need to allocate first */
-        if(enerhist->ener_ave == NULL)
-        {
-            snew(enerhist->ener_ave,enerhist->nener);
-            snew(enerhist->ener_sum,enerhist->nener);
-        }
-
-        for(i=0;i<enerhist->nener;i++)
-        {
-            enerhist->ener_ave[i] = mdebin->ebin->e[i].eav;
-            enerhist->ener_sum[i] = mdebin->ebin->e[i].esum;
-        }
-    }
-
-    if (mdebin->ebin->nsum_sim > 0)
-    {
-        /* Check if we need to allocate first */
-        if(enerhist->ener_sum_sim == NULL)
-        {
-            snew(enerhist->ener_sum_sim,enerhist->nener);
-        }
-
-        for(i=0;i<enerhist->nener;i++)
-        {
-            enerhist->ener_sum_sim[i] = mdebin->ebin->e_sim[i].esum;
-        }
-    }
-    if (mdebin->dhc)
-    {
-        mde_delta_h_coll_update_energyhistory(mdebin->dhc, enerhist);
-    }
-}
-
-void restore_energyhistory_from_state(t_mdebin * mdebin,
-                                      energyhistory_t * enerhist)
-{
-    int i;
-
-    if ((enerhist->nsum > 0 || enerhist->nsum_sim > 0) &&
-        mdebin->ebin->nener != enerhist->nener)
-    {
-        gmx_fatal(FARGS,"Mismatch between number of energies in run input (%d) and checkpoint file (%d).",
-                  mdebin->ebin->nener,enerhist->nener);
-    }
-
-    mdebin->ebin->nsteps     = enerhist->nsteps;
-    mdebin->ebin->nsum       = enerhist->nsum;
-    mdebin->ebin->nsteps_sim = enerhist->nsteps_sim;
-    mdebin->ebin->nsum_sim   = enerhist->nsum_sim;
-
-    for(i=0; i<mdebin->ebin->nener; i++)
-    {
-        mdebin->ebin->e[i].eav  =
-                  (enerhist->nsum > 0 ? enerhist->ener_ave[i] : 0);
-        mdebin->ebin->e[i].esum =
-                  (enerhist->nsum > 0 ? enerhist->ener_sum[i] : 0);
-        mdebin->ebin->e_sim[i].esum =
-                  (enerhist->nsum_sim > 0 ? enerhist->ener_sum_sim[i] : 0);
-    }
-    if (mdebin->dhc)
-    {         
-        mde_delta_h_coll_restore_energyhistory(mdebin->dhc, enerhist);
-    }
-}
diff --git a/src/mdlib/minimize.c b/src/mdlib/minimize.c
deleted file mode 100644 (file)
index 588544c..0000000
+++ /dev/null
@@ -1,2511 +0,0 @@
-/* -*- mode: c; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; c-file-style: "stroustrup"; -*-
- *
- * 
- *                This source code is part of
- * 
- *                 G   R   O   M   A   C   S
- * 
- *          GROningen MAchine for Chemical Simulations
- * 
- *                        VERSION 3.2.0
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
- * 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.
-
- * 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:
- * GROwing Monsters And Cloning Shrimps
- */
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <string.h>
-#include <time.h>
-#include <math.h>
-#include "sysstuff.h"
-#include "string2.h"
-#include "network.h"
-#include "confio.h"
-#include "copyrite.h"
-#include "smalloc.h"
-#include "nrnb.h"
-#include "main.h"
-#include "force.h"
-#include "macros.h"
-#include "random.h"
-#include "names.h"
-#include "gmx_fatal.h"
-#include "txtdump.h"
-#include "typedefs.h"
-#include "update.h"
-#include "constr.h"
-#include "vec.h"
-#include "statutil.h"
-#include "tgroup.h"
-#include "mdebin.h"
-#include "vsite.h"
-#include "force.h"
-#include "mdrun.h"
-#include "domdec.h"
-#include "partdec.h"
-#include "trnio.h"
-#include "sparsematrix.h"
-#include "mtxio.h"
-#include "mdatoms.h"
-#include "ns.h"
-#include "gmx_wallcycle.h"
-#include "mtop_util.h"
-#include "gmxfio.h"
-#include "pme.h"
-
-typedef struct {
-  t_state s;
-  rvec    *f;
-  real    epot;
-  real    fnorm;
-  real    fmax;
-  int     a_fmax;
-} em_state_t;
-
-static em_state_t *init_em_state()
-{
-  em_state_t *ems;
-  
-  snew(ems,1);
-
-  return ems;
-}
-
-static void print_em_start(FILE *fplog,t_commrec *cr,gmx_runtime_t *runtime,
-                           gmx_wallcycle_t wcycle,
-                           const char *name)
-{
-    char buf[STRLEN];
-
-    runtime_start(runtime);
-
-    sprintf(buf,"Started %s",name);
-    print_date_and_time(fplog,cr->nodeid,buf,NULL);
-
-    wallcycle_start(wcycle,ewcRUN);
-}
-static void em_time_end(FILE *fplog,t_commrec *cr,gmx_runtime_t *runtime,
-                        gmx_wallcycle_t wcycle)
-{
-    wallcycle_stop(wcycle,ewcRUN);
-
-    runtime_end(runtime);
-}
-
-static void sp_header(FILE *out,const char *minimizer,real ftol,int nsteps)
-{
-    fprintf(out,"\n");
-    fprintf(out,"%s:\n",minimizer);
-    fprintf(out,"   Tolerance (Fmax)   = %12.5e\n",ftol);
-    fprintf(out,"   Number of steps    = %12d\n",nsteps);
-}
-
-static void warn_step(FILE *fp,real ftol,gmx_bool bLastStep,gmx_bool bConstrain)
-{
-    if (bLastStep)
-    {
-        fprintf(fp,"\nReached the maximum number of steps before reaching Fmax < %g\n",ftol);
-    }
-    else
-    {
-        fprintf(fp,"\nStepsize too small, or no change in energy.\n"
-                "Converged to machine precision,\n"
-                "but not to the requested precision Fmax < %g\n",
-                ftol);
-        if (sizeof(real)<sizeof(double))
-        {
-            fprintf(fp,"\nDouble precision normally gives you higher accuracy.\n");
-        }
-        if (bConstrain)
-        {
-            fprintf(fp,"You might need to increase your constraint accuracy, or turn\n"
-                    "off constraints alltogether (set constraints = none in mdp file)\n");
-        }
-    }
-}
-
-
-
-static void print_converged(FILE *fp,const char *alg,real ftol,
-                           gmx_large_int_t count,gmx_bool bDone,gmx_large_int_t nsteps,
-                           real epot,real fmax, int nfmax, real fnorm)
-{
-  char buf[STEPSTRSIZE];
-
-  if (bDone)
-    fprintf(fp,"\n%s converged to Fmax < %g in %s steps\n",
-           alg,ftol,gmx_step_str(count,buf)); 
-  else if(count<nsteps)
-    fprintf(fp,"\n%s converged to machine precision in %s steps,\n"
-               "but did not reach the requested Fmax < %g.\n",
-           alg,gmx_step_str(count,buf),ftol);
-  else 
-    fprintf(fp,"\n%s did not converge to Fmax < %g in %s steps.\n",
-           alg,ftol,gmx_step_str(count,buf));
-
-#ifdef GMX_DOUBLE
-  fprintf(fp,"Potential Energy  = %21.14e\n",epot); 
-  fprintf(fp,"Maximum force     = %21.14e on atom %d\n",fmax,nfmax+1); 
-  fprintf(fp,"Norm of force     = %21.14e\n",fnorm); 
-#else
-  fprintf(fp,"Potential Energy  = %14.7e\n",epot); 
-  fprintf(fp,"Maximum force     = %14.7e on atom %d\n",fmax,nfmax+1); 
-  fprintf(fp,"Norm of force     = %14.7e\n",fnorm); 
-#endif
-}
-
-static void get_f_norm_max(t_commrec *cr,
-                          t_grpopts *opts,t_mdatoms *mdatoms,rvec *f,
-                          real *fnorm,real *fmax,int *a_fmax)
-{
-  double fnorm2,*sum;
-  real fmax2,fmax2_0,fam;
-  int  la_max,a_max,start,end,i,m,gf;
-
-  /* This routine finds the largest force and returns it.
-   * On parallel machines the global max is taken.
-   */
-  fnorm2 = 0;
-  fmax2 = 0;
-  la_max = -1;
-  gf = 0;
-  start = mdatoms->start;
-  end   = mdatoms->homenr + start;
-  if (mdatoms->cFREEZE) {
-    for(i=start; i<end; i++) {
-      gf = mdatoms->cFREEZE[i];
-      fam = 0;
-      for(m=0; m<DIM; m++)
-       if (!opts->nFreeze[gf][m])
-         fam += sqr(f[i][m]);
-      fnorm2 += fam;
-      if (fam > fmax2) {
-       fmax2  = fam;
-       la_max = i;
-      }
-    }
-  } else {
-    for(i=start; i<end; i++) {
-      fam = norm2(f[i]);
-      fnorm2 += fam;
-      if (fam > fmax2) {
-       fmax2  = fam;
-       la_max = i;
-      }
-    }
-  }
-
-  if (la_max >= 0 && DOMAINDECOMP(cr)) {
-    a_max = cr->dd->gatindex[la_max];
-  } else {
-    a_max = la_max;
-  }
-  if (PAR(cr)) {
-    snew(sum,2*cr->nnodes+1);
-    sum[2*cr->nodeid]   = fmax2;
-    sum[2*cr->nodeid+1] = a_max;
-    sum[2*cr->nnodes]   = fnorm2;
-    gmx_sumd(2*cr->nnodes+1,sum,cr);
-    fnorm2 = sum[2*cr->nnodes];
-    /* Determine the global maximum */
-    for(i=0; i<cr->nnodes; i++) {
-      if (sum[2*i] > fmax2) {
-       fmax2 = sum[2*i];
-       a_max = (int)(sum[2*i+1] + 0.5);
-      }
-    }
-    sfree(sum);
-  }
-
-  if (fnorm)
-    *fnorm = sqrt(fnorm2);
-  if (fmax)
-    *fmax  = sqrt(fmax2);
-  if (a_fmax)
-    *a_fmax = a_max;
-}
-
-static void get_state_f_norm_max(t_commrec *cr,
-                          t_grpopts *opts,t_mdatoms *mdatoms,
-                          em_state_t *ems)
-{
-  get_f_norm_max(cr,opts,mdatoms,ems->f,&ems->fnorm,&ems->fmax,&ems->a_fmax);
-}
-
-void init_em(FILE *fplog,const char *title,
-             t_commrec *cr,t_inputrec *ir,
-             t_state *state_global,gmx_mtop_t *top_global,
-             em_state_t *ems,gmx_localtop_t **top,
-             rvec **f,rvec **f_global,
-             t_nrnb *nrnb,rvec mu_tot,
-             t_forcerec *fr,gmx_enerdata_t **enerd,
-             t_graph **graph,t_mdatoms *mdatoms,gmx_global_stat_t *gstat,
-             gmx_vsite_t *vsite,gmx_constr_t constr,
-             int nfile,const t_filenm fnm[],
-             gmx_mdoutf_t **outf,t_mdebin **mdebin)
-{
-    int  start,homenr,i;
-    real dvdlambda;
-    
-    if (fplog)
-    {
-        fprintf(fplog,"Initiating %s\n",title);
-    }
-    
-    state_global->ngtc = 0;
-    
-    /* Initiate some variables */
-    if (ir->efep != efepNO)
-    {
-        state_global->lambda = ir->init_lambda;
-    }
-    else 
-    {
-        state_global->lambda = 0.0;
-    }
-    
-    init_nrnb(nrnb);
-    
-    if (DOMAINDECOMP(cr))
-    {
-        *top = dd_init_local_top(top_global);
-        
-        dd_init_local_state(cr->dd,state_global,&ems->s);
-
-        *f = NULL;
-        
-        /* Distribute the charge groups over the nodes from the master node */
-        dd_partition_system(fplog,ir->init_step,cr,TRUE,1,
-                            state_global,top_global,ir,
-                            &ems->s,&ems->f,mdatoms,*top,
-                            fr,vsite,NULL,constr,
-                            nrnb,NULL,FALSE);
-        dd_store_state(cr->dd,&ems->s);
-        
-        if (ir->nstfout)
-        {
-            snew(*f_global,top_global->natoms);
-        }
-        else
-        {
-            *f_global = NULL;
-        }
-        *graph = NULL;
-    }
-    else
-    {
-        snew(*f,top_global->natoms);
-
-        /* Just copy the state */
-        ems->s = *state_global;
-        snew(ems->s.x,ems->s.nalloc);
-        snew(ems->f,ems->s.nalloc);
-        for(i=0; i<state_global->natoms; i++)
-        {
-            copy_rvec(state_global->x[i],ems->s.x[i]);
-        }
-        copy_mat(state_global->box,ems->s.box);
-        
-        if (PAR(cr) && ir->eI != eiNM)
-        {
-            /* Initialize the particle decomposition and split the topology */
-            *top = split_system(fplog,top_global,ir,cr);
-            
-            pd_cg_range(cr,&fr->cg0,&fr->hcg);
-        }
-        else
-        {
-            *top = gmx_mtop_generate_local_top(top_global,ir);
-        }
-        *f_global = *f;
-        
-        if (ir->ePBC != epbcNONE && !ir->bPeriodicMols)
-        {
-            *graph = mk_graph(fplog,&((*top)->idef),0,top_global->natoms,FALSE,FALSE);
-        }
-        else
-        {
-            *graph = NULL;
-        }
-
-        if (PARTDECOMP(cr))
-        {
-            pd_at_range(cr,&start,&homenr);
-            homenr -= start;
-        }
-        else
-        {
-            start  = 0;
-            homenr = top_global->natoms;
-        }
-        atoms2md(top_global,ir,0,NULL,start,homenr,mdatoms);
-        update_mdatoms(mdatoms,state_global->lambda);
-    
-        if (vsite)
-        {
-            set_vsite_top(vsite,*top,mdatoms,cr);
-        }
-    }
-    
-    if (constr)
-    {
-        if (ir->eConstrAlg == econtSHAKE &&
-            gmx_mtop_ftype_count(top_global,F_CONSTR) > 0)
-        {
-            gmx_fatal(FARGS,"Can not do energy minimization with %s, use %s\n",
-                      econstr_names[econtSHAKE],econstr_names[econtLINCS]);
-        }
-        
-        if (!DOMAINDECOMP(cr))
-        {
-            set_constraints(constr,*top,ir,mdatoms,cr);
-        }
-
-        if (!ir->bContinuation)
-        {
-            /* Constrain the starting coordinates */
-            dvdlambda=0;
-            constrain(PAR(cr) ? NULL : fplog,TRUE,TRUE,constr,&(*top)->idef,
-                      ir,NULL,cr,-1,0,mdatoms,
-                      ems->s.x,ems->s.x,NULL,ems->s.box,
-                      ems->s.lambda,&dvdlambda,
-                      NULL,NULL,nrnb,econqCoord,FALSE,0,0);
-        }
-    }
-    
-    if (PAR(cr))
-    {
-        *gstat = global_stat_init(ir);
-    }
-    
-    *outf = init_mdoutf(nfile,fnm,0,cr,ir,NULL);
-
-    snew(*enerd,1);
-    init_enerdata(top_global->groups.grps[egcENER].nr,ir->n_flambda,*enerd);
-
-    if (mdebin != NULL)
-    {
-        /* Init bin for energy stuff */
-        *mdebin = init_mdebin((*outf)->fp_ene,top_global,ir,NULL); 
-    }
-
-    clear_rvec(mu_tot);
-    calc_shifts(ems->s.box,fr->shift_vec);
-}
-
-static void finish_em(FILE *fplog,t_commrec *cr,gmx_mdoutf_t *outf,
-                      gmx_runtime_t *runtime,gmx_wallcycle_t wcycle)
-{
-  if (!(cr->duty & DUTY_PME)) {
-    /* Tell the PME only node to finish */
-    gmx_pme_finish(cr);
-  }
-
-  done_mdoutf(outf);
-
-  em_time_end(fplog,cr,runtime,wcycle);
-}
-
-static void swap_em_state(em_state_t *ems1,em_state_t *ems2)
-{
-  em_state_t tmp;
-
-  tmp   = *ems1;
-  *ems1 = *ems2;
-  *ems2 = tmp;
-}
-
-static void copy_em_coords_back(em_state_t *ems,t_state *state,rvec *f)
-{
-  int i;
-
-  for(i=0; (i<state->natoms); i++)
-    copy_rvec(ems->s.x[i],state->x[i]);
-  if (f != NULL)
-    copy_rvec(ems->f[i],f[i]);
-}
-
-static void write_em_traj(FILE *fplog,t_commrec *cr,
-                          gmx_mdoutf_t *outf,
-                          gmx_bool bX,gmx_bool bF,const char *confout,
-                          gmx_mtop_t *top_global,
-                          t_inputrec *ir,gmx_large_int_t step,
-                          em_state_t *state,
-                          t_state *state_global,rvec *f_global)
-{
-    int mdof_flags;
-
-    if ((bX || bF || confout != NULL) && !DOMAINDECOMP(cr))
-    {
-        f_global = state->f;
-        copy_em_coords_back(state,state_global,bF ? f_global : NULL);
-    }
-    
-    mdof_flags = 0;
-    if (bX) { mdof_flags |= MDOF_X; }
-    if (bF) { mdof_flags |= MDOF_F; }
-    write_traj(fplog,cr,outf,mdof_flags,
-               top_global,step,(double)step,
-               &state->s,state_global,state->f,f_global,NULL,NULL);
-    
-    if (confout != NULL && MASTER(cr))
-    {
-        if (ir->ePBC != epbcNONE && !ir->bPeriodicMols && DOMAINDECOMP(cr))
-        {
-            /* Make molecules whole only for confout writing */
-            do_pbc_mtop(fplog,ir->ePBC,state_global->box,top_global,
-                        state_global->x);
-        }
-
-        write_sto_conf_mtop(confout,
-                            *top_global->name,top_global,
-                            state_global->x,NULL,ir->ePBC,state_global->box);
-    }
-}
-
-static void do_em_step(t_commrec *cr,t_inputrec *ir,t_mdatoms *md,
-                      em_state_t *ems1,real a,rvec *f,em_state_t *ems2,
-                      gmx_constr_t constr,gmx_localtop_t *top,
-                      t_nrnb *nrnb,gmx_wallcycle_t wcycle,
-                      gmx_large_int_t count)
-
-{
-  t_state *s1,*s2;
-  int  start,end,gf,i,m;
-  rvec *x1,*x2;
-  real dvdlambda;
-
-  s1 = &ems1->s;
-  s2 = &ems2->s;
-
-  if (DOMAINDECOMP(cr) && s1->ddp_count != cr->dd->ddp_count)
-    gmx_incons("state mismatch in do_em_step");
-
-  s2->flags = s1->flags;
-
-  if (s2->nalloc != s1->nalloc) {
-    s2->nalloc = s1->nalloc;
-    srenew(s2->x,s1->nalloc);
-    srenew(ems2->f,  s1->nalloc);
-    if (s2->flags & (1<<estCGP))
-      srenew(s2->cg_p,  s1->nalloc);
-  }
-  
-  s2->natoms = s1->natoms;
-  s2->lambda = s1->lambda;
-  copy_mat(s1->box,s2->box);
-
-  start = md->start;
-  end   = md->start + md->homenr;
-
-  x1 = s1->x;
-  x2 = s2->x;
-  gf = 0;
-  for(i=start; i<end; i++) {
-    if (md->cFREEZE)
-      gf = md->cFREEZE[i];
-    for(m=0; m<DIM; m++) {
-      if (ir->opts.nFreeze[gf][m])
-       x2[i][m] = x1[i][m];
-      else
-       x2[i][m] = x1[i][m] + a*f[i][m];
-    }
-  }
-
-  if (s2->flags & (1<<estCGP)) {
-    /* Copy the CG p vector */
-    x1 = s1->cg_p;
-    x2 = s2->cg_p;
-    for(i=start; i<end; i++)
-      copy_rvec(x1[i],x2[i]);
-  }
-
-  if (DOMAINDECOMP(cr)) {
-    s2->ddp_count = s1->ddp_count;
-    if (s2->cg_gl_nalloc < s1->cg_gl_nalloc) {
-      s2->cg_gl_nalloc = s1->cg_gl_nalloc;
-      srenew(s2->cg_gl,s2->cg_gl_nalloc);
-    }
-    s2->ncg_gl = s1->ncg_gl;
-    for(i=0; i<s2->ncg_gl; i++)
-      s2->cg_gl[i] = s1->cg_gl[i];
-    s2->ddp_count_cg_gl = s1->ddp_count_cg_gl;
-  }
-
-  if (constr) {
-    wallcycle_start(wcycle,ewcCONSTR);
-    dvdlambda = 0;
-    constrain(NULL,TRUE,TRUE,constr,&top->idef,        
-              ir,NULL,cr,count,0,md,
-              s1->x,s2->x,NULL,s2->box,s2->lambda,
-              &dvdlambda,NULL,NULL,nrnb,econqCoord,FALSE,0,0);
-    wallcycle_stop(wcycle,ewcCONSTR);
-  }
-}
-
-static void do_x_step(t_commrec *cr,int n,rvec *x1,real a,rvec *f,rvec *x2)
-
-{
-  int  start,end,i,m;
-
-  if (DOMAINDECOMP(cr)) {
-    start = 0;
-    end   = cr->dd->nat_home;
-  } else if (PARTDECOMP(cr)) {
-    pd_at_range(cr,&start,&end);
-  } else {
-    start = 0;
-    end   = n;
-  }
-
-  for(i=start; i<end; i++) {
-    for(m=0; m<DIM; m++) {
-      x2[i][m] = x1[i][m] + a*f[i][m];
-    }
-  }
-}
-
-static void do_x_sub(t_commrec *cr,int n,rvec *x1,rvec *x2,real a,rvec *f)
-
-{
-  int  start,end,i,m;
-
-  if (DOMAINDECOMP(cr)) {
-    start = 0;
-    end   = cr->dd->nat_home;
-  } else if (PARTDECOMP(cr)) {
-    pd_at_range(cr,&start,&end);
-  } else {
-    start = 0;
-    end   = n;
-  }
-
-  for(i=start; i<end; i++) {
-    for(m=0; m<DIM; m++) {
-      f[i][m] = (x1[i][m] - x2[i][m])*a;
-    }
-  }
-}
-
-static void em_dd_partition_system(FILE *fplog,int step,t_commrec *cr,
-                                   gmx_mtop_t *top_global,t_inputrec *ir,
-                                   em_state_t *ems,gmx_localtop_t *top,
-                                   t_mdatoms *mdatoms,t_forcerec *fr,
-                                   gmx_vsite_t *vsite,gmx_constr_t constr,
-                                   t_nrnb *nrnb,gmx_wallcycle_t wcycle)
-{
-    /* Repartition the domain decomposition */
-    wallcycle_start(wcycle,ewcDOMDEC);
-    dd_partition_system(fplog,step,cr,FALSE,1,
-                        NULL,top_global,ir,
-                        &ems->s,&ems->f,
-                        mdatoms,top,fr,vsite,NULL,constr,
-                        nrnb,wcycle,FALSE);
-    dd_store_state(cr->dd,&ems->s);
-    wallcycle_stop(wcycle,ewcDOMDEC);
-}
-    
-static void evaluate_energy(FILE *fplog,gmx_bool bVerbose,t_commrec *cr,
-                            t_state *state_global,gmx_mtop_t *top_global,
-                            em_state_t *ems,gmx_localtop_t *top,
-                            t_inputrec *inputrec,
-                            t_nrnb *nrnb,gmx_wallcycle_t wcycle,
-                            gmx_global_stat_t gstat,
-                            gmx_vsite_t *vsite,gmx_constr_t constr,
-                            t_fcdata *fcd,
-                            t_graph *graph,t_mdatoms *mdatoms,
-                            t_forcerec *fr,rvec mu_tot,
-                            gmx_enerdata_t *enerd,tensor vir,tensor pres,
-                            gmx_large_int_t count,gmx_bool bFirst)
-{
-  real t;
-  gmx_bool bNS;
-  int  nabnsb;
-  tensor force_vir,shake_vir,ekin;
-  real dvdl,prescorr,enercorr,dvdlcorr;
-  real terminate=0;
-  
-  /* Set the time to the initial time, the time does not change during EM */
-  t = inputrec->init_t;
-
-  if (bFirst ||
-      (DOMAINDECOMP(cr) && ems->s.ddp_count < cr->dd->ddp_count)) {
-    /* This the first state or an old state used before the last ns */
-    bNS = TRUE;
-  } else {
-    bNS = FALSE;
-    if (inputrec->nstlist > 0) {
-      bNS = TRUE;
-    } else if (inputrec->nstlist == -1) {
-      nabnsb = natoms_beyond_ns_buffer(inputrec,fr,&top->cgs,NULL,ems->s.x);
-      if (PAR(cr))
-       gmx_sumi(1,&nabnsb,cr);
-      bNS = (nabnsb > 0);
-    }
-  }
-
-  if (vsite)
-    construct_vsites(fplog,vsite,ems->s.x,nrnb,1,NULL,
-                    top->idef.iparams,top->idef.il,
-                    fr->ePBC,fr->bMolPBC,graph,cr,ems->s.box);
-
-  if (DOMAINDECOMP(cr)) {
-    if (bNS) {
-      /* Repartition the domain decomposition */
-      em_dd_partition_system(fplog,count,cr,top_global,inputrec,
-                            ems,top,mdatoms,fr,vsite,constr,
-                            nrnb,wcycle);
-    }
-  }
-      
-    /* Calc force & energy on new trial position  */
-    /* do_force always puts the charge groups in the box and shifts again
-     * We do not unshift, so molecules are always whole in congrad.c
-     */
-    do_force(fplog,cr,inputrec,
-             count,nrnb,wcycle,top,top_global,&top_global->groups,
-             ems->s.box,ems->s.x,&ems->s.hist,
-             ems->f,force_vir,mdatoms,enerd,fcd,
-             ems->s.lambda,graph,fr,vsite,mu_tot,t,NULL,NULL,TRUE,
-             GMX_FORCE_STATECHANGED | GMX_FORCE_ALLFORCES | GMX_FORCE_VIRIAL |
-             (bNS ? GMX_FORCE_NS | GMX_FORCE_DOLR : 0));
-       
-  /* Clear the unused shake virial and pressure */
-  clear_mat(shake_vir);
-  clear_mat(pres);
-
-  /* Calculate long range corrections to pressure and energy */
-  calc_dispcorr(fplog,inputrec,fr,count,top_global->natoms,ems->s.box,ems->s.lambda,
-                pres,force_vir,&prescorr,&enercorr,&dvdlcorr);
-  /* don't think these next 4 lines  can be moved in for now, because we 
-     don't always want to write it -- figure out how to clean this up MRS 8/4/2009 */
-  enerd->term[F_DISPCORR] = enercorr;
-  enerd->term[F_EPOT] += enercorr;
-  enerd->term[F_PRES] += prescorr;
-  enerd->term[F_DVDL] += dvdlcorr;
-
-    /* Communicate stuff when parallel */
-    if (PAR(cr) && inputrec->eI != eiNM)
-    {
-        wallcycle_start(wcycle,ewcMoveE);
-
-        global_stat(fplog,gstat,cr,enerd,force_vir,shake_vir,mu_tot,
-                    inputrec,NULL,NULL,NULL,1,&terminate,
-                    top_global,&ems->s,FALSE,
-                    CGLO_ENERGY | 
-                    CGLO_PRESSURE | 
-                    CGLO_CONSTRAINT | 
-                    CGLO_FIRSTITERATE);
-
-        wallcycle_stop(wcycle,ewcMoveE);
-    }
-
-  ems->epot = enerd->term[F_EPOT];
-  
-  if (constr) {
-    /* Project out the constraint components of the force */
-    wallcycle_start(wcycle,ewcCONSTR);
-    dvdl = 0;
-    constrain(NULL,FALSE,FALSE,constr,&top->idef,
-              inputrec,NULL,cr,count,0,mdatoms,
-              ems->s.x,ems->f,ems->f,ems->s.box,ems->s.lambda,&dvdl,
-              NULL,&shake_vir,nrnb,econqForceDispl,FALSE,0,0);
-    if (fr->bSepDVDL && fplog)
-      fprintf(fplog,sepdvdlformat,"Constraints",t,dvdl);
-    enerd->term[F_DHDL_CON] += dvdl;
-    m_add(force_vir,shake_vir,vir);
-    wallcycle_stop(wcycle,ewcCONSTR);
-  } else {
-    copy_mat(force_vir,vir);
-  }
-
-  clear_mat(ekin);
-  enerd->term[F_PRES] =
-    calc_pres(fr->ePBC,inputrec->nwall,ems->s.box,ekin,vir,pres,
-             (fr->eeltype==eelPPPM)?enerd->term[F_COUL_RECIP]:0.0);
-
-  sum_dhdl(enerd,ems->s.lambda,inputrec);
-
-    if (EI_ENERGY_MINIMIZATION(inputrec->eI))
-    {
-        get_state_f_norm_max(cr,&(inputrec->opts),mdatoms,ems);
-    }
-}
-
-static double reorder_partsum(t_commrec *cr,t_grpopts *opts,t_mdatoms *mdatoms,
-                             gmx_mtop_t *mtop,
-                             em_state_t *s_min,em_state_t *s_b)
-{
-  rvec *fm,*fb,*fmg;
-  t_block *cgs_gl;
-  int ncg,*cg_gl,*index,c,cg,i,a0,a1,a,gf,m;
-  double partsum;
-  unsigned char *grpnrFREEZE;
-
-  if (debug)
-    fprintf(debug,"Doing reorder_partsum\n");
-
-  fm = s_min->f;
-  fb = s_b->f;
-
-  cgs_gl = dd_charge_groups_global(cr->dd);
-  index = cgs_gl->index;
-
-  /* Collect fm in a global vector fmg.
-   * This conflicts with the spirit of domain decomposition,
-   * but to fully optimize this a much more complicated algorithm is required.
-   */
-  snew(fmg,mtop->natoms);
-  
-  ncg   = s_min->s.ncg_gl;
-  cg_gl = s_min->s.cg_gl;
-  i = 0;
-  for(c=0; c<ncg; c++) {
-    cg = cg_gl[c];
-    a0 = index[cg];
-    a1 = index[cg+1];
-    for(a=a0; a<a1; a++) {
-      copy_rvec(fm[i],fmg[a]);
-      i++;
-    }
-  }
-  gmx_sum(mtop->natoms*3,fmg[0],cr);
-
-  /* Now we will determine the part of the sum for the cgs in state s_b */
-  ncg   = s_b->s.ncg_gl;
-  cg_gl = s_b->s.cg_gl;
-  partsum = 0;
-  i = 0;
-  gf = 0;
-  grpnrFREEZE = mtop->groups.grpnr[egcFREEZE];
-  for(c=0; c<ncg; c++) {
-    cg = cg_gl[c];
-    a0 = index[cg];
-    a1 = index[cg+1];
-    for(a=a0; a<a1; a++) {
-      if (mdatoms->cFREEZE && grpnrFREEZE) {
-       gf = grpnrFREEZE[i];
-      }
-      for(m=0; m<DIM; m++) {
-       if (!opts->nFreeze[gf][m]) {
-         partsum += (fb[i][m] - fmg[a][m])*fb[i][m];
-       }
-      }
-      i++;
-    }
-  }
-  
-  sfree(fmg);
-
-  return partsum;
-}
-
-static real pr_beta(t_commrec *cr,t_grpopts *opts,t_mdatoms *mdatoms,
-                   gmx_mtop_t *mtop,
-                   em_state_t *s_min,em_state_t *s_b)
-{
-  rvec *fm,*fb;
-  double sum;
-  int  gf,i,m;
-
-  /* This is just the classical Polak-Ribiere calculation of beta;
-   * it looks a bit complicated since we take freeze groups into account,
-   * and might have to sum it in parallel runs.
-   */
-  
-  if (!DOMAINDECOMP(cr) ||
-      (s_min->s.ddp_count == cr->dd->ddp_count &&
-       s_b->s.ddp_count   == cr->dd->ddp_count)) {
-    fm = s_min->f;
-    fb = s_b->f;
-    sum = 0;
-    gf = 0;
-    /* This part of code can be incorrect with DD,
-     * since the atom ordering in s_b and s_min might differ.
-     */
-    for(i=mdatoms->start; i<mdatoms->start+mdatoms->homenr; i++) {
-      if (mdatoms->cFREEZE)
-       gf = mdatoms->cFREEZE[i];
-      for(m=0; m<DIM; m++)
-       if (!opts->nFreeze[gf][m]) {
-         sum += (fb[i][m] - fm[i][m])*fb[i][m];
-       } 
-    }
-  } else {
-    /* We need to reorder cgs while summing */
-    sum = reorder_partsum(cr,opts,mdatoms,mtop,s_min,s_b);
-  }
-  if (PAR(cr))
-    gmx_sumd(1,&sum,cr);
-
-  return sum/sqr(s_min->fnorm);
-}
-
-double do_cg(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 *inputrec,
-             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_seed,
-             real cpt_period,real max_hours,
-             const char *deviceOptions,
-             unsigned long Flags,
-             gmx_runtime_t *runtime)
-{
-  const char *CG="Polak-Ribiere Conjugate Gradients";
-
-  em_state_t *s_min,*s_a,*s_b,*s_c;
-  gmx_localtop_t *top;
-  gmx_enerdata_t *enerd;
-  rvec   *f;
-  gmx_global_stat_t gstat;
-  t_graph    *graph;
-  rvec   *f_global,*p,*sf,*sfm;
-  double gpa,gpb,gpc,tmp,sum[2],minstep;
-  real   fnormn;
-  real   stepsize;     
-  real   a,b,c,beta=0.0;
-  real   epot_repl=0;
-  real   pnorm;
-  t_mdebin   *mdebin;
-  gmx_bool   converged,foundlower;
-  rvec   mu_tot;
-  gmx_bool   do_log=FALSE,do_ene=FALSE,do_x,do_f;
-  tensor vir,pres;
-  int    number_steps,neval=0,nstcg=inputrec->nstcgsteep;
-  gmx_mdoutf_t *outf;
-  int    i,m,gf,step,nminstep;
-  real   terminate=0;  
-
-  step=0;
-
-  s_min = init_em_state();
-  s_a   = init_em_state();
-  s_b   = init_em_state();
-  s_c   = init_em_state();
-
-  /* Init em and store the local state in s_min */
-  init_em(fplog,CG,cr,inputrec,
-          state_global,top_global,s_min,&top,&f,&f_global,
-          nrnb,mu_tot,fr,&enerd,&graph,mdatoms,&gstat,vsite,constr,
-          nfile,fnm,&outf,&mdebin);
-  
-  /* Print to log file */
-  print_em_start(fplog,cr,runtime,wcycle,CG);
-  
-  /* Max number of steps */
-  number_steps=inputrec->nsteps;
-
-  if (MASTER(cr))
-    sp_header(stderr,CG,inputrec->em_tol,number_steps);
-  if (fplog)
-    sp_header(fplog,CG,inputrec->em_tol,number_steps);
-
-  /* Call the force routine and some auxiliary (neighboursearching etc.) */
-  /* do_force always puts the charge groups in the box and shifts again
-   * We do not unshift, so molecules are always whole in congrad.c
-   */
-  evaluate_energy(fplog,bVerbose,cr,
-                 state_global,top_global,s_min,top,
-                 inputrec,nrnb,wcycle,gstat,
-                 vsite,constr,fcd,graph,mdatoms,fr,
-                 mu_tot,enerd,vir,pres,-1,TRUE);
-  where();
-
-  if (MASTER(cr)) {
-    /* Copy stuff to the energy bin for easy printing etc. */
-    upd_mdebin(mdebin,FALSE,FALSE,(double)step,
-              mdatoms->tmass,enerd,&s_min->s,s_min->s.box,
-              NULL,NULL,vir,pres,NULL,mu_tot,constr);
-    
-    print_ebin_header(fplog,step,step,s_min->s.lambda);
-    print_ebin(outf->fp_ene,TRUE,FALSE,FALSE,fplog,step,step,eprNORMAL,
-               TRUE,mdebin,fcd,&(top_global->groups),&(inputrec->opts));
-  }
-  where();
-
-  /* Estimate/guess the initial stepsize */
-  stepsize = inputrec->em_stepsize/s_min->fnorm;
-  if (MASTER(cr)) {
-    fprintf(stderr,"   F-max             = %12.5e on atom %d\n",
-           s_min->fmax,s_min->a_fmax+1);
-    fprintf(stderr,"   F-Norm            = %12.5e\n",
-           s_min->fnorm/sqrt(state_global->natoms));
-    fprintf(stderr,"\n");
-    /* and copy to the log file too... */
-    fprintf(fplog,"   F-max             = %12.5e on atom %d\n",
-           s_min->fmax,s_min->a_fmax+1);
-    fprintf(fplog,"   F-Norm            = %12.5e\n",
-           s_min->fnorm/sqrt(state_global->natoms));
-    fprintf(fplog,"\n");
-  }  
-  /* Start the loop over CG steps.             
-   * Each successful step is counted, and we continue until
-   * we either converge or reach the max number of steps.
-   */
-  converged = FALSE;
-  for(step=0; (number_steps<0 || (number_steps>=0 && step<=number_steps)) && !converged;step++) {
-    
-    /* start taking steps in a new direction 
-     * First time we enter the routine, beta=0, and the direction is 
-     * simply the negative gradient.
-     */
-
-    /* Calculate the new direction in p, and the gradient in this direction, gpa */
-    p  = s_min->s.cg_p;
-    sf = s_min->f;
-    gpa = 0;
-    gf = 0;
-    for(i=mdatoms->start; i<mdatoms->start+mdatoms->homenr; i++) {
-      if (mdatoms->cFREEZE) 
-       gf = mdatoms->cFREEZE[i];
-      for(m=0; m<DIM; m++) {
-       if (!inputrec->opts.nFreeze[gf][m]) {
-         p[i][m] = sf[i][m] + beta*p[i][m];
-         gpa -= p[i][m]*sf[i][m];
-         /* f is negative gradient, thus the sign */
-       } else {
-          p[i][m] = 0;
-       }
-      }
-    }
-    
-    /* Sum the gradient along the line across CPUs */
-    if (PAR(cr))
-      gmx_sumd(1,&gpa,cr);
-
-    /* Calculate the norm of the search vector */
-    get_f_norm_max(cr,&(inputrec->opts),mdatoms,p,&pnorm,NULL,NULL);
-    
-    /* Just in case stepsize reaches zero due to numerical precision... */
-    if(stepsize<=0)      
-      stepsize = inputrec->em_stepsize/pnorm;
-    
-    /* 
-     * Double check the value of the derivative in the search direction.
-     * If it is positive it must be due to the old information in the
-     * CG formula, so just remove that and start over with beta=0.
-     * This corresponds to a steepest descent step.
-     */
-    if(gpa>0) {
-      beta = 0;
-      step--; /* Don't count this step since we are restarting */
-      continue; /* Go back to the beginning of the big for-loop */
-    }
-
-    /* Calculate minimum allowed stepsize, before the average (norm)
-     * relative change in coordinate is smaller than precision
-     */
-    minstep=0;
-    for (i=mdatoms->start; i<mdatoms->start+mdatoms->homenr; i++) {
-      for(m=0; m<DIM; m++) {
-       tmp = fabs(s_min->s.x[i][m]);
-       if(tmp < 1.0)
-         tmp = 1.0;
-       tmp = p[i][m]/tmp;
-       minstep += tmp*tmp;
-      }
-    }
-    /* Add up from all CPUs */
-    if(PAR(cr))
-      gmx_sumd(1,&minstep,cr);
-
-    minstep = GMX_REAL_EPS/sqrt(minstep/(3*state_global->natoms));
-
-    if(stepsize<minstep) {
-      converged=TRUE;
-      break;
-    }
-    
-    /* Write coordinates if necessary */
-    do_x = do_per_step(step,inputrec->nstxout);
-    do_f = do_per_step(step,inputrec->nstfout);
-    
-    write_em_traj(fplog,cr,outf,do_x,do_f,NULL,
-                  top_global,inputrec,step,
-                  s_min,state_global,f_global);
-    
-    /* Take a step downhill.
-     * In theory, we should minimize the function along this direction.
-     * That is quite possible, but it turns out to take 5-10 function evaluations
-     * for each line. However, we dont really need to find the exact minimum -
-     * it is much better to start a new CG step in a modified direction as soon
-     * as we are close to it. This will save a lot of energy evaluations.
-     *
-     * In practice, we just try to take a single step.
-     * If it worked (i.e. lowered the energy), we increase the stepsize but
-     * the continue straight to the next CG step without trying to find any minimum.
-     * If it didn't work (higher energy), there must be a minimum somewhere between
-     * the old position and the new one.
-     * 
-     * Due to the finite numerical accuracy, it turns out that it is a good idea
-     * to even accept a SMALL increase in energy, if the derivative is still downhill.
-     * This leads to lower final energies in the tests I've done. / Erik 
-     */
-    s_a->epot = s_min->epot;
-    a = 0.0;
-    c = a + stepsize; /* reference position along line is zero */
-    
-    if (DOMAINDECOMP(cr) && s_min->s.ddp_count < cr->dd->ddp_count) {
-      em_dd_partition_system(fplog,step,cr,top_global,inputrec,
-                            s_min,top,mdatoms,fr,vsite,constr,
-                            nrnb,wcycle);
-    }
-
-    /* Take a trial step (new coords in s_c) */
-    do_em_step(cr,inputrec,mdatoms,s_min,c,s_min->s.cg_p,s_c,
-              constr,top,nrnb,wcycle,-1);
-    
-    neval++;
-    /* Calculate energy for the trial step */
-    evaluate_energy(fplog,bVerbose,cr,
-                   state_global,top_global,s_c,top,
-                   inputrec,nrnb,wcycle,gstat,
-                   vsite,constr,fcd,graph,mdatoms,fr,
-                   mu_tot,enerd,vir,pres,-1,FALSE);
-    
-    /* Calc derivative along line */
-    p  = s_c->s.cg_p;
-    sf = s_c->f;
-    gpc=0;
-    for(i=mdatoms->start; i<mdatoms->start+mdatoms->homenr; i++) {
-      for(m=0; m<DIM; m++) 
-         gpc -= p[i][m]*sf[i][m];  /* f is negative gradient, thus the sign */
-    }
-    /* Sum the gradient along the line across CPUs */
-    if (PAR(cr))
-      gmx_sumd(1,&gpc,cr);
-
-    /* This is the max amount of increase in energy we tolerate */
-    tmp=sqrt(GMX_REAL_EPS)*fabs(s_a->epot);
-
-    /* Accept the step if the energy is lower, or if it is not significantly higher
-     * and the line derivative is still negative.
-     */
-    if (s_c->epot < s_a->epot || (gpc < 0 && s_c->epot < (s_a->epot + tmp))) {
-      foundlower = TRUE;
-      /* Great, we found a better energy. Increase step for next iteration
-       * if we are still going down, decrease it otherwise
-       */
-      if(gpc<0)
-       stepsize *= 1.618034;  /* The golden section */
-      else
-       stepsize *= 0.618034;  /* 1/golden section */
-    } else {
-      /* New energy is the same or higher. We will have to do some work
-       * to find a smaller value in the interval. Take smaller step next time!
-       */
-      foundlower = FALSE;
-      stepsize *= 0.618034;
-    }    
-
-
-
-    
-    /* OK, if we didn't find a lower value we will have to locate one now - there must
-     * be one in the interval [a=0,c].
-     * The same thing is valid here, though: Don't spend dozens of iterations to find
-     * the line minimum. We try to interpolate based on the derivative at the endpoints,
-     * and only continue until we find a lower value. In most cases this means 1-2 iterations.
-     *
-     * I also have a safeguard for potentially really patological functions so we never
-     * take more than 20 steps before we give up ...
-     *
-     * If we already found a lower value we just skip this step and continue to the update.
-     */
-    if (!foundlower) {
-      nminstep=0;
-
-      do {
-       /* Select a new trial point.
-        * If the derivatives at points a & c have different sign we interpolate to zero,
-        * otherwise just do a bisection.
-        */
-       if(gpa<0 && gpc>0)
-         b = a + gpa*(a-c)/(gpc-gpa);
-       else
-         b = 0.5*(a+c);                
-       
-       /* safeguard if interpolation close to machine accuracy causes errors:
-        * never go outside the interval
-        */
-       if(b<=a || b>=c)
-         b = 0.5*(a+c);
-       
-       if (DOMAINDECOMP(cr) && s_min->s.ddp_count != cr->dd->ddp_count) {
-         /* Reload the old state */
-         em_dd_partition_system(fplog,-1,cr,top_global,inputrec,
-                                s_min,top,mdatoms,fr,vsite,constr,
-                                nrnb,wcycle);
-       }
-
-       /* Take a trial step to this new point - new coords in s_b */
-       do_em_step(cr,inputrec,mdatoms,s_min,b,s_min->s.cg_p,s_b,
-                  constr,top,nrnb,wcycle,-1);
-       
-       neval++;
-       /* Calculate energy for the trial step */
-       evaluate_energy(fplog,bVerbose,cr,
-                       state_global,top_global,s_b,top,
-                       inputrec,nrnb,wcycle,gstat,
-                       vsite,constr,fcd,graph,mdatoms,fr,
-                       mu_tot,enerd,vir,pres,-1,FALSE);
-       
-       /* p does not change within a step, but since the domain decomposition
-        * might change, we have to use cg_p of s_b here.
-        */
-       p  = s_b->s.cg_p;
-       sf = s_b->f;
-       gpb=0;
-       for(i=mdatoms->start; i<mdatoms->start+mdatoms->homenr; i++) {
-         for(m=0; m<DIM; m++)
-             gpb -= p[i][m]*sf[i][m];   /* f is negative gradient, thus the sign */
-       }
-       /* Sum the gradient along the line across CPUs */
-       if (PAR(cr))
-         gmx_sumd(1,&gpb,cr);
-       
-       if (debug)
-         fprintf(debug,"CGE: EpotA %f EpotB %f EpotC %f gpb %f\n",
-                 s_a->epot,s_b->epot,s_c->epot,gpb);
-
-       epot_repl = s_b->epot;
-       
-       /* Keep one of the intervals based on the value of the derivative at the new point */
-       if (gpb > 0) {
-         /* Replace c endpoint with b */
-         swap_em_state(s_b,s_c);
-         c = b;
-         gpc = gpb;
-       } else {
-         /* Replace a endpoint with b */
-         swap_em_state(s_b,s_a);
-         a = b;
-         gpa = gpb;
-       }
-       
-       /* 
-        * Stop search as soon as we find a value smaller than the endpoints.
-        * Never run more than 20 steps, no matter what.
-        */
-       nminstep++;
-      } while ((epot_repl > s_a->epot || epot_repl > s_c->epot) &&
-              (nminstep < 20));     
-      
-      if (fabs(epot_repl - s_min->epot) < fabs(s_min->epot)*GMX_REAL_EPS ||
-         nminstep >= 20) {
-       /* OK. We couldn't find a significantly lower energy.
-        * If beta==0 this was steepest descent, and then we give up.
-        * If not, set beta=0 and restart with steepest descent before quitting.
-         */
-       if (beta == 0.0) {
-         /* Converged */
-         converged = TRUE;
-         break;
-       } else {
-         /* Reset memory before giving up */
-         beta = 0.0;
-         continue;
-       }
-      }
-      
-      /* Select min energy state of A & C, put the best in B.
-       */
-      if (s_c->epot < s_a->epot) {
-       if (debug)
-         fprintf(debug,"CGE: C (%f) is lower than A (%f), moving C to B\n",
-                 s_c->epot,s_a->epot);
-       swap_em_state(s_b,s_c);
-       gpb = gpc;
-       b = c;
-      } else {
-       if (debug)
-         fprintf(debug,"CGE: A (%f) is lower than C (%f), moving A to B\n",
-                 s_a->epot,s_c->epot);
-       swap_em_state(s_b,s_a);
-       gpb = gpa;
-       b = a;
-      }
-      
-    } else {
-      if (debug)
-       fprintf(debug,"CGE: Found a lower energy %f, moving C to B\n",
-               s_c->epot);
-      swap_em_state(s_b,s_c);
-      gpb = gpc;
-      b = c;
-    }
-    
-    /* new search direction */
-    /* beta = 0 means forget all memory and restart with steepest descents. */
-    if (nstcg && ((step % nstcg)==0)) 
-      beta = 0.0;
-    else {
-      /* s_min->fnorm cannot be zero, because then we would have converged
-       * and broken out.
-       */
-
-      /* Polak-Ribiere update.
-       * Change to fnorm2/fnorm2_old for Fletcher-Reeves
-       */
-      beta = pr_beta(cr,&inputrec->opts,mdatoms,top_global,s_min,s_b);
-    }
-    /* Limit beta to prevent oscillations */
-    if (fabs(beta) > 5.0)
-      beta = 0.0;
-    
-    
-    /* update positions */
-    swap_em_state(s_min,s_b);
-    gpa = gpb;
-    
-    /* Print it if necessary */
-    if (MASTER(cr)) {
-      if(bVerbose)
-       fprintf(stderr,"\rStep %d, Epot=%12.6e, Fnorm=%9.3e, Fmax=%9.3e (atom %d)\n",
-               step,s_min->epot,s_min->fnorm/sqrt(state_global->natoms),
-               s_min->fmax,s_min->a_fmax+1);
-      /* Store the new (lower) energies */
-      upd_mdebin(mdebin,FALSE,FALSE,(double)step,
-                mdatoms->tmass,enerd,&s_min->s,s_min->s.box,
-                NULL,NULL,vir,pres,NULL,mu_tot,constr);
-      do_log = do_per_step(step,inputrec->nstlog);
-      do_ene = do_per_step(step,inputrec->nstenergy);
-      if(do_log)
-       print_ebin_header(fplog,step,step,s_min->s.lambda);
-      print_ebin(outf->fp_ene,do_ene,FALSE,FALSE,
-                do_log ? fplog : NULL,step,step,eprNORMAL,
-                TRUE,mdebin,fcd,&(top_global->groups),&(inputrec->opts));
-    }
-    
-    /* Stop when the maximum force lies below tolerance.
-     * If we have reached machine precision, converged is already set to true.
-     */        
-    converged = converged || (s_min->fmax < inputrec->em_tol);
-    
-  } /* End of the loop */
-  
-  if (converged)       
-    step--; /* we never took that last step in this case */
-  
-    if (s_min->fmax > inputrec->em_tol)
-    {
-        if (MASTER(cr))
-        {
-            warn_step(stderr,inputrec->em_tol,step-1==number_steps,FALSE);
-            warn_step(fplog ,inputrec->em_tol,step-1==number_steps,FALSE);
-        }
-        converged = FALSE; 
-    }
-  
-  if (MASTER(cr)) {
-    /* If we printed energy and/or logfile last step (which was the last step)
-     * we don't have to do it again, but otherwise print the final values.
-     */
-    if(!do_log) {
-      /* Write final value to log since we didn't do anything the last step */
-      print_ebin_header(fplog,step,step,s_min->s.lambda);
-    }
-    if (!do_ene || !do_log) {
-      /* Write final energy file entries */
-      print_ebin(outf->fp_ene,!do_ene,FALSE,FALSE,
-                !do_log ? fplog : NULL,step,step,eprNORMAL,
-                TRUE,mdebin,fcd,&(top_global->groups),&(inputrec->opts));
-    }
-  }
-
-  /* Print some stuff... */
-  if (MASTER(cr))
-    fprintf(stderr,"\nwriting lowest energy coordinates.\n");
-  
-  /* IMPORTANT!
-   * For accurate normal mode calculation it is imperative that we
-   * store the last conformation into the full precision binary trajectory.
-   *
-   * However, we should only do it if we did NOT already write this step
-   * above (which we did if do_x or do_f was true).
-   */  
-  do_x = !do_per_step(step,inputrec->nstxout);
-  do_f = (inputrec->nstfout > 0 && !do_per_step(step,inputrec->nstfout));
-  
-  write_em_traj(fplog,cr,outf,do_x,do_f,ftp2fn(efSTO,nfile,fnm),
-                top_global,inputrec,step,
-                s_min,state_global,f_global);
-  
-  fnormn = s_min->fnorm/sqrt(state_global->natoms);
-  
-  if (MASTER(cr)) {
-    print_converged(stderr,CG,inputrec->em_tol,step,converged,number_steps,
-                   s_min->epot,s_min->fmax,s_min->a_fmax,fnormn);
-    print_converged(fplog,CG,inputrec->em_tol,step,converged,number_steps,
-                   s_min->epot,s_min->fmax,s_min->a_fmax,fnormn);
-    
-    fprintf(fplog,"\nPerformed %d energy evaluations in total.\n",neval);
-  }
-  
-  finish_em(fplog,cr,outf,runtime,wcycle);
-  
-  /* To print the actual number of steps we needed somewhere */
-  runtime->nsteps_done = step;
-
-  return 0;
-} /* That's all folks */
-
-
-double do_lbfgs(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 *inputrec,
-                gmx_mtop_t *top_global,t_fcdata *fcd,
-                t_state *state,
-                t_mdatoms *mdatoms,
-                t_nrnb *nrnb,gmx_wallcycle_t wcycle,
-                gmx_edsam_t ed,
-                t_forcerec *fr,
-                int repl_ex_nst,int repl_ex_seed,
-                real cpt_period,real max_hours,
-                const char *deviceOptions,
-                unsigned long Flags,
-                gmx_runtime_t *runtime)
-{
-  static const char *LBFGS="Low-Memory BFGS Minimizer";
-  em_state_t ems;
-  gmx_localtop_t *top;
-  gmx_enerdata_t *enerd;
-  rvec   *f;
-  gmx_global_stat_t gstat;
-  t_graph    *graph;
-  rvec   *f_global;
-  int    ncorr,nmaxcorr,point,cp,neval,nminstep;
-  double stepsize,gpa,gpb,gpc,tmp,minstep;
-  real   *rho,*alpha,*ff,*xx,*p,*s,*lastx,*lastf,**dx,**dg;    
-  real   *xa,*xb,*xc,*fa,*fb,*fc,*xtmp,*ftmp;
-  real   a,b,c,maxdelta,delta;
-  real   diag,Epot0,Epot,EpotA,EpotB,EpotC;
-  real   dgdx,dgdg,sq,yr,beta;
-  t_mdebin   *mdebin;
-  gmx_bool   converged,first;
-  rvec   mu_tot;
-  real   fnorm,fmax;
-  gmx_bool   do_log,do_ene,do_x,do_f,foundlower,*frozen;
-  tensor vir,pres;
-  int    start,end,number_steps;
-  gmx_mdoutf_t *outf;
-  int    i,k,m,n,nfmax,gf,step;
-  /* not used */
-  real   terminate;
-
-  if (PAR(cr))
-    gmx_fatal(FARGS,"Cannot do parallel L-BFGS Minimization - yet.\n");
-  
-  n = 3*state->natoms;
-  nmaxcorr = inputrec->nbfgscorr;
-  
-  /* Allocate memory */
-  /* Use pointers to real so we dont have to loop over both atoms and
-   * dimensions all the time...
-   * x/f are allocated as rvec *, so make new x0/f0 pointers-to-real
-   * that point to the same memory.
-   */
-  snew(xa,n);
-  snew(xb,n);
-  snew(xc,n);
-  snew(fa,n);
-  snew(fb,n);
-  snew(fc,n);
-  snew(frozen,n);
-
-  snew(p,n); 
-  snew(lastx,n); 
-  snew(lastf,n); 
-  snew(rho,nmaxcorr);
-  snew(alpha,nmaxcorr);
-  
-  snew(dx,nmaxcorr);
-  for(i=0;i<nmaxcorr;i++)
-    snew(dx[i],n);
-  
-  snew(dg,nmaxcorr);
-  for(i=0;i<nmaxcorr;i++)
-    snew(dg[i],n);
-
-  step = 0;
-  neval = 0; 
-
-  /* Init em */
-  init_em(fplog,LBFGS,cr,inputrec,
-          state,top_global,&ems,&top,&f,&f_global,
-          nrnb,mu_tot,fr,&enerd,&graph,mdatoms,&gstat,vsite,constr,
-          nfile,fnm,&outf,&mdebin);
-  /* Do_lbfgs is not completely updated like do_steep and do_cg,
-   * so we free some memory again.
-   */
-  sfree(ems.s.x);
-  sfree(ems.f);
-
-  xx = (real *)state->x;
-  ff = (real *)f;
-
-  start = mdatoms->start;
-  end   = mdatoms->homenr + start;
-    
-  /* Print to log file */
-  print_em_start(fplog,cr,runtime,wcycle,LBFGS);
-  
-  do_log = do_ene = do_x = do_f = TRUE;
-  
-  /* Max number of steps */
-  number_steps=inputrec->nsteps;
-
-  /* Create a 3*natoms index to tell whether each degree of freedom is frozen */
-  gf = 0;
-  for(i=start; i<end; i++) {
-    if (mdatoms->cFREEZE)
-      gf = mdatoms->cFREEZE[i];
-     for(m=0; m<DIM; m++) 
-       frozen[3*i+m]=inputrec->opts.nFreeze[gf][m];  
-  }
-  if (MASTER(cr))
-    sp_header(stderr,LBFGS,inputrec->em_tol,number_steps);
-  if (fplog)
-    sp_header(fplog,LBFGS,inputrec->em_tol,number_steps);
-  
-  if (vsite)
-    construct_vsites(fplog,vsite,state->x,nrnb,1,NULL,
-                    top->idef.iparams,top->idef.il,
-                    fr->ePBC,fr->bMolPBC,graph,cr,state->box);
-  
-  /* Call the force routine and some auxiliary (neighboursearching etc.) */
-  /* do_force always puts the charge groups in the box and shifts again
-   * We do not unshift, so molecules are always whole
-   */
-  neval++;
-  ems.s.x = state->x;
-  ems.f = f;
-  evaluate_energy(fplog,bVerbose,cr,
-                 state,top_global,&ems,top,
-                 inputrec,nrnb,wcycle,gstat,
-                 vsite,constr,fcd,graph,mdatoms,fr,
-                 mu_tot,enerd,vir,pres,-1,TRUE);
-  where();
-       
-  if (MASTER(cr)) {
-    /* Copy stuff to the energy bin for easy printing etc. */
-    upd_mdebin(mdebin,FALSE,FALSE,(double)step,
-              mdatoms->tmass,enerd,state,state->box,
-              NULL,NULL,vir,pres,NULL,mu_tot,constr);
-    
-    print_ebin_header(fplog,step,step,state->lambda);
-    print_ebin(outf->fp_ene,TRUE,FALSE,FALSE,fplog,step,step,eprNORMAL,
-               TRUE,mdebin,fcd,&(top_global->groups),&(inputrec->opts));
-  }
-  where();
-  
-  /* This is the starting energy */
-  Epot = enerd->term[F_EPOT];
-  
-  fnorm = ems.fnorm;
-  fmax  = ems.fmax;
-  nfmax = ems.a_fmax;
-  
-  /* Set the initial step.
-   * since it will be multiplied by the non-normalized search direction 
-   * vector (force vector the first time), we scale it by the
-   * norm of the force.
-   */
-  
-  if (MASTER(cr)) {
-    fprintf(stderr,"Using %d BFGS correction steps.\n\n",nmaxcorr);
-    fprintf(stderr,"   F-max             = %12.5e on atom %d\n",fmax,nfmax+1);
-    fprintf(stderr,"   F-Norm            = %12.5e\n",fnorm/sqrt(state->natoms));
-    fprintf(stderr,"\n");
-    /* and copy to the log file too... */
-    fprintf(fplog,"Using %d BFGS correction steps.\n\n",nmaxcorr);
-    fprintf(fplog,"   F-max             = %12.5e on atom %d\n",fmax,nfmax+1);
-    fprintf(fplog,"   F-Norm            = %12.5e\n",fnorm/sqrt(state->natoms));
-    fprintf(fplog,"\n");
-  }   
-  
-  point=0;
-  for(i=0;i<n;i++)
-    if(!frozen[i])
-      dx[point][i] = ff[i];  /* Initial search direction */
-    else
-      dx[point][i] = 0;
-
-  stepsize = 1.0/fnorm;
-  converged = FALSE;
-  
-  /* Start the loop over BFGS steps.           
-   * Each successful step is counted, and we continue until
-   * we either converge or reach the max number of steps.
-   */
-  
-  ncorr=0;
-
-  /* Set the gradient from the force */
-  converged = FALSE;
-  for(step=0; (number_steps<0 || (number_steps>=0 && step<=number_steps)) && !converged; step++) {
-    
-    /* Write coordinates if necessary */
-    do_x = do_per_step(step,inputrec->nstxout);
-    do_f = do_per_step(step,inputrec->nstfout);
-    
-    write_traj(fplog,cr,outf,MDOF_X | MDOF_F,
-               top_global,step,(real)step,state,state,f,f,NULL,NULL);
-
-    /* Do the linesearching in the direction dx[point][0..(n-1)] */
-    
-    /* pointer to current direction - point=0 first time here */
-    s=dx[point];
-    
-    /* calculate line gradient */
-    for(gpa=0,i=0;i<n;i++) 
-       gpa-=s[i]*ff[i];
-
-    /* Calculate minimum allowed stepsize, before the average (norm) 
-     * relative change in coordinate is smaller than precision 
-     */
-    for(minstep=0,i=0;i<n;i++) {
-      tmp=fabs(xx[i]);
-      if(tmp<1.0)
-       tmp=1.0;
-      tmp = s[i]/tmp;
-      minstep += tmp*tmp;
-    }
-    minstep = GMX_REAL_EPS/sqrt(minstep/n);
-    
-    if(stepsize<minstep) {
-      converged=TRUE;
-      break;
-    }
-    
-    /* Store old forces and coordinates */
-    for(i=0;i<n;i++) {
-      lastx[i]=xx[i];
-      lastf[i]=ff[i];
-    }
-    Epot0=Epot;
-    
-    first=TRUE;
-    
-    for(i=0;i<n;i++)
-      xa[i]=xx[i];
-    
-    /* Take a step downhill.
-     * In theory, we should minimize the function along this direction.
-     * That is quite possible, but it turns out to take 5-10 function evaluations
-     * for each line. However, we dont really need to find the exact minimum -
-     * it is much better to start a new BFGS step in a modified direction as soon
-     * as we are close to it. This will save a lot of energy evaluations.
-     *
-     * In practice, we just try to take a single step.
-     * If it worked (i.e. lowered the energy), we increase the stepsize but
-     * the continue straight to the next BFGS step without trying to find any minimum.
-     * If it didn't work (higher energy), there must be a minimum somewhere between
-     * the old position and the new one.
-     * 
-     * Due to the finite numerical accuracy, it turns out that it is a good idea
-     * to even accept a SMALL increase in energy, if the derivative is still downhill.
-     * This leads to lower final energies in the tests I've done. / Erik 
-     */
-    foundlower=FALSE;
-    EpotA = Epot0;
-    a = 0.0;
-    c = a + stepsize; /* reference position along line is zero */
-
-    /* Check stepsize first. We do not allow displacements 
-     * larger than emstep.
-     */
-    do {
-      c = a + stepsize;
-      maxdelta=0;
-      for(i=0;i<n;i++) {
-       delta=c*s[i];
-       if(delta>maxdelta)
-         maxdelta=delta;
-      }
-      if(maxdelta>inputrec->em_stepsize)
-       stepsize*=0.1;
-    } while(maxdelta>inputrec->em_stepsize);
-
-    /* Take a trial step */
-    for (i=0; i<n; i++)
-      xc[i] = lastx[i] + c*s[i];
-    
-    neval++;
-    /* Calculate energy for the trial step */
-    ems.s.x = (rvec *)xc;
-    ems.f   = (rvec *)fc;
-    evaluate_energy(fplog,bVerbose,cr,
-                   state,top_global,&ems,top,
-                   inputrec,nrnb,wcycle,gstat,
-                   vsite,constr,fcd,graph,mdatoms,fr,
-                   mu_tot,enerd,vir,pres,step,FALSE);
-    EpotC = ems.epot;
-    
-    /* Calc derivative along line */
-    for(gpc=0,i=0; i<n; i++) {
-       gpc -= s[i]*fc[i];   /* f is negative gradient, thus the sign */
-    }
-    /* Sum the gradient along the line across CPUs */
-    if (PAR(cr))
-      gmx_sumd(1,&gpc,cr);
-    
-     /* This is the max amount of increase in energy we tolerate */
-   tmp=sqrt(GMX_REAL_EPS)*fabs(EpotA);
-    
-    /* Accept the step if the energy is lower, or if it is not significantly higher
-     * and the line derivative is still negative.
-     */
-    if(EpotC<EpotA || (gpc<0 && EpotC<(EpotA+tmp))) {
-      foundlower = TRUE;
-      /* Great, we found a better energy. Increase step for next iteration
-       * if we are still going down, decrease it otherwise
-       */
-      if(gpc<0)
-       stepsize *= 1.618034;  /* The golden section */
-      else
-       stepsize *= 0.618034;  /* 1/golden section */
-    } else {
-      /* New energy is the same or higher. We will have to do some work
-       * to find a smaller value in the interval. Take smaller step next time!
-       */
-      foundlower = FALSE;
-      stepsize *= 0.618034;
-    }    
-    
-    /* OK, if we didn't find a lower value we will have to locate one now - there must
-     * be one in the interval [a=0,c].
-     * The same thing is valid here, though: Don't spend dozens of iterations to find
-     * the line minimum. We try to interpolate based on the derivative at the endpoints,
-     * and only continue until we find a lower value. In most cases this means 1-2 iterations.
-     *
-     * I also have a safeguard for potentially really patological functions so we never
-     * take more than 20 steps before we give up ...
-     *
-     * If we already found a lower value we just skip this step and continue to the update.
-     */
-
-    if(!foundlower) {
-     
-      nminstep=0;
-      do {
-       /* Select a new trial point.
-        * If the derivatives at points a & c have different sign we interpolate to zero,
-        * otherwise just do a bisection.
-        */
-       
-       if(gpa<0 && gpc>0)
-         b = a + gpa*(a-c)/(gpc-gpa);
-       else
-         b = 0.5*(a+c);                
-       
-       /* safeguard if interpolation close to machine accuracy causes errors:
-        * never go outside the interval
-        */
-       if(b<=a || b>=c)
-         b = 0.5*(a+c);
-       
-       /* Take a trial step */
-       for (i=0; i<n; i++) 
-         xb[i] = lastx[i] + b*s[i];
-       
-       neval++;
-       /* Calculate energy for the trial step */
-       ems.s.x = (rvec *)xb;
-       ems.f   = (rvec *)fb;
-       evaluate_energy(fplog,bVerbose,cr,
-                       state,top_global,&ems,top,
-                       inputrec,nrnb,wcycle,gstat,
-                       vsite,constr,fcd,graph,mdatoms,fr,
-                       mu_tot,enerd,vir,pres,step,FALSE);
-       EpotB = ems.epot;
-       
-       fnorm = ems.fnorm;
-       
-       for(gpb=0,i=0; i<n; i++) 
-         gpb -= s[i]*fb[i];   /* f is negative gradient, thus the sign */
-       
-       /* Sum the gradient along the line across CPUs */
-       if (PAR(cr))
-         gmx_sumd(1,&gpb,cr);
-       
-       /* Keep one of the intervals based on the value of the derivative at the new point */
-       if(gpb>0) {
-         /* Replace c endpoint with b */
-         EpotC = EpotB;
-         c = b;
-         gpc = gpb;
-         /* swap coord pointers b/c */
-         xtmp = xb; 
-         ftmp = fb;
-         xb = xc; 
-         fb = fc;
-         xc = xtmp;
-         fc = ftmp;
-       } else {
-         /* Replace a endpoint with b */
-         EpotA = EpotB;
-         a = b;
-         gpa = gpb;
-         /* swap coord pointers a/b */
-         xtmp = xb; 
-         ftmp = fb;
-         xb = xa; 
-         fb = fa;
-         xa = xtmp; 
-         fa = ftmp;
-       }
-       
-       /* 
-        * Stop search as soon as we find a value smaller than the endpoints,
-        * or if the tolerance is below machine precision.
-        * Never run more than 20 steps, no matter what.
-        */
-       nminstep++; 
-      } while((EpotB>EpotA || EpotB>EpotC) && (nminstep<20));
-
-      if(fabs(EpotB-Epot0)<GMX_REAL_EPS || nminstep>=20) {
-       /* OK. We couldn't find a significantly lower energy.
-        * If ncorr==0 this was steepest descent, and then we give up.
-        * If not, reset memory to restart as steepest descent before quitting.
-         */
-       if(ncorr==0) {
-       /* Converged */
-         converged=TRUE;
-         break;
-       } else {
-         /* Reset memory */
-         ncorr=0;
-         /* Search in gradient direction */
-         for(i=0;i<n;i++)
-           dx[point][i]=ff[i];
-         /* Reset stepsize */
-         stepsize = 1.0/fnorm;
-         continue;
-       }
-      }
-      
-      /* Select min energy state of A & C, put the best in xx/ff/Epot
-       */
-      if(EpotC<EpotA) {
-       Epot = EpotC;
-       /* Use state C */
-       for(i=0;i<n;i++) {
-         xx[i]=xc[i];
-         ff[i]=fc[i];
-       }
-       stepsize=c;
-      } else {
-       Epot = EpotA;
-       /* Use state A */
-       for(i=0;i<n;i++) {
-         xx[i]=xa[i];
-         ff[i]=fa[i];
-       }
-       stepsize=a;
-      }
-      
-    } else {
-      /* found lower */
-      Epot = EpotC;
-      /* Use state C */
-      for(i=0;i<n;i++) {
-       xx[i]=xc[i];
-       ff[i]=fc[i];
-      }
-      stepsize=c;
-    }
-
-    /* Update the memory information, and calculate a new 
-     * approximation of the inverse hessian 
-     */
-    
-    /* Have new data in Epot, xx, ff */        
-    if(ncorr<nmaxcorr)
-      ncorr++;
-
-    for(i=0;i<n;i++) {
-      dg[point][i]=lastf[i]-ff[i];
-      dx[point][i]*=stepsize;
-    }
-    
-    dgdg=0;
-    dgdx=0;    
-    for(i=0;i<n;i++) {
-      dgdg+=dg[point][i]*dg[point][i];
-      dgdx+=dg[point][i]*dx[point][i];
-    }
-    
-    diag=dgdx/dgdg;
-    
-    rho[point]=1.0/dgdx;
-    point++;
-    
-    if(point>=nmaxcorr)
-      point=0;
-    
-    /* Update */
-    for(i=0;i<n;i++)
-      p[i]=ff[i];
-    
-    cp=point;
-    
-    /* Recursive update. First go back over the memory points */
-    for(k=0;k<ncorr;k++) {
-      cp--;
-      if(cp<0) 
-       cp=ncorr-1;
-      
-      sq=0;
-      for(i=0;i<n;i++)
-       sq+=dx[cp][i]*p[i];
-      
-      alpha[cp]=rho[cp]*sq;
-      
-      for(i=0;i<n;i++)
-       p[i] -= alpha[cp]*dg[cp][i];            
-    }
-    
-    for(i=0;i<n;i++)
-      p[i] *= diag;
-    
-    /* And then go forward again */
-    for(k=0;k<ncorr;k++) {
-      yr = 0;
-      for(i=0;i<n;i++)
-       yr += p[i]*dg[cp][i];
-      
-      beta = rho[cp]*yr;           
-      beta = alpha[cp]-beta;
-      
-      for(i=0;i<n;i++)
-       p[i] += beta*dx[cp][i];
-      
-      cp++;    
-      if(cp>=ncorr)
-       cp=0;
-    }
-    
-    for(i=0;i<n;i++)
-      if(!frozen[i])
-       dx[point][i] = p[i];
-      else
-       dx[point][i] = 0;
-
-    stepsize=1.0;
-    
-    /* Test whether the convergence criterion is met */
-    get_f_norm_max(cr,&(inputrec->opts),mdatoms,f,&fnorm,&fmax,&nfmax);
-    
-    /* Print it if necessary */
-    if (MASTER(cr)) {
-      if(bVerbose)
-       fprintf(stderr,"\rStep %d, Epot=%12.6e, Fnorm=%9.3e, Fmax=%9.3e (atom %d)\n",
-               step,Epot,fnorm/sqrt(state->natoms),fmax,nfmax+1);
-      /* Store the new (lower) energies */
-      upd_mdebin(mdebin,FALSE,FALSE,(double)step,
-                mdatoms->tmass,enerd,state,state->box,
-                NULL,NULL,vir,pres,NULL,mu_tot,constr);
-      do_log = do_per_step(step,inputrec->nstlog);
-      do_ene = do_per_step(step,inputrec->nstenergy);
-      if(do_log)
-       print_ebin_header(fplog,step,step,state->lambda);
-      print_ebin(outf->fp_ene,do_ene,FALSE,FALSE,
-                do_log ? fplog : NULL,step,step,eprNORMAL,
-                TRUE,mdebin,fcd,&(top_global->groups),&(inputrec->opts));
-    }
-    
-    /* Stop when the maximum force lies below tolerance.
-     * If we have reached machine precision, converged is already set to true.
-     */
-    
-    converged = converged || (fmax < inputrec->em_tol);
-    
-  } /* End of the loop */
-  
-  if(converged)        
-    step--; /* we never took that last step in this case */
-  
-    if(fmax>inputrec->em_tol)
-    {
-        if (MASTER(cr))
-        {
-            warn_step(stderr,inputrec->em_tol,step-1==number_steps,FALSE);
-            warn_step(fplog ,inputrec->em_tol,step-1==number_steps,FALSE);
-        }
-        converged = FALSE; 
-    }
-  
-  /* If we printed energy and/or logfile last step (which was the last step)
-   * we don't have to do it again, but otherwise print the final values.
-   */
-  if(!do_log) /* Write final value to log since we didn't do anythin last step */
-    print_ebin_header(fplog,step,step,state->lambda);
-  if(!do_ene || !do_log) /* Write final energy file entries */
-    print_ebin(outf->fp_ene,!do_ene,FALSE,FALSE,
-              !do_log ? fplog : NULL,step,step,eprNORMAL,
-              TRUE,mdebin,fcd,&(top_global->groups),&(inputrec->opts));
-  
-  /* Print some stuff... */
-  if (MASTER(cr))
-    fprintf(stderr,"\nwriting lowest energy coordinates.\n");
-  
-  /* IMPORTANT!
-   * For accurate normal mode calculation it is imperative that we
-   * store the last conformation into the full precision binary trajectory.
-   *
-   * However, we should only do it if we did NOT already write this step
-   * above (which we did if do_x or do_f was true).
-   */  
-  do_x = !do_per_step(step,inputrec->nstxout);
-  do_f = !do_per_step(step,inputrec->nstfout);
-  write_em_traj(fplog,cr,outf,do_x,do_f,ftp2fn(efSTO,nfile,fnm),
-                top_global,inputrec,step,
-                &ems,state,f);
-  
-  if (MASTER(cr)) {
-    print_converged(stderr,LBFGS,inputrec->em_tol,step,converged,
-                   number_steps,Epot,fmax,nfmax,fnorm/sqrt(state->natoms));
-    print_converged(fplog,LBFGS,inputrec->em_tol,step,converged,
-                   number_steps,Epot,fmax,nfmax,fnorm/sqrt(state->natoms));
-    
-    fprintf(fplog,"\nPerformed %d energy evaluations in total.\n",neval);
-  }
-  
-  finish_em(fplog,cr,outf,runtime,wcycle);
-
-  /* To print the actual number of steps we needed somewhere */
-  runtime->nsteps_done = step;
-
-  return 0;
-} /* That's all folks */
-
-
-double do_steep(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 *inputrec,
-                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_seed,
-                real cpt_period,real max_hours,
-                const char *deviceOptions,
-                unsigned long Flags,
-                gmx_runtime_t *runtime)
-{ 
-  const char *SD="Steepest Descents";
-  em_state_t *s_min,*s_try;
-  rvec       *f_global;
-  gmx_localtop_t *top;
-  gmx_enerdata_t *enerd;
-  rvec   *f;
-  gmx_global_stat_t gstat;
-  t_graph    *graph;
-  real   stepsize,constepsize;
-  real   ustep,dvdlambda,fnormn;
-  gmx_mdoutf_t *outf;
-  t_mdebin   *mdebin; 
-  gmx_bool   bDone,bAbort,do_x,do_f; 
-  tensor vir,pres; 
-  rvec   mu_tot;
-  int    nsteps;
-  int    count=0; 
-  int    steps_accepted=0; 
-  /* not used */
-  real   terminate=0;
-
-  s_min = init_em_state();
-  s_try = init_em_state();
-
-  /* Init em and store the local state in s_try */
-  init_em(fplog,SD,cr,inputrec,
-          state_global,top_global,s_try,&top,&f,&f_global,
-          nrnb,mu_tot,fr,&enerd,&graph,mdatoms,&gstat,vsite,constr,
-          nfile,fnm,&outf,&mdebin);
-       
-  /* Print to log file  */
-  print_em_start(fplog,cr,runtime,wcycle,SD);
-    
-  /* Set variables for stepsize (in nm). This is the largest  
-   * step that we are going to make in any direction. 
-   */
-  ustep = inputrec->em_stepsize; 
-  stepsize = 0;
-  
-  /* Max number of steps  */
-  nsteps = inputrec->nsteps; 
-  
-  if (MASTER(cr)) 
-    /* Print to the screen  */
-    sp_header(stderr,SD,inputrec->em_tol,nsteps);
-  if (fplog)
-    sp_header(fplog,SD,inputrec->em_tol,nsteps);
-    
-  /**** HERE STARTS THE LOOP ****
-   * count is the counter for the number of steps 
-   * bDone will be TRUE when the minimization has converged
-   * bAbort will be TRUE when nsteps steps have been performed or when
-   * the stepsize becomes smaller than is reasonable for machine precision
-   */
-  count  = 0;
-  bDone  = FALSE;
-  bAbort = FALSE;
-  while( !bDone && !bAbort ) {
-    bAbort = (nsteps >= 0) && (count == nsteps);
-    
-    /* set new coordinates, except for first step */
-    if (count > 0) {
-      do_em_step(cr,inputrec,mdatoms,s_min,stepsize,s_min->f,s_try,
-                constr,top,nrnb,wcycle,count);
-    }
-    
-    evaluate_energy(fplog,bVerbose,cr,
-                   state_global,top_global,s_try,top,
-                   inputrec,nrnb,wcycle,gstat,
-                   vsite,constr,fcd,graph,mdatoms,fr,
-                   mu_tot,enerd,vir,pres,count,count==0);
-        
-    if (MASTER(cr))
-      print_ebin_header(fplog,count,count,s_try->s.lambda);
-
-    if (count == 0)
-      s_min->epot = s_try->epot + 1;
-    
-    /* Print it if necessary  */
-    if (MASTER(cr)) {
-      if (bVerbose) {
-       fprintf(stderr,"Step=%5d, Dmax= %6.1e nm, Epot= %12.5e Fmax= %11.5e, atom= %d%c",
-               count,ustep,s_try->epot,s_try->fmax,s_try->a_fmax+1,
-               (s_try->epot < s_min->epot) ? '\n' : '\r');
-      }
-      
-      if (s_try->epot < s_min->epot) {
-       /* Store the new (lower) energies  */
-       upd_mdebin(mdebin,FALSE,FALSE,(double)count,
-                  mdatoms->tmass,enerd,&s_try->s,s_try->s.box,
-                  NULL,NULL,vir,pres,NULL,mu_tot,constr);
-       print_ebin(outf->fp_ene,TRUE,
-                  do_per_step(steps_accepted,inputrec->nstdisreout),
-                  do_per_step(steps_accepted,inputrec->nstorireout),
-                  fplog,count,count,eprNORMAL,TRUE,
-                  mdebin,fcd,&(top_global->groups),&(inputrec->opts));
-       fflush(fplog);
-      }
-    } 
-    
-    /* Now if the new energy is smaller than the previous...  
-     * or if this is the first step!
-     * or if we did random steps! 
-     */
-    
-    if ( (count==0) || (s_try->epot < s_min->epot) ) {
-      steps_accepted++; 
-
-      /* Test whether the convergence criterion is met...  */
-      bDone = (s_try->fmax < inputrec->em_tol);
-      
-      /* Copy the arrays for force, positions and energy  */
-      /* The 'Min' array always holds the coords and forces of the minimal 
-        sampled energy  */
-      swap_em_state(s_min,s_try);
-      if (count > 0)
-       ustep *= 1.2;
-
-      /* Write to trn, if necessary */
-      do_x = do_per_step(steps_accepted,inputrec->nstxout);
-      do_f = do_per_step(steps_accepted,inputrec->nstfout);
-      write_em_traj(fplog,cr,outf,do_x,do_f,NULL,
-                    top_global,inputrec,count,
-                    s_min,state_global,f_global);
-    } 
-    else {
-      /* If energy is not smaller make the step smaller...  */
-      ustep *= 0.5;
-
-      if (DOMAINDECOMP(cr) && s_min->s.ddp_count != cr->dd->ddp_count) {
-       /* Reload the old state */
-       em_dd_partition_system(fplog,count,cr,top_global,inputrec,
-                              s_min,top,mdatoms,fr,vsite,constr,
-                              nrnb,wcycle);
-      }
-    }
-    
-    /* Determine new step  */
-    stepsize = ustep/s_min->fmax;
-    
-    /* Check if stepsize is too small, with 1 nm as a characteristic length */
-#ifdef GMX_DOUBLE
-        if (count == nsteps || ustep < 1e-12)
-#else
-        if (count == nsteps || ustep < 1e-6)
-#endif
-        {
-            if (MASTER(cr))
-            {
-                warn_step(stderr,inputrec->em_tol,count==nsteps,constr!=NULL);
-                warn_step(fplog ,inputrec->em_tol,count==nsteps,constr!=NULL);
-            }
-            bAbort=TRUE;
-        }
-    
-    count++;
-  } /* End of the loop  */
-  
-    /* Print some shit...  */
-  if (MASTER(cr)) 
-    fprintf(stderr,"\nwriting lowest energy coordinates.\n"); 
-  write_em_traj(fplog,cr,outf,TRUE,inputrec->nstfout,ftp2fn(efSTO,nfile,fnm),
-               top_global,inputrec,count,
-               s_min,state_global,f_global);
-
-  fnormn = s_min->fnorm/sqrt(state_global->natoms);
-
-  if (MASTER(cr)) {
-    print_converged(stderr,SD,inputrec->em_tol,count,bDone,nsteps,
-                   s_min->epot,s_min->fmax,s_min->a_fmax,fnormn);
-    print_converged(fplog,SD,inputrec->em_tol,count,bDone,nsteps,
-                   s_min->epot,s_min->fmax,s_min->a_fmax,fnormn);
-  }
-
-  finish_em(fplog,cr,outf,runtime,wcycle);
-  
-  /* To print the actual number of steps we needed somewhere */
-  inputrec->nsteps=count;
-
-  runtime->nsteps_done = count;
-  
-  return 0;
-} /* That's all folks */
-
-
-double do_nm(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 *inputrec,
-             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_seed,
-             real cpt_period,real max_hours,
-             const char *deviceOptions,
-             unsigned long Flags,
-             gmx_runtime_t *runtime)
-{
-    const char *NM = "Normal Mode Analysis";
-    gmx_mdoutf_t *outf;
-    int        natoms,atom,d;
-    int        nnodes,node;
-    rvec       *f_global;
-    gmx_localtop_t *top;
-    gmx_enerdata_t *enerd;
-    rvec       *f;
-    gmx_global_stat_t gstat;
-    t_graph    *graph;
-    real       t,lambda;
-    gmx_bool       bNS;
-    tensor     vir,pres;
-    rvec       mu_tot;
-    rvec       *fneg,*dfdx;
-    gmx_bool       bSparse; /* use sparse matrix storage format */
-    size_t     sz;
-    gmx_sparsematrix_t * sparse_matrix = NULL;
-    real *     full_matrix             = NULL;
-    em_state_t *   state_work;
-       
-    /* added with respect to mdrun */
-    int        i,j,k,row,col;
-    real       der_range=10.0*sqrt(GMX_REAL_EPS);
-    real       x_min;
-    real       fnorm,fmax;
-    
-    if (constr != NULL)
-    {
-        gmx_fatal(FARGS,"Constraints present with Normal Mode Analysis, this combination is not supported");
-    }
-
-    state_work = init_em_state();
-    
-    /* Init em and store the local state in state_minimum */
-    init_em(fplog,NM,cr,inputrec,
-            state_global,top_global,state_work,&top,
-            &f,&f_global,
-            nrnb,mu_tot,fr,&enerd,&graph,mdatoms,&gstat,vsite,constr,
-            nfile,fnm,&outf,NULL);
-    
-    natoms = top_global->natoms;
-    snew(fneg,natoms);
-    snew(dfdx,natoms);
-    
-#ifndef GMX_DOUBLE
-    if (MASTER(cr))
-    {
-        fprintf(stderr,
-                "NOTE: This version of Gromacs has been compiled in single precision,\n"
-                "      which MIGHT not be accurate enough for normal mode analysis.\n"
-                "      Gromacs now uses sparse matrix storage, so the memory requirements\n"
-                "      are fairly modest even if you recompile in double precision.\n\n");
-    }
-#endif
-    
-    /* Check if we can/should use sparse storage format.
-     *
-     * Sparse format is only useful when the Hessian itself is sparse, which it
-      * will be when we use a cutoff.    
-      * For small systems (n<1000) it is easier to always use full matrix format, though.
-      */
-    if(EEL_FULL(fr->eeltype) || fr->rlist==0.0)
-    {
-        fprintf(stderr,"Non-cutoff electrostatics used, forcing full Hessian format.\n");
-        bSparse = FALSE;
-    }
-    else if(top_global->natoms < 1000)
-    {
-        fprintf(stderr,"Small system size (N=%d), using full Hessian format.\n",top_global->natoms);
-        bSparse = FALSE;
-    }
-    else
-    {
-        fprintf(stderr,"Using compressed symmetric sparse Hessian format.\n");
-        bSparse = TRUE;
-    }
-    
-    sz = DIM*top_global->natoms;
-    
-    fprintf(stderr,"Allocating Hessian memory...\n\n");
-
-    if(bSparse)
-    {
-        sparse_matrix=gmx_sparsematrix_init(sz);
-        sparse_matrix->compressed_symmetric = TRUE;
-    }
-    else
-    {
-        snew(full_matrix,sz*sz);
-    }
-    
-    /* Initial values */
-    t      = inputrec->init_t;
-    lambda = inputrec->init_lambda;
-    
-    init_nrnb(nrnb);
-    
-    where();
-    
-    /* Write start time and temperature */
-    print_em_start(fplog,cr,runtime,wcycle,NM);
-
-    /* fudge nr of steps to nr of atoms */
-    inputrec->nsteps = natoms*2;
-
-    if (MASTER(cr)) 
-    {
-        fprintf(stderr,"starting normal mode calculation '%s'\n%d steps.\n\n",
-                *(top_global->name),(int)inputrec->nsteps);
-    }
-
-    nnodes = cr->nnodes;
-   
-    /* Make evaluate_energy do a single node force calculation */
-    cr->nnodes = 1;
-    evaluate_energy(fplog,bVerbose,cr,
-                    state_global,top_global,state_work,top,
-                    inputrec,nrnb,wcycle,gstat,
-                    vsite,constr,fcd,graph,mdatoms,fr,
-                    mu_tot,enerd,vir,pres,-1,TRUE);
-    cr->nnodes = nnodes;
-
-    /* if forces are not small, warn user */
-    get_state_f_norm_max(cr,&(inputrec->opts),mdatoms,state_work);
-
-    if (MASTER(cr))
-    {
-        fprintf(stderr,"Maximum force:%12.5e\n",state_work->fmax);
-        if (state_work->fmax > 1.0e-3) 
-        {
-            fprintf(stderr,"Maximum force probably not small enough to");
-            fprintf(stderr," ensure that you are in an \nenergy well. ");
-            fprintf(stderr,"Be aware that negative eigenvalues may occur");
-            fprintf(stderr," when the\nresulting matrix is diagonalized.\n");
-        }
-    }
-    
-    /***********************************************************
-     *
-     *      Loop over all pairs in matrix 
-     * 
-     *      do_force called twice. Once with positive and 
-     *      once with negative displacement 
-     *
-     ************************************************************/
-
-    /* Steps are divided one by one over the nodes */
-    for(atom=cr->nodeid; atom<natoms; atom+=nnodes) 
-    {
-        
-        for (d=0; d<DIM; d++) 
-        {
-            x_min = state_work->s.x[atom][d];
-
-            state_work->s.x[atom][d] = x_min - der_range;
-          
-            /* Make evaluate_energy do a single node force calculation */
-            cr->nnodes = 1;
-            evaluate_energy(fplog,bVerbose,cr,
-                            state_global,top_global,state_work,top,
-                            inputrec,nrnb,wcycle,gstat,
-                            vsite,constr,fcd,graph,mdatoms,fr,
-                            mu_tot,enerd,vir,pres,atom*2,FALSE);
-                       
-            for(i=0; i<natoms; i++)
-            {
-                copy_rvec(state_work->f[i], fneg[i]);
-            }
-            
-            state_work->s.x[atom][d] = x_min + der_range;
-            
-            evaluate_energy(fplog,bVerbose,cr,
-                            state_global,top_global,state_work,top,
-                            inputrec,nrnb,wcycle,gstat,
-                            vsite,constr,fcd,graph,mdatoms,fr,
-                            mu_tot,enerd,vir,pres,atom*2+1,FALSE);
-            cr->nnodes = nnodes;
-
-            /* x is restored to original */
-            state_work->s.x[atom][d] = x_min;
-
-            for(j=0; j<natoms; j++) 
-            {
-                for (k=0; (k<DIM); k++) 
-                {
-                    dfdx[j][k] =
-                        -(state_work->f[j][k] - fneg[j][k])/(2*der_range);
-                }
-            }
-
-            if (!MASTER(cr))
-            {
-#ifdef GMX_MPI
-#ifdef GMX_DOUBLE
-#define mpi_type MPI_DOUBLE
-#else
-#define mpi_type MPI_FLOAT
-#endif
-                MPI_Send(dfdx[0],natoms*DIM,mpi_type,MASTERNODE(cr),cr->nodeid,
-                         cr->mpi_comm_mygroup);
-#endif
-            }
-            else
-            {
-                for(node=0; (node<nnodes && atom+node<natoms); node++)
-                {
-                    if (node > 0)
-                    {
-#ifdef GMX_MPI
-                        MPI_Status stat;
-                        MPI_Recv(dfdx[0],natoms*DIM,mpi_type,node,node,
-                                 cr->mpi_comm_mygroup,&stat);
-#undef mpi_type
-#endif
-                    }
-
-                    row = (atom + node)*DIM + d;
-
-                    for(j=0; j<natoms; j++) 
-                    {
-                        for(k=0; k<DIM; k++) 
-                        {
-                            col = j*DIM + k;
-                            
-                            if (bSparse)
-                            {
-                                if (col >= row && dfdx[j][k] != 0.0)
-                                {
-                                    gmx_sparsematrix_increment_value(sparse_matrix,
-                                                                     row,col,dfdx[j][k]);
-                                }
-                            }
-                            else
-                            {
-                                full_matrix[row*sz+col] = dfdx[j][k];
-                            }
-                        }
-                    }
-                }
-            }
-            
-            if (bVerbose && fplog)
-            {
-                fflush(fplog);            
-            }
-        }
-        /* write progress */
-        if (MASTER(cr) && bVerbose) 
-        {
-            fprintf(stderr,"\rFinished step %d out of %d",
-                    min(atom+nnodes,natoms),natoms); 
-            fflush(stderr);
-        }
-    }
-    
-    if (MASTER(cr)) 
-    {
-        fprintf(stderr,"\n\nWriting Hessian...\n");
-        gmx_mtxio_write(ftp2fn(efMTX,nfile,fnm),sz,sz,full_matrix,sparse_matrix);
-    }
-
-    finish_em(fplog,cr,outf,runtime,wcycle);
-
-    runtime->nsteps_done = natoms*2;
-    
-    return 0;
-}
diff --git a/src/mdlib/ns.c b/src/mdlib/ns.c
deleted file mode 100644 (file)
index f27ba3b..0000000
+++ /dev/null
@@ -1,2789 +0,0 @@
-/* -*- mode: c; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; c-file-style: "stroustrup"; -*-
- *
- * 
- *                This source code is part of
- * 
- *                 G   R   O   M   A   C   S
- * 
- *          GROningen MAchine for Chemical Simulations
- * 
- *                        VERSION 3.2.0
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
- * 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.
-
- * 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:
- * GROwing Monsters And Cloning Shrimps
- */
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#ifdef GMX_THREAD_SHM_FDECOMP
-#include <pthread.h> 
-#endif
-
-#include <math.h>
-#include <string.h>
-#include "sysstuff.h"
-#include "smalloc.h"
-#include "macros.h"
-#include "maths.h"
-#include "vec.h"
-#include "network.h"
-#include "nsgrid.h"
-#include "force.h"
-#include "nonbonded.h"
-#include "ns.h"
-#include "pbc.h"
-#include "names.h"
-#include "gmx_fatal.h"
-#include "nrnb.h"
-#include "txtdump.h"
-#include "mtop_util.h"
-
-#include "domdec.h"
-
-
-/* 
- *    E X C L U S I O N   H A N D L I N G
- */
-
-#ifdef DEBUG
-static void SETEXCL_(t_excl e[],atom_id i,atom_id j)
-{   e[j] = e[j] | (1<<i); }
-static void RMEXCL_(t_excl e[],atom_id i,atom_id j) 
-{ e[j]=e[j] & ~(1<<i); }
-static gmx_bool ISEXCL_(t_excl e[],atom_id i,atom_id j) 
-{ return (gmx_bool)(e[j] & (1<<i)); }
-static gmx_bool NOTEXCL_(t_excl e[],atom_id i,atom_id j)
-{  return !(ISEXCL(e,i,j)); }
-#else
-#define SETEXCL(e,i,j) (e)[((atom_id) (j))] |= (1<<((atom_id) (i)))
-#define RMEXCL(e,i,j)  (e)[((atom_id) (j))] &= (~(1<<((atom_id) (i))))
-#define ISEXCL(e,i,j)  (gmx_bool) ((e)[((atom_id) (j))] & (1<<((atom_id) (i))))
-#define NOTEXCL(e,i,j) !(ISEXCL(e,i,j))
-#endif
-
-/************************************************
- *
- *  U T I L I T I E S    F O R    N S
- *
- ************************************************/
-
-static void reallocate_nblist(t_nblist *nl)
-{
-    if (gmx_debug_at)
-    {
-        fprintf(debug,"reallocating neigborlist il_code=%d, maxnri=%d\n",
-                nl->il_code,nl->maxnri); 
-    }
-    srenew(nl->iinr,   nl->maxnri);
-    if (nl->enlist == enlistCG_CG)
-    {
-        srenew(nl->iinr_end,nl->maxnri);
-    }
-    srenew(nl->gid,    nl->maxnri);
-    srenew(nl->shift,  nl->maxnri);
-    srenew(nl->jindex, nl->maxnri+1);
-}
-
-/* ivdw/icoul are used to determine the type of interaction, so we
- * can set an innerloop index here. The obvious choice for this would have
- * been the vdwtype/coultype values in the forcerecord, but unfortunately 
- * those types are braindead - for instance both Buckingham and normal 
- * Lennard-Jones use the same value (evdwCUT), and a separate gmx_boolean variable
- * to determine which interaction is used. There is further no special value
- * for 'no interaction'. For backward compatibility with old TPR files we won't
- * change this in the 3.x series, so when calling this routine you should use:
- *
- * icoul=0 no coulomb interaction
- * icoul=1 cutoff standard coulomb
- * icoul=2 reaction-field coulomb
- * icoul=3 tabulated coulomb
- *
- * ivdw=0 no vdw interaction
- * ivdw=1 standard L-J interaction
- * ivdw=2 Buckingham
- * ivdw=3 tabulated vdw.
- *
- * Kind of ugly, but it works.
- */
-static void init_nblist(t_nblist *nl_sr,t_nblist *nl_lr,
-                        int maxsr,int maxlr,
-                        int ivdw, int icoul, 
-                        gmx_bool bfree, int enlist)
-{
-    t_nblist *nl;
-    int      homenr;
-    int      i,nn;
-    
-    int inloop[20] =
-    { 
-        eNR_NBKERNEL_NONE,
-        eNR_NBKERNEL010,
-        eNR_NBKERNEL020,
-        eNR_NBKERNEL030,
-        eNR_NBKERNEL100,
-        eNR_NBKERNEL110,
-        eNR_NBKERNEL120,
-        eNR_NBKERNEL130,
-        eNR_NBKERNEL200,
-        eNR_NBKERNEL210,
-        eNR_NBKERNEL220,
-        eNR_NBKERNEL230,
-        eNR_NBKERNEL300,
-        eNR_NBKERNEL310,
-        eNR_NBKERNEL320,
-        eNR_NBKERNEL330,
-        eNR_NBKERNEL400,
-        eNR_NBKERNEL410,
-        eNR_NBKERNEL_NONE,
-        eNR_NBKERNEL430
-    };
-  
-    for(i=0; (i<2); i++)
-    {
-        nl     = (i == 0) ? nl_sr : nl_lr;
-        homenr = (i == 0) ? maxsr : maxlr;
-
-        if (nl == NULL)
-        {
-            continue;
-        }
-        
-        /* Set coul/vdw in neighborlist, and for the normal loops we determine
-         * an index of which one to call.
-         */
-        nl->ivdw  = ivdw;
-        nl->icoul = icoul;
-        nl->free_energy = bfree;
-    
-        if (bfree)
-        {
-            nl->enlist  = enlistATOM_ATOM;
-            nl->il_code = eNR_NBKERNEL_FREE_ENERGY;
-        }
-        else
-        {
-            nl->enlist = enlist;
-
-            nn = inloop[4*icoul + ivdw];
-            
-            /* solvent loops follow directly after the corresponding
-            * ordinary loops, in the order:
-            *
-            * SPC, SPC-SPC, TIP4p, TIP4p-TIP4p
-            *   
-            */
-            switch (enlist) {
-            case enlistATOM_ATOM:
-            case enlistCG_CG:
-                break;
-            case enlistSPC_ATOM:     nn += 1; break;
-            case enlistSPC_SPC:      nn += 2; break;
-            case enlistTIP4P_ATOM:   nn += 3; break;
-            case enlistTIP4P_TIP4P:  nn += 4; break;
-            }
-            
-            nl->il_code = nn;
-        }
-
-        if (debug)
-            fprintf(debug,"Initiating neighbourlist type %d for %s interactions,\nwith %d SR, %d LR atoms.\n",
-                    nl->il_code,ENLISTTYPE(enlist),maxsr,maxlr);
-        
-        /* maxnri is influenced by the number of shifts (maximum is 8)
-         * and the number of energy groups.
-         * If it is not enough, nl memory will be reallocated during the run.
-         * 4 seems to be a reasonable factor, which only causes reallocation
-         * during runs with tiny and many energygroups.
-         */
-        nl->maxnri      = homenr*4;
-        nl->maxnrj      = 0;
-        nl->maxlen      = 0;
-        nl->nri         = -1;
-        nl->nrj         = 0;
-        nl->iinr        = NULL;
-        nl->gid         = NULL;
-        nl->shift       = NULL;
-        nl->jindex      = NULL;
-        reallocate_nblist(nl);
-        nl->jindex[0] = 0;
-#ifdef GMX_THREAD_SHM_FDECOMP
-        nl->counter = 0;
-        snew(nl->mtx,1);
-        pthread_mutex_init(nl->mtx,NULL);
-#endif
-    }
-}
-
-void init_neighbor_list(FILE *log,t_forcerec *fr,int homenr)
-{
-   /* Make maxlr tunable! (does not seem to be a big difference though) 
-    * This parameter determines the number of i particles in a long range 
-    * neighbourlist. Too few means many function calls, too many means
-    * cache trashing.
-    */
-   int maxsr,maxsr_wat,maxlr,maxlr_wat;
-   int icoul,icoulf,ivdw;
-   int solvent;
-   int enlist_def,enlist_w,enlist_ww;
-   int i;
-   t_nblists *nbl;
-
-   /* maxsr     = homenr-fr->nWatMol*3; */
-   maxsr     = homenr;
-
-   if (maxsr < 0)
-   {
-     gmx_fatal(FARGS,"%s, %d: Negative number of short range atoms.\n"
-                "Call your Gromacs dealer for assistance.",__FILE__,__LINE__);
-   }
-   /* This is just for initial allocation, so we do not reallocate
-    * all the nlist arrays many times in a row.
-    * The numbers seem very accurate, but they are uncritical.
-    */
-   maxsr_wat = min(fr->nWatMol,(homenr+2)/3); 
-   if (fr->bTwinRange) 
-   {
-       maxlr     = 50;
-       maxlr_wat = min(maxsr_wat,maxlr);
-   }
-   else
-   {
-     maxlr = maxlr_wat = 0;
-   }  
-
-   /* Determine the values for icoul/ivdw. */
-   /* Start with GB */
-   if(fr->bGB)
-   {
-       icoul=4;
-   }
-   else if (fr->bcoultab)
-   {
-       icoul = 3;
-   }
-   else if (EEL_RF(fr->eeltype))
-   {
-       icoul = 2;
-   }
-   else 
-   {
-       icoul = 1;
-   }
-   
-   if (fr->bvdwtab)
-   {
-       ivdw = 3;
-   }
-   else if (fr->bBHAM)
-   {
-       ivdw = 2;
-   }
-   else 
-   {
-       ivdw = 1;
-   }
-
-   fr->ns.bCGlist = (getenv("GMX_NBLISTCG") != 0);
-   if (!fr->ns.bCGlist)
-   {
-       enlist_def = enlistATOM_ATOM;
-   }
-   else
-   {
-       enlist_def = enlistCG_CG;
-       if (log != NULL)
-       {
-           fprintf(log,"\nUsing charge-group - charge-group neighbor lists and kernels\n\n");
-       }
-       if (!fr->bExcl_IntraCGAll_InterCGNone)
-       {
-           gmx_fatal(FARGS,"The charge-group - charge-group force loops only support systems with all intra-cg interactions excluded and no inter-cg exclusions, this is not the case for this system.");
-       }
-   }
-   
-   if (fr->solvent_opt == esolTIP4P) {
-       enlist_w  = enlistTIP4P_ATOM;
-       enlist_ww = enlistTIP4P_TIP4P;
-   } else {
-       enlist_w  = enlistSPC_ATOM;
-       enlist_ww = enlistSPC_SPC;
-   }
-
-   for(i=0; i<fr->nnblists; i++) 
-   {
-       nbl = &(fr->nblists[i]);
-       init_nblist(&nbl->nlist_sr[eNL_VDWQQ],&nbl->nlist_lr[eNL_VDWQQ],
-                   maxsr,maxlr,ivdw,icoul,FALSE,enlist_def);
-       init_nblist(&nbl->nlist_sr[eNL_VDW],&nbl->nlist_lr[eNL_VDW],
-                   maxsr,maxlr,ivdw,0,FALSE,enlist_def);
-       init_nblist(&nbl->nlist_sr[eNL_QQ],&nbl->nlist_lr[eNL_QQ],
-                   maxsr,maxlr,0,icoul,FALSE,enlist_def);
-       init_nblist(&nbl->nlist_sr[eNL_VDWQQ_WATER],&nbl->nlist_lr[eNL_VDWQQ_WATER],
-                   maxsr_wat,maxlr_wat,ivdw,icoul, FALSE,enlist_w);
-       init_nblist(&nbl->nlist_sr[eNL_QQ_WATER],&nbl->nlist_lr[eNL_QQ_WATER],
-                   maxsr_wat,maxlr_wat,0,icoul, FALSE,enlist_w);
-       init_nblist(&nbl->nlist_sr[eNL_VDWQQ_WATERWATER],&nbl->nlist_lr[eNL_VDWQQ_WATERWATER],
-                   maxsr_wat,maxlr_wat,ivdw,icoul, FALSE,enlist_ww);
-       init_nblist(&nbl->nlist_sr[eNL_QQ_WATERWATER],&nbl->nlist_lr[eNL_QQ_WATERWATER],
-                   maxsr_wat,maxlr_wat,0,icoul, FALSE,enlist_ww);
-       
-       if (fr->efep != efepNO) 
-       {
-           if (fr->bEwald)
-           {
-               icoulf = 5;
-           }
-           else
-           {
-               icoulf = icoul;
-           }
-
-           init_nblist(&nbl->nlist_sr[eNL_VDWQQ_FREE],&nbl->nlist_lr[eNL_VDWQQ_FREE],
-                       maxsr,maxlr,ivdw,icoulf,TRUE,enlistATOM_ATOM);
-           init_nblist(&nbl->nlist_sr[eNL_VDW_FREE],&nbl->nlist_lr[eNL_VDW_FREE],
-                       maxsr,maxlr,ivdw,0,TRUE,enlistATOM_ATOM);
-           init_nblist(&nbl->nlist_sr[eNL_QQ_FREE],&nbl->nlist_lr[eNL_QQ_FREE],
-                       maxsr,maxlr,0,icoulf,TRUE,enlistATOM_ATOM);
-       }  
-   }
-   /* QMMM MM list */
-   if (fr->bQMMM && fr->qr->QMMMscheme != eQMMMschemeoniom)
-   {
-       init_nblist(&fr->QMMMlist,NULL,
-                   maxsr,maxlr,0,icoul,FALSE,enlistATOM_ATOM);
-   }
-
-   fr->ns.nblist_initialized=TRUE;
-}
-
-static void reset_nblist(t_nblist *nl)
-{
-     nl->nri       = -1;
-     nl->nrj       = 0;
-     nl->maxlen    = 0;
-     if (nl->jindex)
-     {
-         nl->jindex[0] = 0;
-     }
-}
-
-static void reset_neighbor_list(t_forcerec *fr,gmx_bool bLR,int nls,int eNL)
-{
-    int n,i;
-  
-    if (bLR) 
-    {
-        reset_nblist(&(fr->nblists[nls].nlist_lr[eNL]));
-    }
-    else 
-    {
-        for(n=0; n<fr->nnblists; n++)
-        {
-            for(i=0; i<eNL_NR; i++)
-            {
-                reset_nblist(&(fr->nblists[n].nlist_sr[i]));
-            }
-        }
-        if (fr->bQMMM)
-        { 
-            /* only reset the short-range nblist */
-            reset_nblist(&(fr->QMMMlist));
-        }
-    }
-}
-
-
-
-
-static inline void new_i_nblist(t_nblist *nlist,
-                                gmx_bool bLR,atom_id i_atom,int shift,int gid)
-{
-    int    i,k,nri,nshift;
-    
-    nri = nlist->nri;
-    
-    /* Check whether we have to increase the i counter */
-    if ((nri == -1) ||
-        (nlist->iinr[nri]  != i_atom) || 
-        (nlist->shift[nri] != shift) || 
-        (nlist->gid[nri]   != gid))
-    {
-        /* This is something else. Now see if any entries have 
-         * been added in the list of the previous atom.
-         */
-        if ((nri == -1) ||
-            ((nlist->jindex[nri+1] > nlist->jindex[nri]) && 
-             (nlist->gid[nri] != -1)))
-        {
-            /* If so increase the counter */
-            nlist->nri++;
-            nri++;
-            if (nlist->nri >= nlist->maxnri)
-            {
-                nlist->maxnri += over_alloc_large(nlist->nri);
-                reallocate_nblist(nlist);
-            }
-        }
-        /* Set the number of neighbours and the atom number */
-        nlist->jindex[nri+1] = nlist->jindex[nri];
-        nlist->iinr[nri]     = i_atom;
-        nlist->gid[nri]      = gid;
-        nlist->shift[nri]    = shift;
-    }
-}
-
-static inline void close_i_nblist(t_nblist *nlist) 
-{
-    int nri = nlist->nri;
-    int len;
-    
-    if (nri >= 0)
-    {
-        nlist->jindex[nri+1] = nlist->nrj;
-        
-        len=nlist->nrj -  nlist->jindex[nri];
-        
-        /* nlist length for water i molecules is treated statically 
-         * in the innerloops 
-         */
-        if (len > nlist->maxlen)
-        {
-            nlist->maxlen = len;
-        }
-    }
-}
-
-static inline void close_nblist(t_nblist *nlist)
-{
-    /* Only close this nblist when it has been initialized.
-     * Avoid the creation of i-lists with no j-particles.
-     */
-    if (nlist->nrj == 0)
-    {
-        /* Some assembly kernels do not support empty lists,
-         * make sure here that we don't generate any empty lists.
-         * With the current ns code this branch is taken in two cases:
-         * No i-particles at all: nri=-1 here
-         * There are i-particles, but no j-particles; nri=0 here
-         */
-        nlist->nri = 0;
-    }
-    else
-    {
-        /* Close list number nri by incrementing the count */
-        nlist->nri++;
-    }
-}
-
-static inline void close_neighbor_list(t_forcerec *fr,gmx_bool bLR,int nls,int eNL, 
-                                       gmx_bool bMakeQMMMnblist)
-{
-    int n,i;
-    
-    if (bMakeQMMMnblist) {
-        if (!bLR)
-        {
-            close_nblist(&(fr->QMMMlist));
-        }
-    }
-    else 
-    {
-        if (bLR)
-        {
-            close_nblist(&(fr->nblists[nls].nlist_lr[eNL]));
-        }
-        else
-        { 
-            for(n=0; n<fr->nnblists; n++)
-            {
-                for(i=0; (i<eNL_NR); i++)
-                {
-                    close_nblist(&(fr->nblists[n].nlist_sr[i]));
-                }
-            }
-        }
-    }
-}
-
-static inline void add_j_to_nblist(t_nblist *nlist,atom_id j_atom,gmx_bool bLR)
-{
-    int nrj=nlist->nrj;
-    
-    if (nlist->nrj >= nlist->maxnrj)
-    {
-        nlist->maxnrj = over_alloc_small(nlist->nrj + 1);
-        if (gmx_debug_at)
-            fprintf(debug,"Increasing %s nblist %s j size to %d\n",
-                    bLR ? "LR" : "SR",nrnb_str(nlist->il_code),nlist->maxnrj);
-        
-        srenew(nlist->jjnr,nlist->maxnrj);
-    }
-
-    nlist->jjnr[nrj] = j_atom;
-    nlist->nrj ++;
-}
-
-static inline void add_j_to_nblist_cg(t_nblist *nlist,
-                                      atom_id j_start,int j_end,
-                                      t_excl *bexcl,gmx_bool bLR)
-{
-    int nrj=nlist->nrj;
-    int j;
-
-    if (nlist->nrj >= nlist->maxnrj)
-    {
-        nlist->maxnrj = over_alloc_small(nlist->nrj + 1);
-        if (gmx_debug_at)
-            fprintf(debug,"Increasing %s nblist %s j size to %d\n",
-                    bLR ? "LR" : "SR",nrnb_str(nlist->il_code),nlist->maxnrj);
-        
-        srenew(nlist->jjnr    ,nlist->maxnrj);
-        srenew(nlist->jjnr_end,nlist->maxnrj);
-        srenew(nlist->excl    ,nlist->maxnrj*MAX_CGCGSIZE);
-    }
-
-    nlist->jjnr[nrj]     = j_start;
-    nlist->jjnr_end[nrj] = j_end;
-
-    if (j_end - j_start > MAX_CGCGSIZE)
-    {
-        gmx_fatal(FARGS,"The charge-group - charge-group neighborlist do not support charge groups larger than %d, found a charge group of size %d",MAX_CGCGSIZE,j_end-j_start);
-    }
-
-    /* Set the exclusions */
-    for(j=j_start; j<j_end; j++)
-    {
-        nlist->excl[nrj*MAX_CGCGSIZE + j - j_start] = bexcl[j];
-    }
-
-    nlist->nrj ++;
-}
-
-typedef void
-put_in_list_t(gmx_bool              bHaveVdW[],
-              int               ngid,
-              t_mdatoms *       md,
-              int               icg,
-              int               jgid,
-              int               nj,
-              atom_id           jjcg[],
-              atom_id           index[],
-              t_excl            bExcl[],
-              int               shift,
-              t_forcerec *      fr,
-              gmx_bool              bLR,
-              gmx_bool              bDoVdW,
-              gmx_bool              bDoCoul);
-
-static void 
-put_in_list_at(gmx_bool              bHaveVdW[],
-               int               ngid,
-               t_mdatoms *       md,
-               int               icg,
-               int               jgid,
-               int               nj,
-               atom_id           jjcg[],
-               atom_id           index[],
-               t_excl            bExcl[],
-               int               shift,
-               t_forcerec *      fr,
-               gmx_bool              bLR,
-               gmx_bool              bDoVdW,
-               gmx_bool              bDoCoul)
-{
-    /* The a[] index has been removed,
-     * to put it back in i_atom should be a[i0] and jj should be a[jj].
-     */
-    t_nblist *   vdwc;
-    t_nblist *   vdw;
-    t_nblist *   coul;
-    t_nblist *   vdwc_free  = NULL;
-    t_nblist *   vdw_free   = NULL;
-    t_nblist *   coul_free  = NULL;
-    t_nblist *   vdwc_ww    = NULL;
-    t_nblist *   coul_ww    = NULL;
-    
-    int            i,j,jcg,igid,gid,nbl_ind,ind_ij;
-    atom_id   jj,jj0,jj1,i_atom;
-    int       i0,nicg,len;
-    
-    int       *cginfo;
-    int       *type,*typeB;
-    real      *charge,*chargeB;
-    real      qi,qiB,qq,rlj;
-    gmx_bool      bFreeEnergy,bFree,bFreeJ,bNotEx,*bPert;
-    gmx_bool      bDoVdW_i,bDoCoul_i,bDoCoul_i_sol;
-    int       iwater,jwater;
-    t_nblist  *nlist;
-    
-    /* Copy some pointers */
-    cginfo  = fr->cginfo;
-    charge  = md->chargeA;
-    chargeB = md->chargeB;
-    type    = md->typeA;
-    typeB   = md->typeB;
-    bPert   = md->bPerturbed;
-    
-    /* Get atom range */
-    i0     = index[icg];
-    nicg   = index[icg+1]-i0;
-    
-    /* Get the i charge group info */
-    igid   = GET_CGINFO_GID(cginfo[icg]);
-    iwater = GET_CGINFO_SOLOPT(cginfo[icg]);
-    
-    bFreeEnergy = FALSE;
-    if (md->nPerturbed) 
-    {
-        /* Check if any of the particles involved are perturbed. 
-         * If not we can do the cheaper normal put_in_list
-         * and use more solvent optimization.
-         */
-        for(i=0; i<nicg; i++)
-        {
-            bFreeEnergy |= bPert[i0+i];
-        }
-        /* Loop over the j charge groups */
-        for(j=0; (j<nj && !bFreeEnergy); j++) 
-        {
-            jcg = jjcg[j];
-            jj0 = index[jcg];
-            jj1 = index[jcg+1];
-            /* Finally loop over the atoms in the j-charge group */    
-            for(jj=jj0; jj<jj1; jj++)
-            {
-                bFreeEnergy |= bPert[jj];
-            }
-        }
-    }
-    
-    /* Unpack pointers to neighbourlist structs */
-    if (fr->nnblists == 1)
-    {
-        nbl_ind = 0;
-    }
-    else
-    {
-        nbl_ind = fr->gid2nblists[GID(igid,jgid,ngid)];
-    }
-    if (bLR)
-    {
-        nlist = fr->nblists[nbl_ind].nlist_lr;
-    }
-    else
-    {
-        nlist = fr->nblists[nbl_ind].nlist_sr;
-    }
-    
-    if (iwater != esolNO)
-    {
-        vdwc = &nlist[eNL_VDWQQ_WATER];
-        vdw  = &nlist[eNL_VDW];
-        coul = &nlist[eNL_QQ_WATER];
-#ifndef DISABLE_WATERWATER_NLIST
-        vdwc_ww = &nlist[eNL_VDWQQ_WATERWATER];
-        coul_ww = &nlist[eNL_QQ_WATERWATER];
-#endif
-    } 
-    else 
-    {
-        vdwc = &nlist[eNL_VDWQQ];
-        vdw  = &nlist[eNL_VDW];
-        coul = &nlist[eNL_QQ];
-    }
-    
-    if (!bFreeEnergy) 
-    {
-        if (iwater != esolNO) 
-        {
-            /* Loop over the atoms in the i charge group */    
-            i_atom  = i0;
-            gid     = GID(igid,jgid,ngid);
-            /* Create new i_atom for each energy group */
-            if (bDoCoul && bDoVdW)
-            {
-                new_i_nblist(vdwc,bLR,i_atom,shift,gid);
-#ifndef DISABLE_WATERWATER_NLIST
-                new_i_nblist(vdwc_ww,bLR,i_atom,shift,gid);
-#endif
-            }
-            if (bDoVdW)
-            {
-                new_i_nblist(vdw,bLR,i_atom,shift,gid);
-            }
-            if (bDoCoul) 
-            {
-                new_i_nblist(coul,bLR,i_atom,shift,gid);
-#ifndef DISABLE_WATERWATER_NLIST
-                new_i_nblist(coul_ww,bLR,i_atom,shift,gid);
-#endif
-            }      
-         /* Loop over the j charge groups */
-            for(j=0; (j<nj); j++) 
-            {
-                jcg=jjcg[j];
-                
-                if (jcg == icg)
-                {
-                    continue;
-                }
-                
-                jj0 = index[jcg];
-                jwater = GET_CGINFO_SOLOPT(cginfo[jcg]);
-                
-                if (iwater == esolSPC && jwater == esolSPC)
-                {
-                    /* Interaction between two SPC molecules */
-                    if (!bDoCoul)
-                    {
-                        /* VdW only - only first atoms in each water interact */
-                        add_j_to_nblist(vdw,jj0,bLR);
-                    }
-                    else 
-                    {
-#ifdef DISABLE_WATERWATER_NLIST        
-                        /* Add entries for the three atoms - only do VdW if we need to */
-                        if (!bDoVdW)
-                        {
-                            add_j_to_nblist(coul,jj0,bLR);
-                        }
-                        else
-                        {
-                            add_j_to_nblist(vdwc,jj0,bLR);
-                        }
-                        add_j_to_nblist(coul,jj0+1,bLR);
-                        add_j_to_nblist(coul,jj0+2,bLR);           
-#else
-                        /* One entry for the entire water-water interaction */
-                        if (!bDoVdW)
-                        {
-                            add_j_to_nblist(coul_ww,jj0,bLR);
-                        }
-                        else
-                        {
-                            add_j_to_nblist(vdwc_ww,jj0,bLR);
-                        }
-#endif
-                    }  
-                } 
-                else if (iwater == esolTIP4P && jwater == esolTIP4P) 
-                {
-                    /* Interaction between two TIP4p molecules */
-                    if (!bDoCoul)
-                    {
-                        /* VdW only - only first atoms in each water interact */
-                        add_j_to_nblist(vdw,jj0,bLR);
-                    }
-                    else 
-                    {
-#ifdef DISABLE_WATERWATER_NLIST        
-                        /* Add entries for the four atoms - only do VdW if we need to */
-                        if (bDoVdW)
-                        {
-                            add_j_to_nblist(vdw,jj0,bLR);
-                        }
-                        add_j_to_nblist(coul,jj0+1,bLR);
-                        add_j_to_nblist(coul,jj0+2,bLR);           
-                        add_j_to_nblist(coul,jj0+3,bLR);           
-#else
-                        /* One entry for the entire water-water interaction */
-                        if (!bDoVdW)
-                        {
-                            add_j_to_nblist(coul_ww,jj0,bLR);
-                        }
-                        else
-                        {
-                            add_j_to_nblist(vdwc_ww,jj0,bLR);
-                        }
-#endif
-                    }                                          
-                }
-                else 
-                {
-                    /* j charge group is not water, but i is.
-                     * Add entries to the water-other_atom lists; the geometry of the water
-                     * molecule doesn't matter - that is taken care of in the nonbonded kernel,
-                     * so we don't care if it is SPC or TIP4P...
-                     */
-                    
-                    jj1 = index[jcg+1];
-                    
-                    if (!bDoVdW) 
-                    {
-                        for(jj=jj0; (jj<jj1); jj++) 
-                        {
-                            if (charge[jj] != 0)
-                            {
-                                add_j_to_nblist(coul,jj,bLR);
-                            }
-                        }
-                    }
-                    else if (!bDoCoul)
-                    {
-                        for(jj=jj0; (jj<jj1); jj++)
-                        {
-                            if (bHaveVdW[type[jj]])
-                            {
-                                add_j_to_nblist(vdw,jj,bLR);
-                            }
-                        }
-                    }
-                    else 
-                    {
-                        /* _charge_ _groups_ interact with both coulomb and LJ */
-                        /* Check which atoms we should add to the lists!       */
-                        for(jj=jj0; (jj<jj1); jj++) 
-                        {
-                            if (bHaveVdW[type[jj]]) 
-                            {
-                                if (charge[jj] != 0)
-                                {
-                                    add_j_to_nblist(vdwc,jj,bLR);
-                                }
-                                else
-                                {
-                                    add_j_to_nblist(vdw,jj,bLR);
-                                }
-                            }
-                            else if (charge[jj] != 0)
-                            {
-                                add_j_to_nblist(coul,jj,bLR);
-                            }
-                        }
-                    }
-                }
-            }
-            close_i_nblist(vdw); 
-            close_i_nblist(coul); 
-            close_i_nblist(vdwc);  
-#ifndef DISABLE_WATERWATER_NLIST
-            close_i_nblist(coul_ww);
-            close_i_nblist(vdwc_ww); 
-#endif
-        } 
-        else
-        { 
-            /* no solvent as i charge group */
-            /* Loop over the atoms in the i charge group */    
-            for(i=0; i<nicg; i++) 
-            {
-                i_atom  = i0+i;
-                gid     = GID(igid,jgid,ngid);
-                qi      = charge[i_atom];
-                
-                /* Create new i_atom for each energy group */
-                if (bDoVdW && bDoCoul)
-                {
-                    new_i_nblist(vdwc,bLR,i_atom,shift,gid);
-                }
-                if (bDoVdW)
-                {
-                    new_i_nblist(vdw,bLR,i_atom,shift,gid);
-                }
-                if (bDoCoul)
-                {
-                    new_i_nblist(coul,bLR,i_atom,shift,gid);
-                }
-                bDoVdW_i  = (bDoVdW  && bHaveVdW[type[i_atom]]);
-                bDoCoul_i = (bDoCoul && qi!=0);
-                
-                if (bDoVdW_i || bDoCoul_i) 
-                {
-                    /* Loop over the j charge groups */
-                    for(j=0; (j<nj); j++) 
-                    {
-                        jcg=jjcg[j];
-                        
-                        /* Check for large charge groups */
-                        if (jcg == icg)
-                        {
-                            jj0 = i0 + i + 1;
-                        }
-                        else
-                        {
-                            jj0 = index[jcg];
-                        }
-                        
-                        jj1=index[jcg+1];
-                        /* Finally loop over the atoms in the j-charge group */        
-                        for(jj=jj0; jj<jj1; jj++) 
-                        {
-                            bNotEx = NOTEXCL(bExcl,i,jj);
-                            
-                            if (bNotEx) 
-                            {
-                                if (!bDoVdW_i) 
-                                { 
-                                    if (charge[jj] != 0)
-                                    {
-                                        add_j_to_nblist(coul,jj,bLR);
-                                    }
-                                }
-                                else if (!bDoCoul_i) 
-                                {
-                                    if (bHaveVdW[type[jj]])
-                                    {
-                                        add_j_to_nblist(vdw,jj,bLR);
-                                    }
-                                }
-                                else 
-                                {
-                                    if (bHaveVdW[type[jj]]) 
-                                    {
-                                        if (charge[jj] != 0)
-                                        {
-                                            add_j_to_nblist(vdwc,jj,bLR);
-                                        }
-                                        else
-                                        {
-                                            add_j_to_nblist(vdw,jj,bLR);
-                                        }
-                                    } 
-                                    else if (charge[jj] != 0)
-                                    {
-                                        add_j_to_nblist(coul,jj,bLR);
-                                    }
-                                }
-                            }
-                        }
-                    }
-                }
-                close_i_nblist(vdw);
-                close_i_nblist(coul);
-                close_i_nblist(vdwc);
-            }
-        }
-    }
-    else
-    {
-        /* we are doing free energy */
-        vdwc_free = &nlist[eNL_VDWQQ_FREE];
-        vdw_free  = &nlist[eNL_VDW_FREE];
-        coul_free = &nlist[eNL_QQ_FREE];
-        /* Loop over the atoms in the i charge group */    
-        for(i=0; i<nicg; i++) 
-        {
-            i_atom  = i0+i;
-            gid     = GID(igid,jgid,ngid);
-            qi      = charge[i_atom];
-            qiB     = chargeB[i_atom];
-            
-            /* Create new i_atom for each energy group */
-            if (bDoVdW && bDoCoul) 
-                new_i_nblist(vdwc,bLR,i_atom,shift,gid);
-            if (bDoVdW)   
-                new_i_nblist(vdw,bLR,i_atom,shift,gid);
-            if (bDoCoul) 
-                new_i_nblist(coul,bLR,i_atom,shift,gid);
-            
-            new_i_nblist(vdw_free,bLR,i_atom,shift,gid);
-            new_i_nblist(coul_free,bLR,i_atom,shift,gid);
-            new_i_nblist(vdwc_free,bLR,i_atom,shift,gid);
-            
-            bDoVdW_i  = (bDoVdW  &&
-                         (bHaveVdW[type[i_atom]] || bHaveVdW[typeB[i_atom]]));
-            bDoCoul_i = (bDoCoul && (qi!=0 || qiB!=0));
-            /* For TIP4P the first atom does not have a charge,
-             * but the last three do. So we should still put an atom
-             * without LJ but with charge in the water-atom neighborlist
-             * for a TIP4p i charge group.
-             * For SPC type water the first atom has LJ and charge,
-             * so there is no such problem.
-             */
-            if (iwater == esolNO)
-            {
-                bDoCoul_i_sol = bDoCoul_i;
-            }
-            else
-            {
-                bDoCoul_i_sol = bDoCoul;
-            }
-            
-            if (bDoVdW_i || bDoCoul_i_sol) 
-            {
-                /* Loop over the j charge groups */
-                for(j=0; (j<nj); j++)
-                {
-                    jcg=jjcg[j];
-                    
-                    /* Check for large charge groups */
-                    if (jcg == icg)
-                    {
-                        jj0 = i0 + i + 1;
-                    }
-                    else
-                    {
-                        jj0 = index[jcg];
-                    }
-                    
-                    jj1=index[jcg+1];
-                    /* Finally loop over the atoms in the j-charge group */    
-                    bFree = bPert[i_atom];
-                    for(jj=jj0; (jj<jj1); jj++) 
-                    {
-                        bFreeJ = bFree || bPert[jj];
-                        /* Complicated if, because the water H's should also
-                         * see perturbed j-particles
-                         */
-                        if (iwater==esolNO || i==0 || bFreeJ) 
-                        {
-                            bNotEx = NOTEXCL(bExcl,i,jj);
-                            
-                            if (bNotEx) 
-                            {
-                                if (bFreeJ)
-                                {
-                                    if (!bDoVdW_i) 
-                                    {
-                                        if (charge[jj]!=0 || chargeB[jj]!=0)
-                                        {
-                                            add_j_to_nblist(coul_free,jj,bLR);
-                                        }
-                                    }
-                                    else if (!bDoCoul_i) 
-                                    {
-                                        if (bHaveVdW[type[jj]] || bHaveVdW[typeB[jj]])
-                                        {
-                                            add_j_to_nblist(vdw_free,jj,bLR);
-                                        }
-                                    }
-                                    else 
-                                    {
-                                        if (bHaveVdW[type[jj]] || bHaveVdW[typeB[jj]]) 
-                                        {
-                                            if (charge[jj]!=0 || chargeB[jj]!=0)
-                                            {
-                                                add_j_to_nblist(vdwc_free,jj,bLR);
-                                            }
-                                            else
-                                            {
-                                                add_j_to_nblist(vdw_free,jj,bLR);
-                                            }
-                                        }
-                                        else if (charge[jj]!=0 || chargeB[jj]!=0)
-                                            add_j_to_nblist(coul_free,jj,bLR);
-                                    }
-                                }
-                                else if (!bDoVdW_i) 
-                                { 
-                                    /* This is done whether or not bWater is set */
-                                    if (charge[jj] != 0)
-                                    {
-                                        add_j_to_nblist(coul,jj,bLR);
-                                    }
-                                }
-                                else if (!bDoCoul_i_sol) 
-                                { 
-                                    if (bHaveVdW[type[jj]])
-                                    {
-                                        add_j_to_nblist(vdw,jj,bLR);
-                                    }
-                                }
-                                else 
-                                {
-                                    if (bHaveVdW[type[jj]]) 
-                                    {
-                                        if (charge[jj] != 0)
-                                        {
-                                            add_j_to_nblist(vdwc,jj,bLR);
-                                        }
-                                        else
-                                        {
-                                            add_j_to_nblist(vdw,jj,bLR);
-                                        }
-                                    } 
-                                    else if (charge[jj] != 0)
-                                    {
-                                        add_j_to_nblist(coul,jj,bLR);
-                                    }
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-            close_i_nblist(vdw);
-            close_i_nblist(coul);
-            close_i_nblist(vdwc);
-            close_i_nblist(vdw_free);
-            close_i_nblist(coul_free);
-            close_i_nblist(vdwc_free);
-        }
-    }
-}
-
-static void 
-put_in_list_qmmm(gmx_bool              bHaveVdW[],
-                 int               ngid,
-                 t_mdatoms *       md,
-                 int               icg,
-                 int               jgid,
-                 int               nj,
-                 atom_id           jjcg[],
-                 atom_id           index[],
-                 t_excl            bExcl[],
-                 int               shift,
-                 t_forcerec *      fr,
-                 gmx_bool              bLR,
-                 gmx_bool              bDoVdW,
-                 gmx_bool              bDoCoul)
-{
-    t_nblist *   coul;
-    int          i,j,jcg,igid,gid;
-    atom_id   jj,jj0,jj1,i_atom;
-    int       i0,nicg;
-    gmx_bool      bNotEx;
-    
-    /* Get atom range */
-    i0     = index[icg];
-    nicg   = index[icg+1]-i0;
-    
-    /* Get the i charge group info */
-    igid   = GET_CGINFO_GID(fr->cginfo[icg]);
-    
-    coul = &fr->QMMMlist;
-    
-    /* Loop over atoms in the ith charge group */
-    for (i=0;i<nicg;i++)
-    {
-        i_atom = i0+i;
-        gid    = GID(igid,jgid,ngid);
-        /* Create new i_atom for each energy group */
-        new_i_nblist(coul,bLR,i_atom,shift,gid);
-        
-        /* Loop over the j charge groups */
-        for (j=0;j<nj;j++)
-        {
-            jcg=jjcg[j];
-            
-            /* Charge groups cannot have QM and MM atoms simultaneously */
-            if (jcg!=icg)
-            {
-                jj0 = index[jcg];
-                jj1 = index[jcg+1];
-                /* Finally loop over the atoms in the j-charge group */
-                for(jj=jj0; jj<jj1; jj++)
-                {
-                    bNotEx = NOTEXCL(bExcl,i,jj);
-                    if(bNotEx)
-                        add_j_to_nblist(coul,jj,bLR);
-                }
-            }
-        }
-        close_i_nblist(coul);
-    }
-}
-
-static void 
-put_in_list_cg(gmx_bool              bHaveVdW[],
-               int               ngid,
-               t_mdatoms *       md,
-               int               icg,
-               int               jgid,
-               int               nj,
-               atom_id           jjcg[],
-               atom_id           index[],
-               t_excl            bExcl[],
-               int               shift,
-               t_forcerec *      fr,
-               gmx_bool              bLR,
-               gmx_bool              bDoVdW,
-               gmx_bool              bDoCoul)
-{
-    int          cginfo;
-    int          igid,gid,nbl_ind;
-    t_nblist *   vdwc;
-    int          j,jcg;
-
-    cginfo = fr->cginfo[icg];
-
-    igid = GET_CGINFO_GID(cginfo);
-    gid  = GID(igid,jgid,ngid);
-
-    /* Unpack pointers to neighbourlist structs */
-    if (fr->nnblists == 1)
-    {
-        nbl_ind = 0;
-    }
-    else
-    {
-        nbl_ind = fr->gid2nblists[gid];
-    }
-    if (bLR)
-    {
-        vdwc = &fr->nblists[nbl_ind].nlist_lr[eNL_VDWQQ];
-    }
-    else
-    {
-        vdwc = &fr->nblists[nbl_ind].nlist_sr[eNL_VDWQQ];
-    }
-
-    /* Make a new neighbor list for charge group icg.
-     * Currently simply one neighbor list is made with LJ and Coulomb.
-     * If required, zero interactions could be removed here
-     * or in the force loop.
-     */
-    new_i_nblist(vdwc,bLR,index[icg],shift,gid);
-    vdwc->iinr_end[vdwc->nri] = index[icg+1];
-
-    for(j=0; (j<nj); j++) 
-    {
-        jcg = jjcg[j];
-        /* Skip the icg-icg pairs if all self interactions are excluded */
-        if (!(jcg == icg && GET_CGINFO_EXCL_INTRA(cginfo)))
-        {
-            /* Here we add the j charge group jcg to the list,
-             * exclusions are also added to the list.
-             */
-            add_j_to_nblist_cg(vdwc,index[jcg],index[jcg+1],bExcl,bLR);
-        }
-    }
-
-    close_i_nblist(vdwc);  
-}
-
-static void setexcl(atom_id start,atom_id end,t_blocka *excl,gmx_bool b,
-                    t_excl bexcl[])
-{
-    atom_id i,k;
-    
-    if (b)
-    {
-        for(i=start; i<end; i++)
-        {
-            for(k=excl->index[i]; k<excl->index[i+1]; k++)
-            {
-                SETEXCL(bexcl,i-start,excl->a[k]);
-            }
-        }
-    }
-    else
-    {
-        for(i=start; i<end; i++)
-        {
-            for(k=excl->index[i]; k<excl->index[i+1]; k++)
-            {
-                RMEXCL(bexcl,i-start,excl->a[k]);
-            }
-        }
-    }
-}
-
-int calc_naaj(int icg,int cgtot)
-{
-    int naaj;
-    
-    if ((cgtot % 2) == 1)
-    {
-        /* Odd number of charge groups, easy */
-        naaj = 1 + (cgtot/2);
-    }
-    else if ((cgtot % 4) == 0)
-    {
-    /* Multiple of four is hard */
-        if (icg < cgtot/2)
-        {
-            if ((icg % 2) == 0)
-            {
-                naaj=1+(cgtot/2);
-            }
-            else
-            {
-                naaj=cgtot/2;
-            }
-        }
-        else
-        {
-            if ((icg % 2) == 1)
-            {
-                naaj=1+(cgtot/2);
-            }
-            else
-            {
-                naaj=cgtot/2;
-            }
-        }
-    }
-    else
-    {
-        /* cgtot/2 = odd */
-        if ((icg % 2) == 0)
-        {
-            naaj=1+(cgtot/2);
-        }
-        else
-        {
-            naaj=cgtot/2;
-        }
-    }
-#ifdef DEBUG
-    fprintf(log,"naaj=%d\n",naaj);
-#endif
-
-    return naaj;
-}
-
-/************************************************
- *
- *  S I M P L E      C O R E     S T U F F
- *
- ************************************************/
-
-static real calc_image_tric(rvec xi,rvec xj,matrix box,
-                            rvec b_inv,int *shift)
-{
-    /* This code assumes that the cut-off is smaller than
-     * a half times the smallest diagonal element of the box.
-     */
-    const real h25=2.5;
-    real dx,dy,dz;
-    real r2;
-    int  tx,ty,tz;
-    
-    /* Compute diff vector */
-    dz = xj[ZZ] - xi[ZZ];
-    dy = xj[YY] - xi[YY];
-    dx = xj[XX] - xi[XX];
-    
-  /* Perform NINT operation, using trunc operation, therefore
-   * we first add 2.5 then subtract 2 again
-   */
-    tz = dz*b_inv[ZZ] + h25;
-    tz -= 2;
-    dz -= tz*box[ZZ][ZZ];
-    dy -= tz*box[ZZ][YY];
-    dx -= tz*box[ZZ][XX];
-
-    ty = dy*b_inv[YY] + h25;
-    ty -= 2;
-    dy -= ty*box[YY][YY];
-    dx -= ty*box[YY][XX];
-    
-    tx = dx*b_inv[XX]+h25;
-    tx -= 2;
-    dx -= tx*box[XX][XX];
-  
-    /* Distance squared */
-    r2 = (dx*dx) + (dy*dy) + (dz*dz);
-
-    *shift = XYZ2IS(tx,ty,tz);
-
-    return r2;
-}
-
-static real calc_image_rect(rvec xi,rvec xj,rvec box_size,
-                            rvec b_inv,int *shift)
-{
-    const real h15=1.5;
-    real ddx,ddy,ddz;
-    real dx,dy,dz;
-    real r2;
-    int  tx,ty,tz;
-    
-    /* Compute diff vector */
-    dx = xj[XX] - xi[XX];
-    dy = xj[YY] - xi[YY];
-    dz = xj[ZZ] - xi[ZZ];
-  
-    /* Perform NINT operation, using trunc operation, therefore
-     * we first add 1.5 then subtract 1 again
-     */
-    tx = dx*b_inv[XX] + h15;
-    ty = dy*b_inv[YY] + h15;
-    tz = dz*b_inv[ZZ] + h15;
-    tx--;
-    ty--;
-    tz--;
-    
-    /* Correct diff vector for translation */
-    ddx = tx*box_size[XX] - dx;
-    ddy = ty*box_size[YY] - dy;
-    ddz = tz*box_size[ZZ] - dz;
-    
-    /* Distance squared */
-    r2 = (ddx*ddx) + (ddy*ddy) + (ddz*ddz);
-    
-    *shift = XYZ2IS(tx,ty,tz);
-    
-    return r2;
-}
-
-static void add_simple(t_ns_buf *nsbuf,int nrj,atom_id cg_j,
-                       gmx_bool bHaveVdW[],int ngid,t_mdatoms *md,
-                       int icg,int jgid,t_block *cgs,t_excl bexcl[],
-                       int shift,t_forcerec *fr,put_in_list_t *put_in_list)
-{
-    if (nsbuf->nj + nrj > MAX_CG)
-    {
-        put_in_list(bHaveVdW,ngid,md,icg,jgid,nsbuf->ncg,nsbuf->jcg,
-                    cgs->index,bexcl,shift,fr,FALSE,TRUE,TRUE);
-        /* Reset buffer contents */
-        nsbuf->ncg = nsbuf->nj = 0;
-    }
-    nsbuf->jcg[nsbuf->ncg++] = cg_j;
-    nsbuf->nj += nrj;
-}
-
-static void ns_inner_tric(rvec x[],int icg,int *i_egp_flags,
-                          int njcg,atom_id jcg[],
-                          matrix box,rvec b_inv,real rcut2,
-                          t_block *cgs,t_ns_buf **ns_buf,
-                          gmx_bool bHaveVdW[],int ngid,t_mdatoms *md,
-                          t_excl bexcl[],t_forcerec *fr,
-                          put_in_list_t *put_in_list)
-{
-    int      shift;
-    int      j,nrj,jgid;
-    int      *cginfo=fr->cginfo;
-    atom_id  cg_j,*cgindex;
-    t_ns_buf *nsbuf;
-    
-    cgindex = cgs->index;
-    shift   = CENTRAL;
-    for(j=0; (j<njcg); j++)
-    {
-        cg_j   = jcg[j];
-        nrj    = cgindex[cg_j+1]-cgindex[cg_j];
-        if (calc_image_tric(x[icg],x[cg_j],box,b_inv,&shift) < rcut2)
-        {
-            jgid  = GET_CGINFO_GID(cginfo[cg_j]);
-            if (!(i_egp_flags[jgid] & EGP_EXCL))
-            {
-                add_simple(&ns_buf[jgid][shift],nrj,cg_j,
-                           bHaveVdW,ngid,md,icg,jgid,cgs,bexcl,shift,fr,
-                           put_in_list);
-            }
-        }
-    }
-}
-
-static void ns_inner_rect(rvec x[],int icg,int *i_egp_flags,
-                          int njcg,atom_id jcg[],
-                          gmx_bool bBox,rvec box_size,rvec b_inv,real rcut2,
-                          t_block *cgs,t_ns_buf **ns_buf,
-                          gmx_bool bHaveVdW[],int ngid,t_mdatoms *md,
-                          t_excl bexcl[],t_forcerec *fr,
-                          put_in_list_t *put_in_list)
-{
-    int      shift;
-    int      j,nrj,jgid;
-    int      *cginfo=fr->cginfo;
-    atom_id  cg_j,*cgindex;
-    t_ns_buf *nsbuf;
-
-    cgindex = cgs->index;
-    if (bBox)
-    {
-        shift = CENTRAL;
-        for(j=0; (j<njcg); j++)
-        {
-            cg_j   = jcg[j];
-            nrj    = cgindex[cg_j+1]-cgindex[cg_j];
-            if (calc_image_rect(x[icg],x[cg_j],box_size,b_inv,&shift) < rcut2)
-            {
-                jgid  = GET_CGINFO_GID(cginfo[cg_j]);
-                if (!(i_egp_flags[jgid] & EGP_EXCL))
-                {
-                    add_simple(&ns_buf[jgid][shift],nrj,cg_j,
-                               bHaveVdW,ngid,md,icg,jgid,cgs,bexcl,shift,fr,
-                               put_in_list);
-                }
-            }
-        }
-    } 
-    else
-    {
-        for(j=0; (j<njcg); j++)
-        {
-            cg_j   = jcg[j];
-            nrj    = cgindex[cg_j+1]-cgindex[cg_j];
-            if ((rcut2 == 0) || (distance2(x[icg],x[cg_j]) < rcut2)) {
-                jgid  = GET_CGINFO_GID(cginfo[cg_j]);
-                if (!(i_egp_flags[jgid] & EGP_EXCL))
-                {
-                    add_simple(&ns_buf[jgid][CENTRAL],nrj,cg_j,
-                               bHaveVdW,ngid,md,icg,jgid,cgs,bexcl,CENTRAL,fr,
-                               put_in_list);
-                }
-            }
-        }
-    }
-}
-
-/* ns_simple_core needs to be adapted for QMMM still 2005 */
-
-static int ns_simple_core(t_forcerec *fr,
-                          gmx_localtop_t *top,
-                          t_mdatoms *md,
-                          matrix box,rvec box_size,
-                          t_excl bexcl[],atom_id *aaj,
-                          int ngid,t_ns_buf **ns_buf,
-                          put_in_list_t *put_in_list,gmx_bool bHaveVdW[])
-{
-    int      naaj,k;
-    real     rlist2;
-    int      nsearch,icg,jcg,igid,i0,nri,nn;
-    int      *cginfo;
-    t_ns_buf *nsbuf;
-    /* atom_id  *i_atoms; */
-    t_block  *cgs=&(top->cgs);
-    t_blocka *excl=&(top->excls);
-    rvec     b_inv;
-    int      m;
-    gmx_bool     bBox,bTriclinic;
-    int      *i_egp_flags;
-    
-    rlist2 = sqr(fr->rlist);
-    
-    bBox = (fr->ePBC != epbcNONE);
-    if (bBox)
-    {
-        for(m=0; (m<DIM); m++)
-        {
-            b_inv[m] = divide(1.0,box_size[m]);
-        }
-        bTriclinic = TRICLINIC(box);
-    }
-    else
-    {
-        bTriclinic = FALSE;
-    }
-    
-    cginfo = fr->cginfo;
-    
-    nsearch=0;
-    for (icg=fr->cg0; (icg<fr->hcg); icg++)
-    {
-        /*
-          i0        = cgs->index[icg];
-          nri       = cgs->index[icg+1]-i0;
-          i_atoms   = &(cgs->a[i0]);
-          i_eg_excl = fr->eg_excl + ngid*md->cENER[*i_atoms];
-          setexcl(nri,i_atoms,excl,TRUE,bexcl);
-        */
-        igid = GET_CGINFO_GID(cginfo[icg]);
-        i_egp_flags = fr->egp_flags + ngid*igid;
-        setexcl(cgs->index[icg],cgs->index[icg+1],excl,TRUE,bexcl);
-        
-        naaj=calc_naaj(icg,cgs->nr);
-        if (bTriclinic)
-        {
-            ns_inner_tric(fr->cg_cm,icg,i_egp_flags,naaj,&(aaj[icg]),
-                          box,b_inv,rlist2,cgs,ns_buf,
-                          bHaveVdW,ngid,md,bexcl,fr,put_in_list);
-        }
-        else
-        {
-            ns_inner_rect(fr->cg_cm,icg,i_egp_flags,naaj,&(aaj[icg]),
-                          bBox,box_size,b_inv,rlist2,cgs,ns_buf,
-                          bHaveVdW,ngid,md,bexcl,fr,put_in_list);
-        }
-        nsearch += naaj;
-        
-        for(nn=0; (nn<ngid); nn++)
-        {
-            for(k=0; (k<SHIFTS); k++)
-            {
-                nsbuf = &(ns_buf[nn][k]);
-                if (nsbuf->ncg > 0)
-                {
-                    put_in_list(bHaveVdW,ngid,md,icg,nn,nsbuf->ncg,nsbuf->jcg,
-                                cgs->index,bexcl,k,fr,FALSE,TRUE,TRUE);
-                    nsbuf->ncg=nsbuf->nj=0;
-                }
-            }
-        }
-        /* setexcl(nri,i_atoms,excl,FALSE,bexcl); */
-        setexcl(cgs->index[icg],cgs->index[icg+1],excl,FALSE,bexcl);
-    }
-    close_neighbor_list(fr,FALSE,-1,-1,FALSE);
-    
-    return nsearch;
-}
-
-/************************************************
- *
- *    N S 5     G R I D     S T U F F
- *
- ************************************************/
-
-static inline void get_dx(int Nx,real gridx,real rc2,int xgi,real x,
-                          int *dx0,int *dx1,real *dcx2)
-{
-    real dcx,tmp;
-    int  xgi0,xgi1,i;
-    
-    if (xgi < 0)
-    {
-        *dx0 = 0;
-        xgi0 = -1;
-        *dx1 = -1;
-        xgi1 = 0;
-    }
-    else if (xgi >= Nx)
-    {
-        *dx0 = Nx;
-        xgi0 = Nx-1;
-        *dx1 = Nx-1;
-        xgi1 = Nx;
-    }
-    else
-    {
-        dcx2[xgi] = 0;
-        *dx0 = xgi;
-        xgi0 = xgi-1;
-        *dx1 = xgi;
-        xgi1 = xgi+1;
-    }
-    
-    for(i=xgi0; i>=0; i--)
-    {
-        dcx = (i+1)*gridx-x;
-        tmp = dcx*dcx;
-        if (tmp >= rc2)
-            break;
-        *dx0 = i;
-        dcx2[i] = tmp;
-    }
-    for(i=xgi1; i<Nx; i++)
-    {
-        dcx = i*gridx-x;
-        tmp = dcx*dcx;
-        if (tmp >= rc2)
-        {
-            break;
-        }
-        *dx1 = i;
-        dcx2[i] = tmp;
-    }
-}
-
-static inline void get_dx_dd(int Nx,real gridx,real rc2,int xgi,real x,
-                             int ncpddc,int shift_min,int shift_max,
-                             int *g0,int *g1,real *dcx2)
-{
-    real dcx,tmp;
-    int  g_min,g_max,shift_home;
-    
-    if (xgi < 0)
-    {
-        g_min = 0;
-        g_max = Nx - 1;
-        *g0   = 0;
-        *g1   = -1;
-    }
-    else if (xgi >= Nx)
-    {
-        g_min = 0;
-        g_max = Nx - 1;
-        *g0   = Nx;
-        *g1   = Nx - 1;
-    }
-    else
-    {
-        if (ncpddc == 0)
-        {
-            g_min = 0;
-            g_max = Nx - 1;
-        }
-        else
-        {
-            if (xgi < ncpddc)
-            {
-                shift_home = 0;
-            }
-            else
-            {
-                shift_home = -1;
-            }
-            g_min = (shift_min == shift_home ? 0          : ncpddc);
-            g_max = (shift_max == shift_home ? ncpddc - 1 : Nx - 1);
-        }
-        if (shift_min > 0)
-        {
-            *g0 = g_min;
-            *g1 = g_min - 1;
-        }
-        else if (shift_max < 0)
-        {
-            *g0 = g_max + 1;
-            *g1 = g_max;
-        }
-        else
-        {
-            *g0 = xgi;
-            *g1 = xgi;
-            dcx2[xgi] = 0;
-        }
-    }
-    
-    while (*g0 > g_min)
-    {
-        /* Check one grid cell down */
-        dcx = ((*g0 - 1) + 1)*gridx - x;
-        tmp = dcx*dcx;
-        if (tmp >= rc2)
-        {
-            break;
-        }
-        (*g0)--;
-        dcx2[*g0] = tmp;
-    }
-    
-    while (*g1 < g_max)
-    {
-        /* Check one grid cell up */
-        dcx = (*g1 + 1)*gridx - x;
-        tmp = dcx*dcx;
-        if (tmp >= rc2)
-        {
-            break;
-        }
-        (*g1)++;
-        dcx2[*g1] = tmp;
-    }
-}
-
-
-#define sqr(x) ((x)*(x))
-#define calc_dx2(XI,YI,ZI,y) (sqr(XI-y[XX]) + sqr(YI-y[YY]) + sqr(ZI-y[ZZ]))
-#define calc_cyl_dx2(XI,YI,y) (sqr(XI-y[XX]) + sqr(YI-y[YY]))
-/****************************************************
- *
- *    F A S T   N E I G H B O R  S E A R C H I N G
- *
- *    Optimized neighboursearching routine using grid 
- *    at least 1x1x1, see GROMACS manual
- *
- ****************************************************/
-
-static void do_longrange(t_commrec *cr,gmx_localtop_t *top,t_forcerec *fr,
-                         int ngid,t_mdatoms *md,int icg,
-                         int jgid,int nlr,
-                         atom_id lr[],t_excl bexcl[],int shift,
-                         rvec x[],rvec box_size,t_nrnb *nrnb,
-                         real lambda,real *dvdlambda,
-                         gmx_grppairener_t *grppener,
-                         gmx_bool bDoVdW,gmx_bool bDoCoul,
-                         gmx_bool bEvaluateNow,put_in_list_t *put_in_list,
-                         gmx_bool bHaveVdW[],
-                         gmx_bool bDoForces,rvec *f)
-{
-    int n,i;
-    t_nblist *nl;
-    
-    for(n=0; n<fr->nnblists; n++)
-    {
-        for(i=0; (i<eNL_NR); i++)
-        {
-            nl = &fr->nblists[n].nlist_lr[i];
-            if ((nl->nri > nl->maxnri-32) || bEvaluateNow)
-            {
-                close_neighbor_list(fr,TRUE,n,i,FALSE);
-                /* Evaluate the energies and forces */
-                do_nonbonded(cr,fr,x,f,md,NULL,
-                             grppener->ener[fr->bBHAM ? egBHAMLR : egLJLR],
-                             grppener->ener[egCOULLR],
-                                                        grppener->ener[egGB],box_size,
-                             nrnb,lambda,dvdlambda,n,i,
-                             GMX_DONB_LR | GMX_DONB_FORCES);
-                
-                reset_neighbor_list(fr,TRUE,n,i);
-            }
-        }
-    }
-    
-    if (!bEvaluateNow)
-    {  
-        /* Put the long range particles in a list */
-        /* do_longrange is never called for QMMM  */
-        put_in_list(bHaveVdW,ngid,md,icg,jgid,nlr,lr,top->cgs.index,
-                    bexcl,shift,fr,TRUE,bDoVdW,bDoCoul);
-    }
-}
-
-static void get_cutoff2(t_forcerec *fr,gmx_bool bDoLongRange,
-                        real *rvdw2,real *rcoul2,
-                        real *rs2,real *rm2,real *rl2)
-{
-    *rs2 = sqr(fr->rlist);
-    if (bDoLongRange && fr->bTwinRange)
-    {
-        /* The VdW and elec. LR cut-off's could be different,
-         * so we can not simply set them to rlistlong.
-         */
-        if (EVDW_MIGHT_BE_ZERO_AT_CUTOFF(fr->vdwtype) &&
-            fr->rvdw > fr->rlist)
-        {
-            *rvdw2  = sqr(fr->rlistlong);
-        }
-        else
-        {
-            *rvdw2  = sqr(fr->rvdw);
-        }
-        if (EEL_MIGHT_BE_ZERO_AT_CUTOFF(fr->eeltype) &&
-            fr->rcoulomb > fr->rlist)
-        {
-            *rcoul2 = sqr(fr->rlistlong);
-        }
-        else
-        {
-            *rcoul2 = sqr(fr->rcoulomb);
-        }
-    }
-    else
-    {
-        /* Workaround for a gcc -O3 or -ffast-math problem */
-        *rvdw2  = *rs2;
-        *rcoul2 = *rs2;
-    }
-    *rm2 = min(*rvdw2,*rcoul2);
-    *rl2 = max(*rvdw2,*rcoul2);
-}
-
-static void init_nsgrid_lists(t_forcerec *fr,int ngid,gmx_ns_t *ns)
-{
-    real rvdw2,rcoul2,rs2,rm2,rl2;
-    int j;
-
-    get_cutoff2(fr,TRUE,&rvdw2,&rcoul2,&rs2,&rm2,&rl2);
-
-    /* Short range buffers */
-    snew(ns->nl_sr,ngid);
-    /* Counters */
-    snew(ns->nsr,ngid);
-    snew(ns->nlr_ljc,ngid);
-    snew(ns->nlr_one,ngid);
-    
-    if (rm2 > rs2)
-    {
-            /* Long range VdW and Coul buffers */
-        snew(ns->nl_lr_ljc,ngid);
-    }
-    if (rl2 > rm2)
-    {
-        /* Long range VdW or Coul only buffers */
-        snew(ns->nl_lr_one,ngid);
-    }
-    for(j=0; (j<ngid); j++) {
-        snew(ns->nl_sr[j],MAX_CG);
-        if (rm2 > rs2)
-        {
-            snew(ns->nl_lr_ljc[j],MAX_CG);
-        }
-        if (rl2 > rm2)
-        {
-            snew(ns->nl_lr_one[j],MAX_CG);
-        }
-    }
-    if (debug)
-    {
-        fprintf(debug,
-                "ns5_core: rs2 = %g, rm2 = %g, rl2 = %g (nm^2)\n",
-                rs2,rm2,rl2);
-    }
-}
-
-static int nsgrid_core(FILE *log,t_commrec *cr,t_forcerec *fr,
-                       matrix box,rvec box_size,int ngid,
-                       gmx_localtop_t *top,
-                       t_grid *grid,rvec x[],
-                       t_excl bexcl[],gmx_bool *bExcludeAlleg,
-                       t_nrnb *nrnb,t_mdatoms *md,
-                       real lambda,real *dvdlambda,
-                       gmx_grppairener_t *grppener,
-                       put_in_list_t *put_in_list,
-                       gmx_bool bHaveVdW[],
-                       gmx_bool bDoLongRange,gmx_bool bDoForces,rvec *f,
-                       gmx_bool bMakeQMMMnblist)
-{
-    gmx_ns_t *ns;
-    atom_id **nl_lr_ljc,**nl_lr_one,**nl_sr;
-    int     *nlr_ljc,*nlr_one,*nsr;
-    gmx_domdec_t *dd=NULL;
-    t_block *cgs=&(top->cgs);
-    int     *cginfo=fr->cginfo;
-    /* atom_id *i_atoms,*cgsindex=cgs->index; */
-    ivec    sh0,sh1,shp;
-    int     cell_x,cell_y,cell_z;
-    int     d,tx,ty,tz,dx,dy,dz,cj;
-#ifdef ALLOW_OFFDIAG_LT_HALFDIAG
-    int     zsh_ty,zsh_tx,ysh_tx;
-#endif
-    int     dx0,dx1,dy0,dy1,dz0,dz1;
-    int     Nx,Ny,Nz,shift=-1,j,nrj,nns,nn=-1;
-    real    gridx,gridy,gridz,grid_x,grid_y,grid_z;
-    real    *dcx2,*dcy2,*dcz2;
-    int     zgi,ygi,xgi;
-    int     cg0,cg1,icg=-1,cgsnr,i0,igid,nri,naaj,max_jcg;
-    int     jcg0,jcg1,jjcg,cgj0,jgid;
-    int     *grida,*gridnra,*gridind;
-    gmx_bool    rvdw_lt_rcoul,rcoul_lt_rvdw;
-    rvec    xi,*cgcm,grid_offset;
-    real    r2,rs2,rvdw2,rcoul2,rm2,rl2,XI,YI,ZI,dcx,dcy,dcz,tmp1,tmp2;
-    int     *i_egp_flags;
-    gmx_bool    bDomDec,bTriclinicX,bTriclinicY;
-    ivec    ncpddc;
-    
-    ns = &fr->ns;
-    
-    bDomDec = DOMAINDECOMP(cr);
-    if (bDomDec)
-    {
-        dd = cr->dd;
-    }
-    
-    bTriclinicX = ((YY < grid->npbcdim &&
-                    (!bDomDec || dd->nc[YY]==1) && box[YY][XX] != 0) ||
-                   (ZZ < grid->npbcdim &&
-                    (!bDomDec || dd->nc[ZZ]==1) && box[ZZ][XX] != 0));
-    bTriclinicY =  (ZZ < grid->npbcdim &&
-                    (!bDomDec || dd->nc[ZZ]==1) && box[ZZ][YY] != 0);
-    
-    cgsnr    = cgs->nr;
-
-    get_cutoff2(fr,bDoLongRange,&rvdw2,&rcoul2,&rs2,&rm2,&rl2);
-
-    rvdw_lt_rcoul = (rvdw2 >= rcoul2);
-    rcoul_lt_rvdw = (rcoul2 >= rvdw2);
-    
-    if (bMakeQMMMnblist)
-    {
-        rm2 = rl2;
-        rs2 = rl2;
-    }
-
-    nl_sr     = ns->nl_sr;
-    nsr       = ns->nsr;
-    nl_lr_ljc = ns->nl_lr_ljc;
-    nl_lr_one = ns->nl_lr_one;
-    nlr_ljc   = ns->nlr_ljc;
-    nlr_one   = ns->nlr_one;
-    
-    /* Unpack arrays */
-    cgcm    = fr->cg_cm;
-    Nx      = grid->n[XX];
-    Ny      = grid->n[YY];
-    Nz      = grid->n[ZZ];
-    grida   = grid->a;
-    gridind = grid->index;
-    gridnra = grid->nra;
-    nns     = 0;
-    
-    gridx      = grid->cell_size[XX];
-    gridy      = grid->cell_size[YY];
-    gridz      = grid->cell_size[ZZ];
-    grid_x     = 1/gridx;
-    grid_y     = 1/gridy;
-    grid_z     = 1/gridz;
-    copy_rvec(grid->cell_offset,grid_offset);
-    copy_ivec(grid->ncpddc,ncpddc);
-    dcx2       = grid->dcx2;
-    dcy2       = grid->dcy2;
-    dcz2       = grid->dcz2;
-    
-#ifdef ALLOW_OFFDIAG_LT_HALFDIAG
-    zsh_ty = floor(-box[ZZ][YY]/box[YY][YY]+0.5);
-    zsh_tx = floor(-box[ZZ][XX]/box[XX][XX]+0.5);
-    ysh_tx = floor(-box[YY][XX]/box[XX][XX]+0.5);
-    if (zsh_tx!=0 && ysh_tx!=0)
-    {
-        /* This could happen due to rounding, when both ratios are 0.5 */
-        ysh_tx = 0;
-    }
-#endif
-    
-    debug_gmx();
-
-    if (fr->n_tpi)
-    {
-        /* We only want a list for the test particle */
-        cg0 = cgsnr - 1;
-    }
-    else
-    {
-        cg0 = grid->icg0;
-    }
-    cg1 = grid->icg1;
-
-    /* Set the shift range */
-    for(d=0; d<DIM; d++)
-    {
-        sh0[d] = -1;
-        sh1[d] = 1;
-        /* Check if we need periodicity shifts.
-         * Without PBC or with domain decomposition we don't need them.
-         */
-        if (d >= ePBC2npbcdim(fr->ePBC) || (bDomDec && dd->nc[d] > 1))
-        {
-            shp[d] = 0;
-        }
-        else
-        {
-            if (d == XX &&
-                box[XX][XX] - fabs(box[YY][XX]) - fabs(box[ZZ][XX]) < sqrt(rl2))
-            {
-                shp[d] = 2;
-            }
-            else
-            {
-                shp[d] = 1;
-            }
-        }
-    }
-    
-    /* Loop over charge groups */
-    for(icg=cg0; (icg < cg1); icg++)
-    {
-        igid = GET_CGINFO_GID(cginfo[icg]);
-        /* Skip this charge group if all energy groups are excluded! */
-        if (bExcludeAlleg[igid])
-        {
-            continue;
-        }
-        
-        i0   = cgs->index[icg];
-        
-        if (bMakeQMMMnblist)
-        { 
-            /* Skip this charge group if it is not a QM atom while making a
-             * QM/MM neighbourlist
-             */
-            if (md->bQM[i0]==FALSE)
-            {
-                continue; /* MM particle, go to next particle */ 
-            }
-            
-            /* Compute the number of charge groups that fall within the control
-             * of this one (icg)
-             */
-            naaj    = calc_naaj(icg,cgsnr);
-            jcg0    = icg;
-            jcg1    = icg + naaj;
-            max_jcg = cgsnr;       
-        } 
-        else
-        { 
-            /* make a normal neighbourlist */
-            
-            if (bDomDec)
-            {
-                /* Get the j charge-group and dd cell shift ranges */
-                dd_get_ns_ranges(cr->dd,icg,&jcg0,&jcg1,sh0,sh1);
-                max_jcg = 0;
-            }
-            else
-            {
-                /* Compute the number of charge groups that fall within the control
-                 * of this one (icg)
-                 */
-                naaj = calc_naaj(icg,cgsnr);
-                jcg0 = icg;
-                jcg1 = icg + naaj;
-                
-                if (fr->n_tpi)
-                {
-                    /* The i-particle is awlways the test particle,
-                     * so we want all j-particles
-                     */
-                    max_jcg = cgsnr - 1;
-                }
-                else
-                {
-                    max_jcg  = jcg1 - cgsnr;
-                }
-            }
-        }
-        
-        i_egp_flags = fr->egp_flags + igid*ngid;
-        
-        /* Set the exclusions for the atoms in charge group icg using a bitmask */
-        setexcl(i0,cgs->index[icg+1],&top->excls,TRUE,bexcl);
-        
-        ci2xyz(grid,icg,&cell_x,&cell_y,&cell_z);
-        
-        /* Changed iicg to icg, DvdS 990115 
-         * (but see consistency check above, DvdS 990330) 
-         */
-#ifdef NS5DB
-        fprintf(log,"icg=%5d, naaj=%5d, cell %d %d %d\n",
-                icg,naaj,cell_x,cell_y,cell_z);
-#endif
-        /* Loop over shift vectors in three dimensions */
-        for (tz=-shp[ZZ]; tz<=shp[ZZ]; tz++)
-        {
-            ZI = cgcm[icg][ZZ]+tz*box[ZZ][ZZ];
-            /* Calculate range of cells in Z direction that have the shift tz */
-            zgi = cell_z + tz*Nz;
-#define FAST_DD_NS
-#ifndef FAST_DD_NS
-            get_dx(Nz,gridz,rl2,zgi,ZI,&dz0,&dz1,dcz2);
-#else
-            get_dx_dd(Nz,gridz,rl2,zgi,ZI-grid_offset[ZZ],
-                      ncpddc[ZZ],sh0[ZZ],sh1[ZZ],&dz0,&dz1,dcz2);
-#endif
-            if (dz0 > dz1)
-            {
-                continue;
-            }
-            for (ty=-shp[YY]; ty<=shp[YY]; ty++)
-            {
-                YI = cgcm[icg][YY]+ty*box[YY][YY]+tz*box[ZZ][YY];
-                /* Calculate range of cells in Y direction that have the shift ty */
-                if (bTriclinicY)
-                {
-                    ygi = (int)(Ny + (YI - grid_offset[YY])*grid_y) - Ny;
-                }
-                else
-                {
-                    ygi = cell_y + ty*Ny;
-                }
-#ifndef FAST_DD_NS
-                get_dx(Ny,gridy,rl2,ygi,YI,&dy0,&dy1,dcy2);
-#else
-                get_dx_dd(Ny,gridy,rl2,ygi,YI-grid_offset[YY],
-                          ncpddc[YY],sh0[YY],sh1[YY],&dy0,&dy1,dcy2);
-#endif
-                if (dy0 > dy1)
-                {
-                    continue;
-                }
-                for (tx=-shp[XX]; tx<=shp[XX]; tx++)
-                {
-                    XI = cgcm[icg][XX]+tx*box[XX][XX]+ty*box[YY][XX]+tz*box[ZZ][XX];
-                    /* Calculate range of cells in X direction that have the shift tx */
-                    if (bTriclinicX)
-                    {
-                        xgi = (int)(Nx + (XI - grid_offset[XX])*grid_x) - Nx;
-                    }
-                    else
-                    {
-                        xgi = cell_x + tx*Nx;
-                    }
-#ifndef FAST_DD_NS
-                    get_dx(Nx,gridx,rl2,xgi*Nx,XI,&dx0,&dx1,dcx2);
-#else
-                    get_dx_dd(Nx,gridx,rl2,xgi,XI-grid_offset[XX],
-                              ncpddc[XX],sh0[XX],sh1[XX],&dx0,&dx1,dcx2);
-#endif
-                    if (dx0 > dx1)
-                    {
-                        continue;
-                    }
-                    /* Get shift vector */       
-                    shift=XYZ2IS(tx,ty,tz);
-#ifdef NS5DB
-                    range_check(shift,0,SHIFTS);
-#endif
-                    for(nn=0; (nn<ngid); nn++)
-                    {
-                        nsr[nn]      = 0;
-                        nlr_ljc[nn]  = 0;
-                        nlr_one[nn] = 0;
-                    }
-#ifdef NS5DB
-                    fprintf(log,"shift: %2d, dx0,1: %2d,%2d, dy0,1: %2d,%2d, dz0,1: %2d,%2d\n",
-                            shift,dx0,dx1,dy0,dy1,dz0,dz1);
-                    fprintf(log,"cgcm: %8.3f  %8.3f  %8.3f\n",cgcm[icg][XX],
-                            cgcm[icg][YY],cgcm[icg][ZZ]);
-                    fprintf(log,"xi:   %8.3f  %8.3f  %8.3f\n",XI,YI,ZI);
-#endif
-                    for (dx=dx0; (dx<=dx1); dx++)
-                    {
-                        tmp1 = rl2 - dcx2[dx];
-                        for (dy=dy0; (dy<=dy1); dy++)
-                        {
-                            tmp2 = tmp1 - dcy2[dy];
-                            if (tmp2 > 0)
-                            {
-                                for (dz=dz0; (dz<=dz1); dz++) {
-                                    if (tmp2 > dcz2[dz]) {
-                                        /* Find grid-cell cj in which possible neighbours are */
-                                        cj   = xyz2ci(Ny,Nz,dx,dy,dz);
-                                        
-                                        /* Check out how many cgs (nrj) there in this cell */
-                                        nrj  = gridnra[cj];
-                                        
-                                        /* Find the offset in the cg list */
-                                        cgj0 = gridind[cj];
-                                        
-                                        /* Check if all j's are out of range so we
-                                         * can skip the whole cell.
-                                         * Should save some time, especially with DD.
-                                         */
-                                        if (nrj == 0 ||
-                                            (grida[cgj0] >= max_jcg &&
-                                             (grida[cgj0] >= jcg1 || grida[cgj0+nrj-1] < jcg0)))
-                                        {
-                                            continue;
-                                        }
-                                        
-                                        /* Loop over cgs */
-                                        for (j=0; (j<nrj); j++)
-                                        {
-                                            jjcg = grida[cgj0+j];
-                                            
-                                            /* check whether this guy is in range! */
-                                            if ((jjcg >= jcg0 && jjcg < jcg1) ||
-                                                (jjcg < max_jcg))
-                                            {
-                                                r2=calc_dx2(XI,YI,ZI,cgcm[jjcg]);
-                                                if (r2 < rl2) {
-                                                    /* jgid = gid[cgsatoms[cgsindex[jjcg]]]; */
-                                                    jgid = GET_CGINFO_GID(cginfo[jjcg]);
-                                                    /* check energy group exclusions */
-                                                    if (!(i_egp_flags[jgid] & EGP_EXCL))
-                                                    {
-                                                        if (r2 < rs2)
-                                                        {
-                                                            if (nsr[jgid] >= MAX_CG)
-                                                            {
-                                                                put_in_list(bHaveVdW,ngid,md,icg,jgid,
-                                                                            nsr[jgid],nl_sr[jgid],
-                                                                            cgs->index,/* cgsatoms, */ bexcl,
-                                                                            shift,fr,FALSE,TRUE,TRUE);
-                                                                nsr[jgid]=0;
-                                                            }
-                                                            nl_sr[jgid][nsr[jgid]++]=jjcg;
-                                                        } 
-                                                        else if (r2 < rm2)
-                                                        {
-                                                            if (nlr_ljc[jgid] >= MAX_CG)
-                                                            {
-                                                                do_longrange(cr,top,fr,ngid,md,icg,jgid,
-                                                                             nlr_ljc[jgid],
-                                                                             nl_lr_ljc[jgid],bexcl,shift,x,
-                                                                             box_size,nrnb,
-                                                                             lambda,dvdlambda,
-                                                                             grppener,
-                                                                             TRUE,TRUE,FALSE,
-                                                                             put_in_list,
-                                                                             bHaveVdW,
-                                                                             bDoForces,f);
-                                                                nlr_ljc[jgid]=0;
-                                                            }
-                                                            nl_lr_ljc[jgid][nlr_ljc[jgid]++]=jjcg;
-                                                        }
-                                                        else
-                                                        {
-                                                            if (nlr_one[jgid] >= MAX_CG) {
-                                                                do_longrange(cr,top,fr,ngid,md,icg,jgid,
-                                                                             nlr_one[jgid],
-                                                                             nl_lr_one[jgid],bexcl,shift,x,
-                                                                             box_size,nrnb,
-                                                                             lambda,dvdlambda,
-                                                                             grppener,
-                                                                             rvdw_lt_rcoul,rcoul_lt_rvdw,FALSE,
-                                                                             put_in_list,
-                                                                             bHaveVdW,
-                                                                             bDoForces,f);
-                                                                nlr_one[jgid]=0;
-                                                            }
-                                                            nl_lr_one[jgid][nlr_one[jgid]++]=jjcg;
-                                                        }
-                                                    }
-                                                }
-                                                nns++;
-                                            }
-                                        }
-                                    }
-                                }
-                            }
-                        }
-                    }
-                    /* CHECK whether there is anything left in the buffers */
-                    for(nn=0; (nn<ngid); nn++)
-                    {
-                        if (nsr[nn] > 0)
-                        {
-                            put_in_list(bHaveVdW,ngid,md,icg,nn,nsr[nn],nl_sr[nn],
-                                        cgs->index, /* cgsatoms, */ bexcl,
-                                        shift,fr,FALSE,TRUE,TRUE);
-                        }
-                        
-                        if (nlr_ljc[nn] > 0)
-                        {
-                            do_longrange(cr,top,fr,ngid,md,icg,nn,nlr_ljc[nn],
-                                         nl_lr_ljc[nn],bexcl,shift,x,box_size,nrnb,
-                                         lambda,dvdlambda,grppener,TRUE,TRUE,FALSE,
-                                         put_in_list,bHaveVdW,bDoForces,f);
-                        }
-                        
-                        if (nlr_one[nn] > 0)
-                        {
-                            do_longrange(cr,top,fr,ngid,md,icg,nn,nlr_one[nn],
-                                         nl_lr_one[nn],bexcl,shift,x,box_size,nrnb,
-                                         lambda,dvdlambda,grppener,
-                                         rvdw_lt_rcoul,rcoul_lt_rvdw,FALSE,
-                                         put_in_list,bHaveVdW,bDoForces,f);
-                        }
-                    }
-                }
-            }
-        }
-        /* setexcl(nri,i_atoms,&top->atoms.excl,FALSE,bexcl); */
-        setexcl(cgs->index[icg],cgs->index[icg+1],&top->excls,FALSE,bexcl);
-    }
-    /* Perform any left over force calculations */
-    for (nn=0; (nn<ngid); nn++)
-    {
-        if (rm2 > rs2)
-        {
-            do_longrange(cr,top,fr,0,md,icg,nn,nlr_ljc[nn],
-                         nl_lr_ljc[nn],bexcl,shift,x,box_size,nrnb,
-                         lambda,dvdlambda,grppener,
-                         TRUE,TRUE,TRUE,put_in_list,bHaveVdW,bDoForces,f);
-        }
-        if (rl2 > rm2) {
-            do_longrange(cr,top,fr,0,md,icg,nn,nlr_one[nn],
-                         nl_lr_one[nn],bexcl,shift,x,box_size,nrnb,
-                         lambda,dvdlambda,grppener,
-                         rvdw_lt_rcoul,rcoul_lt_rvdw,
-                         TRUE,put_in_list,bHaveVdW,bDoForces,f);
-        }
-    }
-    debug_gmx();
-    
-    /* Close off short range neighbourlists */
-    close_neighbor_list(fr,FALSE,-1,-1,bMakeQMMMnblist);
-    
-    return nns;
-}
-
-void ns_realloc_natoms(gmx_ns_t *ns,int natoms)
-{
-    int i;
-    
-    if (natoms > ns->nra_alloc)
-    {
-        ns->nra_alloc = over_alloc_dd(natoms);
-        srenew(ns->bexcl,ns->nra_alloc);
-        for(i=0; i<ns->nra_alloc; i++)
-        {
-            ns->bexcl[i] = 0;
-        }
-    }
-}
-
-void init_ns(FILE *fplog,const t_commrec *cr,
-             gmx_ns_t *ns,t_forcerec *fr,
-             const gmx_mtop_t *mtop,
-             matrix box)
-{
-    int  mt,icg,nr_in_cg,maxcg,i,j,jcg,ngid,ncg;
-    t_block *cgs;
-    char *ptr;
-    
-    /* Compute largest charge groups size (# atoms) */
-    nr_in_cg=1;
-    for(mt=0; mt<mtop->nmoltype; mt++) {
-        cgs = &mtop->moltype[mt].cgs;
-        for (icg=0; (icg < cgs->nr); icg++)
-        {
-            nr_in_cg=max(nr_in_cg,(int)(cgs->index[icg+1]-cgs->index[icg]));
-        }
-    }
-
-    /* Verify whether largest charge group is <= max cg.
-     * This is determined by the type of the local exclusion type 
-     * Exclusions are stored in bits. (If the type is not large
-     * enough, enlarge it, unsigned char -> unsigned short -> unsigned long)
-     */
-    maxcg = sizeof(t_excl)*8;
-    if (nr_in_cg > maxcg)
-    {
-        gmx_fatal(FARGS,"Max #atoms in a charge group: %d > %d\n",
-                  nr_in_cg,maxcg);
-    }
-    
-    ngid = mtop->groups.grps[egcENER].nr;
-    snew(ns->bExcludeAlleg,ngid);
-    for(i=0; i<ngid; i++) {
-        ns->bExcludeAlleg[i] = TRUE;
-        for(j=0; j<ngid; j++)
-        {
-            if (!(fr->egp_flags[i*ngid+j] & EGP_EXCL))
-            {
-                ns->bExcludeAlleg[i] = FALSE;
-            }
-        }
-    }
-    
-    if (fr->bGrid) {
-        /* Grid search */
-        ns->grid = init_grid(fplog,fr);
-        init_nsgrid_lists(fr,ngid,ns);
-    }
-    else
-    {
-        /* Simple search */
-        snew(ns->ns_buf,ngid);
-        for(i=0; (i<ngid); i++)
-        {
-            snew(ns->ns_buf[i],SHIFTS);
-        }
-        ncg = ncg_mtop(mtop);
-        snew(ns->simple_aaj,2*ncg);
-        for(jcg=0; (jcg<ncg); jcg++)
-        {
-            ns->simple_aaj[jcg]     = jcg;
-            ns->simple_aaj[jcg+ncg] = jcg;
-        }
-    }
-    
-    /* Create array that determines whether or not atoms have VdW */
-    snew(ns->bHaveVdW,fr->ntype);
-    for(i=0; (i<fr->ntype); i++)
-    {
-        for(j=0; (j<fr->ntype); j++)
-        {
-            ns->bHaveVdW[i] = (ns->bHaveVdW[i] || 
-                               (fr->bBHAM ? 
-                                ((BHAMA(fr->nbfp,fr->ntype,i,j) != 0) ||
-                                 (BHAMB(fr->nbfp,fr->ntype,i,j) != 0) ||
-                                 (BHAMC(fr->nbfp,fr->ntype,i,j) != 0)) :
-                                ((C6(fr->nbfp,fr->ntype,i,j) != 0) ||
-                                 (C12(fr->nbfp,fr->ntype,i,j) != 0))));
-        }
-    }
-    if (debug) 
-        pr_bvec(debug,0,"bHaveVdW",ns->bHaveVdW,fr->ntype,TRUE);
-    
-    ns->nra_alloc = 0;
-    ns->bexcl = NULL;
-    if (!DOMAINDECOMP(cr))
-    {
-        /* This could be reduced with particle decomposition */
-        ns_realloc_natoms(ns,mtop->natoms);
-    }
-
-    ns->nblist_initialized=FALSE;
-
-    /* nbr list debug dump */
-    {
-        char *ptr=getenv("GMX_DUMP_NL");
-        if (ptr)
-        {
-            ns->dump_nl=strtol(ptr,NULL,10);
-            if (fplog)
-            {
-                fprintf(fplog, "GMX_DUMP_NL = %d", ns->dump_nl);
-            }
-        }
-        else
-        {
-            ns->dump_nl=0;
-        }
-    }
-}
-
-                        
-int search_neighbours(FILE *log,t_forcerec *fr,
-                      rvec x[],matrix box,
-                      gmx_localtop_t *top,
-                      gmx_groups_t *groups,
-                      t_commrec *cr,
-                      t_nrnb *nrnb,t_mdatoms *md,
-                      real lambda,real *dvdlambda,
-                      gmx_grppairener_t *grppener,
-                      gmx_bool bFillGrid,
-                      gmx_bool bDoLongRange,
-                      gmx_bool bDoForces,rvec *f)
-{
-    t_block  *cgs=&(top->cgs);
-    rvec     box_size,grid_x0,grid_x1;
-    int      i,j,m,ngid;
-    real     min_size,grid_dens;
-    int      nsearch;
-    gmx_bool     bGrid;
-    char     *ptr;
-    gmx_bool     *i_egp_flags;
-    int      cg_start,cg_end,start,end;
-    gmx_ns_t *ns;
-    t_grid   *grid;
-    gmx_domdec_zones_t *dd_zones;
-    put_in_list_t *put_in_list;
-       
-    ns = &fr->ns;
-
-    /* Set some local variables */
-    bGrid = fr->bGrid;
-    ngid = groups->grps[egcENER].nr;
-    
-    for(m=0; (m<DIM); m++)
-    {
-        box_size[m] = box[m][m];
-    }
-  
-    if (fr->ePBC != epbcNONE)
-    {
-        if (sqr(fr->rlistlong) >= max_cutoff2(fr->ePBC,box))
-        {
-            gmx_fatal(FARGS,"One of the box vectors has become shorter than twice the cut-off length or box_yy-|box_zy| or box_zz has become smaller than the cut-off.");
-        }
-        if (!bGrid)
-        {
-            min_size = min(box_size[XX],min(box_size[YY],box_size[ZZ]));
-            if (2*fr->rlistlong >= min_size)
-                gmx_fatal(FARGS,"One of the box diagonal elements has become smaller than twice the cut-off length.");
-        }
-    }
-    
-    if (DOMAINDECOMP(cr))
-    {
-        ns_realloc_natoms(ns,cgs->index[cgs->nr]);
-    }
-    debug_gmx();
-    
-    /* Reset the neighbourlists */
-    reset_neighbor_list(fr,FALSE,-1,-1);
-    
-    if (bGrid && bFillGrid)
-    {
-               
-        grid = ns->grid;
-        if (DOMAINDECOMP(cr))
-        {
-            dd_zones = domdec_zones(cr->dd);
-        }
-        else
-        {
-            dd_zones = NULL;
-
-            get_nsgrid_boundaries(grid,NULL,box,NULL,NULL,NULL,
-                                  cgs->nr,fr->cg_cm,grid_x0,grid_x1,&grid_dens);
-
-            grid_first(log,grid,NULL,NULL,fr->ePBC,box,grid_x0,grid_x1,
-                       fr->rlistlong,grid_dens);
-        }
-        debug_gmx();
-        
-        /* Don't know why this all is... (DvdS 3/99) */
-#ifndef SEGV
-        start = 0;
-        end   = cgs->nr;
-#else
-        start = fr->cg0;
-        end   = (cgs->nr+1)/2;
-#endif
-        
-        if (DOMAINDECOMP(cr))
-        {
-            end = cgs->nr;
-            fill_grid(log,dd_zones,grid,end,-1,end,fr->cg_cm);
-            grid->icg0 = 0;
-            grid->icg1 = dd_zones->izone[dd_zones->nizone-1].cg1;
-        }
-        else
-        {
-            fill_grid(log,NULL,grid,cgs->nr,fr->cg0,fr->hcg,fr->cg_cm);
-            grid->icg0 = fr->cg0;
-            grid->icg1 = fr->hcg;
-            debug_gmx();
-            
-            if (PARTDECOMP(cr))
-                mv_grid(cr,grid);
-            debug_gmx();
-        }
-        
-        calc_elemnr(log,grid,start,end,cgs->nr);
-        calc_ptrs(grid);
-        grid_last(log,grid,start,end,cgs->nr);
-        
-        if (gmx_debug_at)
-        {
-            check_grid(debug,grid);
-            print_grid(debug,grid);
-        }
-    }
-    else if (fr->n_tpi)
-    {
-        /* Set the grid cell index for the test particle only.
-         * The cell to cg index is not corrected, but that does not matter.
-         */
-        fill_grid(log,NULL,ns->grid,fr->hcg,fr->hcg-1,fr->hcg,fr->cg_cm);
-    }
-    debug_gmx();
-    
-    if (!fr->ns.bCGlist)
-    {
-        put_in_list = put_in_list_at;
-    }
-    else
-    {
-        put_in_list = put_in_list_cg;
-    }
-
-    /* Do the core! */
-    if (bGrid)
-    {
-        grid = ns->grid;
-        nsearch = nsgrid_core(log,cr,fr,box,box_size,ngid,top,
-                              grid,x,ns->bexcl,ns->bExcludeAlleg,
-                              nrnb,md,lambda,dvdlambda,grppener,
-                              put_in_list,ns->bHaveVdW,
-                              bDoLongRange,bDoForces,f,
-                              FALSE);
-        
-        /* neighbour searching withouth QMMM! QM atoms have zero charge in
-         * the classical calculation. The charge-charge interaction
-         * between QM and MM atoms is handled in the QMMM core calculation
-         * (see QMMM.c). The VDW however, we'd like to compute classically
-         * and the QM MM atom pairs have just been put in the
-         * corresponding neighbourlists. in case of QMMM we still need to
-         * fill a special QMMM neighbourlist that contains all neighbours
-         * of the QM atoms. If bQMMM is true, this list will now be made: 
-         */
-        if (fr->bQMMM && fr->qr->QMMMscheme!=eQMMMschemeoniom)
-        {
-            nsearch += nsgrid_core(log,cr,fr,box,box_size,ngid,top,
-                                   grid,x,ns->bexcl,ns->bExcludeAlleg,
-                                   nrnb,md,lambda,dvdlambda,grppener,
-                                   put_in_list_qmmm,ns->bHaveVdW,
-                                   bDoLongRange,bDoForces,f,
-                                   TRUE);
-        }
-    }
-    else 
-    {
-        nsearch = ns_simple_core(fr,top,md,box,box_size,
-                                 ns->bexcl,ns->simple_aaj,
-                                 ngid,ns->ns_buf,put_in_list,ns->bHaveVdW);
-    }
-    debug_gmx();
-    
-#ifdef DEBUG
-    pr_nsblock(log);
-#endif
-    
-    inc_nrnb(nrnb,eNR_NS,nsearch);
-    /* inc_nrnb(nrnb,eNR_LR,fr->nlr); */
-    
-    return nsearch;
-}
-
-int natoms_beyond_ns_buffer(t_inputrec *ir,t_forcerec *fr,t_block *cgs,
-                            matrix scale_tot,rvec *x)
-{
-    int  cg0,cg1,cg,a0,a1,a,i,j;
-    real rint,hbuf2,scale;
-    rvec *cg_cm,cgsc;
-    gmx_bool bIsotropic;
-    int  nBeyond;
-    
-    nBeyond = 0;
-    
-    rint = max(ir->rcoulomb,ir->rvdw);
-    if (ir->rlist < rint)
-    {
-        gmx_fatal(FARGS,"The neighbor search buffer has negative size: %f nm",
-                  ir->rlist - rint);
-    }
-    cg_cm = fr->cg_cm;
-    
-    cg0 = fr->cg0;
-    cg1 = fr->hcg;
-    
-    if (!EI_DYNAMICS(ir->eI) || !DYNAMIC_BOX(*ir))
-    {
-        hbuf2 = sqr(0.5*(ir->rlist - rint));
-        for(cg=cg0; cg<cg1; cg++)
-        {
-            a0 = cgs->index[cg];
-            a1 = cgs->index[cg+1];
-            for(a=a0; a<a1; a++)
-            {
-                if (distance2(cg_cm[cg],x[a]) > hbuf2)
-                {
-                    nBeyond++;
-                }
-            }
-        }
-    }
-    else
-    {
-        bIsotropic = TRUE;
-        scale = scale_tot[0][0];
-        for(i=1; i<DIM; i++)
-        {
-            /* With anisotropic scaling, the original spherical ns volumes become
-             * ellipsoids. To avoid costly transformations we use the minimum
-             * eigenvalue of the scaling matrix for determining the buffer size.
-             * Since the lower half is 0, the eigenvalues are the diagonal elements.
-             */
-            scale = min(scale,scale_tot[i][i]);
-            if (scale_tot[i][i] != scale_tot[i-1][i-1])
-            {
-                bIsotropic = FALSE;
-            }
-            for(j=0; j<i; j++)
-            {
-                if (scale_tot[i][j] != 0)
-                {
-                    bIsotropic = FALSE;
-                }
-            }
-        }
-        hbuf2 = sqr(0.5*(scale*ir->rlist - rint));
-        if (bIsotropic)
-        {
-            for(cg=cg0; cg<cg1; cg++)
-            {
-                svmul(scale,cg_cm[cg],cgsc);
-                a0 = cgs->index[cg];
-                a1 = cgs->index[cg+1];
-                for(a=a0; a<a1; a++)
-                {
-                    if (distance2(cgsc,x[a]) > hbuf2)
-                    {                    
-                        nBeyond++;
-                    }
-                }
-            }
-        }
-        else
-        {
-            /* Anistropic scaling */
-            for(cg=cg0; cg<cg1; cg++)
-            {
-                /* Since scale_tot contains the transpose of the scaling matrix,
-                 * we need to multiply with the transpose.
-                 */
-                tmvmul_ur0(scale_tot,cg_cm[cg],cgsc);
-                a0 = cgs->index[cg];
-                a1 = cgs->index[cg+1];
-                for(a=a0; a<a1; a++)
-                {
-                    if (distance2(cgsc,x[a]) > hbuf2)
-                    {
-                        nBeyond++;
-                    }
-                }
-            }
-        }
-    }
-    
-    return nBeyond;
-}
diff --git a/src/mdlib/sim_util.c b/src/mdlib/sim_util.c
deleted file mode 100644 (file)
index d8d94ff..0000000
+++ /dev/null
@@ -1,1535 +0,0 @@
-/* -*- mode: c; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; c-file-style: "stroustrup"; -*-
- *
- * 
- *                This source code is part of
- * 
- *                 G   R   O   M   A   C   S
- * 
- *          GROningen MAchine for Chemical Simulations
- * 
- *                        VERSION 3.2.0
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
- * 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.
-
- * 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:
- * GROwing Monsters And Cloning Shrimps
- */
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#ifdef GMX_CRAY_XT3
-#include<catamount/dclock.h>
-#endif
-
-
-#include <stdio.h>
-#include <time.h>
-#ifdef HAVE_SYS_TIME_H
-#include <sys/time.h>
-#endif
-#include <math.h>
-#include "typedefs.h"
-#include "string2.h"
-#include "gmxfio.h"
-#include "smalloc.h"
-#include "names.h"
-#include "confio.h"
-#include "mvdata.h"
-#include "txtdump.h"
-#include "pbc.h"
-#include "chargegroup.h"
-#include "vec.h"
-#include "time.h"
-#include "nrnb.h"
-#include "mshift.h"
-#include "mdrun.h"
-#include "update.h"
-#include "physics.h"
-#include "main.h"
-#include "mdatoms.h"
-#include "force.h"
-#include "bondf.h"
-#include "pme.h"
-#include "pppm.h"
-#include "disre.h"
-#include "orires.h"
-#include "network.h"
-#include "calcmu.h"
-#include "constr.h"
-#include "xvgr.h"
-#include "trnio.h"
-#include "xtcio.h"
-#include "copyrite.h"
-
-#include "mpelogging.h"
-#include "domdec.h"
-#include "partdec.h"
-#include "gmx_wallcycle.h"
-#include "genborn.h"
-
-#ifdef GMX_LIB_MPI
-#include <mpi.h>
-#endif
-#ifdef GMX_THREADS
-#include "tmpi.h"
-#endif
-
-#include "qmmm.h"
-
-#if 0
-typedef struct gmx_timeprint {
-    
-} t_gmx_timeprint;
-#endif
-
-/* Portable version of ctime_r implemented in src/gmxlib/string2.c, but we do not want it declared in public installed headers */
-char *
-gmx_ctime_r(const time_t *clock,char *buf, int n);
-
-
-double
-gmx_gettime()
-{
-#ifdef HAVE_GETTIMEOFDAY
-       struct timeval t;
-       struct timezone tz = { 0,0 };
-       double seconds;
-       
-       gettimeofday(&t,&tz);
-       
-       seconds = (double) t.tv_sec + 1e-6*(double)t.tv_usec;
-       
-       return seconds;
-#else
-       double  seconds;
-       
-       seconds = time(NULL);
-       
-       return seconds;
-#endif
-}
-
-
-#define difftime(end,start) ((double)(end)-(double)(start))
-
-void print_time(FILE *out,gmx_runtime_t *runtime,gmx_large_int_t step,   
-                t_inputrec *ir, t_commrec *cr)
-{
-    time_t finish;
-    char   timebuf[STRLEN];
-    double dt;
-    char buf[48];
-    
-#ifndef GMX_THREADS
-    if (!PAR(cr))
-#endif
-    {
-        fprintf(out,"\r");
-    }
-    fprintf(out,"step %s",gmx_step_str(step,buf));
-    if ((step >= ir->nstlist))
-    {
-        if ((ir->nstlist == 0) || ((step % ir->nstlist) == 0))
-        {
-            /* We have done a full cycle let's update time_per_step */
-            runtime->last = gmx_gettime();
-            dt = difftime(runtime->last,runtime->real);
-            runtime->time_per_step = dt/(step - ir->init_step + 1);
-        }
-        dt = (ir->nsteps + ir->init_step - step)*runtime->time_per_step;
-        
-        if (ir->nsteps >= 0)
-        {
-            if (dt >= 300)
-            {    
-                finish = (time_t) (runtime->last + dt);
-                gmx_ctime_r(&finish,timebuf,STRLEN);
-                sprintf(buf,"%s",timebuf);
-                buf[strlen(buf)-1]='\0';
-                fprintf(out,", will finish %s",buf);
-            }
-            else
-                fprintf(out,", remaining runtime: %5d s          ",(int)dt);
-        }
-        else
-        {
-            fprintf(out," performance: %.1f ns/day    ",
-                    ir->delta_t/1000*24*60*60/runtime->time_per_step);
-        }
-    }
-#ifndef GMX_THREADS
-    if (PAR(cr))
-    {
-        fprintf(out,"\n");
-    }
-#endif
-
-    fflush(out);
-}
-
-#ifdef NO_CLOCK 
-#define clock() -1
-#endif
-
-static double set_proctime(gmx_runtime_t *runtime)
-{
-    double diff;
-#ifdef GMX_CRAY_XT3
-    double prev;
-
-    prev = runtime->proc;
-    runtime->proc = dclock();
-    
-    diff = runtime->proc - prev;
-#else
-    clock_t prev;
-
-    prev = runtime->proc;
-    runtime->proc = clock();
-
-    diff = (double)(runtime->proc - prev)/(double)CLOCKS_PER_SEC;
-#endif
-    if (diff < 0)
-    {
-        /* The counter has probably looped, ignore this data */
-        diff = 0;
-    }
-
-    return diff;
-}
-
-void runtime_start(gmx_runtime_t *runtime)
-{
-    runtime->real = gmx_gettime();
-    runtime->proc          = 0;
-    set_proctime(runtime);
-    runtime->realtime      = 0;
-    runtime->proctime      = 0;
-    runtime->last          = 0;
-    runtime->time_per_step = 0;
-}
-
-void runtime_end(gmx_runtime_t *runtime)
-{
-    double now;
-    
-    now = gmx_gettime();
-    
-    runtime->proctime += set_proctime(runtime);
-    runtime->realtime  = now - runtime->real;
-    runtime->real      = now;
-}
-
-void runtime_upd_proc(gmx_runtime_t *runtime)
-{
-    runtime->proctime += set_proctime(runtime);
-}
-
-void print_date_and_time(FILE *fplog,int nodeid,const char *title,
-                         const gmx_runtime_t *runtime)
-{
-    int i;
-    char timebuf[STRLEN];
-    char time_string[STRLEN];
-    time_t tmptime;
-
-    if (fplog)
-    {
-        if (runtime != NULL)
-        {
-            tmptime = (time_t) runtime->real;
-            gmx_ctime_r(&tmptime,timebuf,STRLEN);
-        }
-        else
-        {
-            tmptime = (time_t) gmx_gettime();
-            gmx_ctime_r(&tmptime,timebuf,STRLEN);
-        }
-        for(i=0; timebuf[i]>=' '; i++)
-        {
-            time_string[i]=timebuf[i];
-        }
-        time_string[i]='\0';
-
-        fprintf(fplog,"%s on node %d %s\n",title,nodeid,time_string);
-    }
-}
-
-static void sum_forces(int start,int end,rvec f[],rvec flr[])
-{
-  int i;
-  
-  if (gmx_debug_at) {
-    pr_rvecs(debug,0,"fsr",f+start,end-start);
-    pr_rvecs(debug,0,"flr",flr+start,end-start);
-  }
-  for(i=start; (i<end); i++)
-    rvec_inc(f[i],flr[i]);
-}
-
-/* 
- * calc_f_el calculates forces due to an electric field.
- *
- * force is kJ mol^-1 nm^-1 = e * kJ mol^-1 nm^-1 / e 
- *
- * Et[] contains the parameters for the time dependent 
- * part of the field (not yet used). 
- * Ex[] contains the parameters for
- * the spatial dependent part of the field. You can have cool periodic
- * fields in principle, but only a constant field is supported
- * now. 
- * The function should return the energy due to the electric field
- * (if any) but for now returns 0.
- *
- * WARNING:
- * There can be problems with the virial.
- * Since the field is not self-consistent this is unavoidable.
- * For neutral molecules the virial is correct within this approximation.
- * For neutral systems with many charged molecules the error is small.
- * But for systems with a net charge or a few charged molecules
- * the error can be significant when the field is high.
- * Solution: implement a self-consitent electric field into PME.
- */
-static void calc_f_el(FILE *fp,int  start,int homenr,
-                      real charge[],rvec x[],rvec f[],
-                      t_cosines Ex[],t_cosines Et[],double t)
-{
-    rvec Ext;
-    real t0;
-    int  i,m;
-    
-    for(m=0; (m<DIM); m++)
-    {
-        if (Et[m].n > 0)
-        {
-            if (Et[m].n == 3)
-            {
-                t0 = Et[m].a[1];
-                Ext[m] = cos(Et[m].a[0]*(t-t0))*exp(-sqr(t-t0)/(2.0*sqr(Et[m].a[2])));
-            }
-            else
-            {
-                Ext[m] = cos(Et[m].a[0]*t);
-            }
-        }
-        else
-        {
-            Ext[m] = 1.0;
-        }
-        if (Ex[m].n > 0)
-        {
-            /* Convert the field strength from V/nm to MD-units */
-            Ext[m] *= Ex[m].a[0]*FIELDFAC;
-            for(i=start; (i<start+homenr); i++)
-                f[i][m] += charge[i]*Ext[m];
-        }
-        else
-        {
-            Ext[m] = 0;
-        }
-    }
-    if (fp != NULL)
-    {
-        fprintf(fp,"%10g  %10g  %10g  %10g #FIELD\n",t,
-                Ext[XX]/FIELDFAC,Ext[YY]/FIELDFAC,Ext[ZZ]/FIELDFAC);
-    }
-}
-
-static void calc_virial(FILE *fplog,int start,int homenr,rvec x[],rvec f[],
-                       tensor vir_part,t_graph *graph,matrix box,
-                       t_nrnb *nrnb,const t_forcerec *fr,int ePBC)
-{
-  int i,j;
-  tensor virtest;
-
-  /* The short-range virial from surrounding boxes */
-  clear_mat(vir_part);
-  calc_vir(fplog,SHIFTS,fr->shift_vec,fr->fshift,vir_part,ePBC==epbcSCREW,box);
-  inc_nrnb(nrnb,eNR_VIRIAL,SHIFTS);
-  
-  /* Calculate partial virial, for local atoms only, based on short range. 
-   * Total virial is computed in global_stat, called from do_md 
-   */
-  f_calc_vir(fplog,start,start+homenr,x,f,vir_part,graph,box);
-  inc_nrnb(nrnb,eNR_VIRIAL,homenr);
-
-  /* Add position restraint contribution */
-  for(i=0; i<DIM; i++) {
-    vir_part[i][i] += fr->vir_diag_posres[i];
-  }
-
-  /* Add wall contribution */
-  for(i=0; i<DIM; i++) {
-    vir_part[i][ZZ] += fr->vir_wall_z[i];
-  }
-
-  if (debug)
-    pr_rvecs(debug,0,"vir_part",vir_part,DIM);
-}
-
-static void print_large_forces(FILE *fp,t_mdatoms *md,t_commrec *cr,
-                              gmx_large_int_t step,real pforce,rvec *x,rvec *f)
-{
-  int  i;
-  real pf2,fn2;
-  char buf[STEPSTRSIZE];
-
-  pf2 = sqr(pforce);
-  for(i=md->start; i<md->start+md->homenr; i++) {
-    fn2 = norm2(f[i]);
-    /* We also catch NAN, if the compiler does not optimize this away. */
-    if (fn2 >= pf2 || fn2 != fn2) {
-      fprintf(fp,"step %s  atom %6d  x %8.3f %8.3f %8.3f  force %12.5e\n",
-             gmx_step_str(step,buf),
-             ddglatnr(cr->dd,i),x[i][XX],x[i][YY],x[i][ZZ],sqrt(fn2));
-    }
-  }
-}
-
-void do_force(FILE *fplog,t_commrec *cr,
-              t_inputrec *inputrec,
-              gmx_large_int_t step,t_nrnb *nrnb,gmx_wallcycle_t wcycle,
-              gmx_localtop_t *top,
-              gmx_mtop_t *mtop,
-              gmx_groups_t *groups,
-              matrix box,rvec x[],history_t *hist,
-              rvec f[],
-              tensor vir_force,
-              t_mdatoms *mdatoms,
-              gmx_enerdata_t *enerd,t_fcdata *fcd,
-              real lambda,t_graph *graph,
-              t_forcerec *fr,gmx_vsite_t *vsite,rvec mu_tot,
-              double t,FILE *field,gmx_edsam_t ed,
-              gmx_bool bBornRadii,
-              int flags)
-{
-    int    cg0,cg1,i,j;
-    int    start,homenr;
-    double mu[2*DIM]; 
-    gmx_bool   bSepDVDL,bStateChanged,bNS,bFillGrid,bCalcCGCM,bBS;
-    gmx_bool   bDoLongRange,bDoForces,bSepLRF;
-    matrix boxs;
-    real   e,v,dvdl;
-    t_pbc  pbc;
-    float  cycles_ppdpme,cycles_pme,cycles_seppme,cycles_force;
-  
-    start  = mdatoms->start;
-    homenr = mdatoms->homenr;
-
-    bSepDVDL = (fr->bSepDVDL && do_per_step(step,inputrec->nstlog));
-
-    clear_mat(vir_force);
-
-    if (PARTDECOMP(cr))
-    {
-        pd_cg_range(cr,&cg0,&cg1);
-    }
-    else
-    {
-        cg0 = 0;
-        if (DOMAINDECOMP(cr))
-        {
-            cg1 = cr->dd->ncg_tot;
-        }
-        else
-        {
-            cg1 = top->cgs.nr;
-        }
-        if (fr->n_tpi > 0)
-        {
-            cg1--;
-        }
-    }
-
-    bStateChanged = (flags & GMX_FORCE_STATECHANGED);
-    bNS           = (flags & GMX_FORCE_NS) && (fr->bAllvsAll==FALSE); 
-    bFillGrid     = (bNS && bStateChanged);
-    bCalcCGCM     = (bFillGrid && !DOMAINDECOMP(cr));
-    bDoLongRange  = (fr->bTwinRange && bNS && (flags & GMX_FORCE_DOLR));
-    bDoForces     = (flags & GMX_FORCE_FORCES);
-    bSepLRF       = (bDoLongRange && bDoForces && (flags & GMX_FORCE_SEPLRF));
-
-    if (bStateChanged)
-    {
-        update_forcerec(fplog,fr,box);
-        
-        /* Calculate total (local) dipole moment in a temporary common array. 
-         * This makes it possible to sum them over nodes faster.
-         */
-        calc_mu(start,homenr,
-                x,mdatoms->chargeA,mdatoms->chargeB,mdatoms->nChargePerturbed,
-                mu,mu+DIM);
-    }
-  
-  if (fr->ePBC != epbcNONE) { 
-    /* Compute shift vectors every step,
-     * because of pressure coupling or box deformation!
-     */
-    if ((flags & GMX_FORCE_DYNAMICBOX) && bStateChanged)
-      calc_shifts(box,fr->shift_vec);
-    
-    if (bCalcCGCM) { 
-      put_charge_groups_in_box(fplog,cg0,cg1,fr->ePBC,box,
-                              &(top->cgs),x,fr->cg_cm);
-      inc_nrnb(nrnb,eNR_CGCM,homenr);
-      inc_nrnb(nrnb,eNR_RESETX,cg1-cg0);
-    } 
-    else if (EI_ENERGY_MINIMIZATION(inputrec->eI) && graph) {
-      unshift_self(graph,box,x);
-    }
-  } 
-  else if (bCalcCGCM) {
-    calc_cgcm(fplog,cg0,cg1,&(top->cgs),x,fr->cg_cm);
-    inc_nrnb(nrnb,eNR_CGCM,homenr);
-  }
-  
-  if (bCalcCGCM) {
-    if (PAR(cr)) {
-      move_cgcm(fplog,cr,fr->cg_cm);
-    }
-    if (gmx_debug_at)
-      pr_rvecs(debug,0,"cgcm",fr->cg_cm,top->cgs.nr);
-  }
-
-#ifdef GMX_MPI
-  if (!(cr->duty & DUTY_PME)) {
-    /* Send particle coordinates to the pme nodes.
-     * Since this is only implemented for domain decomposition
-     * and domain decomposition does not use the graph,
-     * we do not need to worry about shifting.
-     */    
-
-    wallcycle_start(wcycle,ewcPP_PMESENDX);
-    GMX_MPE_LOG(ev_send_coordinates_start);
-
-    bBS = (inputrec->nwall == 2);
-    if (bBS) {
-      copy_mat(box,boxs);
-      svmul(inputrec->wall_ewald_zfac,boxs[ZZ],boxs[ZZ]);
-    }
-
-    gmx_pme_send_x(cr,bBS ? boxs : box,x,
-                   mdatoms->nChargePerturbed,lambda,
-                   ( flags & GMX_FORCE_VIRIAL),step);
-
-    GMX_MPE_LOG(ev_send_coordinates_finish);
-    wallcycle_stop(wcycle,ewcPP_PMESENDX);
-  }
-#endif /* GMX_MPI */
-
-    /* Communicate coordinates and sum dipole if necessary */
-    if (PAR(cr))
-    {
-        wallcycle_start(wcycle,ewcMOVEX);
-        if (DOMAINDECOMP(cr))
-        {
-            dd_move_x(cr->dd,box,x);
-        }
-        else
-        {
-            move_x(fplog,cr,GMX_LEFT,GMX_RIGHT,x,nrnb);
-        }
-        /* When we don't need the total dipole we sum it in global_stat */
-        if (bStateChanged && NEED_MUTOT(*inputrec))
-        {
-            gmx_sumd(2*DIM,mu,cr);
-        }
-        wallcycle_stop(wcycle,ewcMOVEX);
-    }
-    if (bStateChanged)
-    {
-        for(i=0; i<2; i++)
-        {
-            for(j=0;j<DIM;j++)
-            {
-                fr->mu_tot[i][j] = mu[i*DIM + j];
-            }
-        }
-    }
-    if (fr->efep == efepNO)
-    {
-        copy_rvec(fr->mu_tot[0],mu_tot);
-    }
-    else
-    {
-        for(j=0; j<DIM; j++)
-        {
-            mu_tot[j] =
-                (1.0 - lambda)*fr->mu_tot[0][j] + lambda*fr->mu_tot[1][j];
-        }
-    }
-
-    /* Reset energies */
-    reset_enerdata(&(inputrec->opts),fr,bNS,enerd,MASTER(cr));
-    clear_rvecs(SHIFTS,fr->fshift);
-
-    if (bNS)
-    {
-        wallcycle_start(wcycle,ewcNS);
-        
-        if (graph && bStateChanged)
-        {
-            /* Calculate intramolecular shift vectors to make molecules whole */
-            mk_mshift(fplog,graph,fr->ePBC,box,x);
-        }
-
-        /* Reset long range forces if necessary */
-        if (fr->bTwinRange)
-        {
-            /* Reset the (long-range) forces if necessary */
-            clear_rvecs(fr->natoms_force_constr,bSepLRF ? fr->f_twin : f);
-        }
-
-        /* Do the actual neighbour searching and if twin range electrostatics
-         * also do the calculation of long range forces and energies.
-         */
-        dvdl = 0; 
-        ns(fplog,fr,x,box,
-           groups,&(inputrec->opts),top,mdatoms,
-           cr,nrnb,lambda,&dvdl,&enerd->grpp,bFillGrid,
-           bDoLongRange,bDoForces,bSepLRF ? fr->f_twin : f);
-        if (bSepDVDL)
-        {
-            fprintf(fplog,sepdvdlformat,"LR non-bonded",0.0,dvdl);
-        }
-        enerd->dvdl_lin += dvdl;
-        
-        wallcycle_stop(wcycle,ewcNS);
-    }
-       
-    if (inputrec->implicit_solvent && bNS) 
-    {
-        make_gb_nblist(cr,inputrec->gb_algorithm,inputrec->rlist,
-                       x,box,fr,&top->idef,graph,fr->born);
-    }
-       
-    if (DOMAINDECOMP(cr))
-    {
-        if (!(cr->duty & DUTY_PME))
-        {
-            wallcycle_start(wcycle,ewcPPDURINGPME);
-            dd_force_flop_start(cr->dd,nrnb);
-        }
-    }
-       
-    /* Start the force cycle counter.
-     * This counter is stopped in do_forcelow_level.
-     * No parallel communication should occur while this counter is running,
-     * since that will interfere with the dynamic load balancing.
-     */
-    wallcycle_start(wcycle,ewcFORCE);
-    
-    if (bDoForces)
-    {
-        /* Reset forces for which the virial is calculated separately:
-         * PME/Ewald forces if necessary */
-        if (fr->bF_NoVirSum) 
-        {
-            if (flags & GMX_FORCE_VIRIAL)
-            {
-                fr->f_novirsum = fr->f_novirsum_alloc;
-                GMX_BARRIER(cr->mpi_comm_mygroup);
-                if (fr->bDomDec)
-                {
-                    clear_rvecs(fr->f_novirsum_n,fr->f_novirsum);
-                }
-                else
-                {
-                    clear_rvecs(homenr,fr->f_novirsum+start);
-                }
-                GMX_BARRIER(cr->mpi_comm_mygroup);
-            }
-            else
-            {
-                /* We are not calculating the pressure so we do not need
-                 * a separate array for forces that do not contribute
-                 * to the pressure.
-                 */
-                fr->f_novirsum = f;
-            }
-        }
-
-        if (bSepLRF)
-        {
-            /* Add the long range forces to the short range forces */
-            for(i=0; i<fr->natoms_force_constr; i++)
-            {
-                copy_rvec(fr->f_twin[i],f[i]);
-            }
-        }
-        else if (!(fr->bTwinRange && bNS))
-        {
-            /* Clear the short-range forces */
-            clear_rvecs(fr->natoms_force_constr,f);
-        }
-
-        clear_rvec(fr->vir_diag_posres);
-
-        GMX_BARRIER(cr->mpi_comm_mygroup);
-    }
-    if (inputrec->ePull == epullCONSTRAINT)
-    {
-        clear_pull_forces(inputrec->pull);
-    }
-
-    /* update QMMMrec, if necessary */
-    if(fr->bQMMM)
-    {
-        update_QMMMrec(cr,fr,x,mdatoms,box,top);
-    }
-
-    if ((flags & GMX_FORCE_BONDED) && top->idef.il[F_POSRES].nr > 0)
-    {
-        /* Position restraints always require full pbc */
-        set_pbc(&pbc,inputrec->ePBC,box);
-        v = posres(top->idef.il[F_POSRES].nr,top->idef.il[F_POSRES].iatoms,
-                   top->idef.iparams_posres,
-                   (const rvec*)x,fr->f_novirsum,fr->vir_diag_posres,
-                   inputrec->ePBC==epbcNONE ? NULL : &pbc,lambda,&dvdl,
-                   fr->rc_scaling,fr->ePBC,fr->posres_com,fr->posres_comB);
-        if (bSepDVDL)
-        {
-            fprintf(fplog,sepdvdlformat,
-                    interaction_function[F_POSRES].longname,v,dvdl);
-        }
-        enerd->term[F_POSRES] += v;
-        /* This linear lambda dependence assumption is only correct
-         * when only k depends on lambda,
-         * not when the reference position depends on lambda.
-         * grompp checks for this.
-         */
-        enerd->dvdl_lin += dvdl;
-        inc_nrnb(nrnb,eNR_POSRES,top->idef.il[F_POSRES].nr/2);
-    }
-
-    /* Compute the bonded and non-bonded energies and optionally forces */    
-    do_force_lowlevel(fplog,step,fr,inputrec,&(top->idef),
-                      cr,nrnb,wcycle,mdatoms,&(inputrec->opts),
-                      x,hist,f,enerd,fcd,mtop,top,fr->born,
-                      &(top->atomtypes),bBornRadii,box,
-                      lambda,graph,&(top->excls),fr->mu_tot,
-                      flags,&cycles_pme);
-    
-    cycles_force = wallcycle_stop(wcycle,ewcFORCE);
-    GMX_BARRIER(cr->mpi_comm_mygroup);
-    
-    if (ed)
-    {
-        do_flood(fplog,cr,x,f,ed,box,step);
-    }
-       
-    if (DOMAINDECOMP(cr))
-    {
-        dd_force_flop_stop(cr->dd,nrnb);
-        if (wcycle)
-        {
-            dd_cycles_add(cr->dd,cycles_force-cycles_pme,ddCyclF);
-        }
-    }
-    
-    if (bDoForces)
-    {
-        if (IR_ELEC_FIELD(*inputrec))
-        {
-            /* Compute forces due to electric field */
-            calc_f_el(MASTER(cr) ? field : NULL,
-                      start,homenr,mdatoms->chargeA,x,fr->f_novirsum,
-                      inputrec->ex,inputrec->et,t);
-        }
-        
-        /* Communicate the forces */
-        if (PAR(cr))
-        {
-            wallcycle_start(wcycle,ewcMOVEF);
-            if (DOMAINDECOMP(cr))
-            {
-                dd_move_f(cr->dd,f,fr->fshift);
-                /* Do we need to communicate the separate force array
-                 * for terms that do not contribute to the single sum virial?
-                 * Position restraints and electric fields do not introduce
-                 * inter-cg forces, only full electrostatics methods do.
-                 * When we do not calculate the virial, fr->f_novirsum = f,
-                 * so we have already communicated these forces.
-                 */
-                if (EEL_FULL(fr->eeltype) && cr->dd->n_intercg_excl &&
-                    (flags & GMX_FORCE_VIRIAL))
-                {
-                    dd_move_f(cr->dd,fr->f_novirsum,NULL);
-                }
-                if (bSepLRF)
-                {
-                    /* We should not update the shift forces here,
-                     * since f_twin is already included in f.
-                     */
-                    dd_move_f(cr->dd,fr->f_twin,NULL);
-                }
-            }
-            else
-            {
-                pd_move_f(cr,f,nrnb);
-                if (bSepLRF)
-                {
-                    pd_move_f(cr,fr->f_twin,nrnb);
-                }
-            }
-            wallcycle_stop(wcycle,ewcMOVEF);
-        }
-
-        /* If we have NoVirSum forces, but we do not calculate the virial,
-         * we sum fr->f_novirum=f later.
-         */
-        if (vsite && !(fr->bF_NoVirSum && !(flags & GMX_FORCE_VIRIAL)))
-        {
-            wallcycle_start(wcycle,ewcVSITESPREAD);
-            spread_vsite_f(fplog,vsite,x,f,fr->fshift,nrnb,
-                           &top->idef,fr->ePBC,fr->bMolPBC,graph,box,cr);
-            wallcycle_stop(wcycle,ewcVSITESPREAD);
-
-            if (bSepLRF)
-            {
-                wallcycle_start(wcycle,ewcVSITESPREAD);
-                spread_vsite_f(fplog,vsite,x,fr->f_twin,NULL,
-                               nrnb,
-                               &top->idef,fr->ePBC,fr->bMolPBC,graph,box,cr);
-                wallcycle_stop(wcycle,ewcVSITESPREAD);
-            }
-        }
-        
-        if (flags & GMX_FORCE_VIRIAL)
-        {
-            /* Calculation of the virial must be done after vsites! */
-            calc_virial(fplog,mdatoms->start,mdatoms->homenr,x,f,
-                        vir_force,graph,box,nrnb,fr,inputrec->ePBC);
-        }
-    }
-
-    if (inputrec->ePull == epullUMBRELLA || inputrec->ePull == epullCONST_F)
-    {
-        /* Calculate the center of mass forces, this requires communication,
-         * which is why pull_potential is called close to other communication.
-         * The virial contribution is calculated directly,
-         * which is why we call pull_potential after calc_virial.
-         */
-        set_pbc(&pbc,inputrec->ePBC,box);
-        dvdl = 0; 
-        enerd->term[F_COM_PULL] =
-            pull_potential(inputrec->ePull,inputrec->pull,mdatoms,&pbc,
-                           cr,t,lambda,x,f,vir_force,&dvdl);
-        if (bSepDVDL)
-        {
-            fprintf(fplog,sepdvdlformat,"Com pull",enerd->term[F_COM_PULL],dvdl);
-        }
-        enerd->dvdl_lin += dvdl;
-    }
-
-    if (PAR(cr) && !(cr->duty & DUTY_PME))
-    {
-        cycles_ppdpme = wallcycle_stop(wcycle,ewcPPDURINGPME);
-        dd_cycles_add(cr->dd,cycles_ppdpme,ddCyclPPduringPME);
-
-        /* In case of node-splitting, the PP nodes receive the long-range 
-         * forces, virial and energy from the PME nodes here.
-         */    
-        wallcycle_start(wcycle,ewcPP_PMEWAITRECVF);
-        dvdl = 0;
-        gmx_pme_receive_f(cr,fr->f_novirsum,fr->vir_el_recip,&e,&dvdl,
-                          &cycles_seppme);
-        if (bSepDVDL)
-        {
-            fprintf(fplog,sepdvdlformat,"PME mesh",e,dvdl);
-        }
-        enerd->term[F_COUL_RECIP] += e;
-        enerd->dvdl_lin += dvdl;
-        if (wcycle)
-        {
-            dd_cycles_add(cr->dd,cycles_seppme,ddCyclPME);
-        }
-        wallcycle_stop(wcycle,ewcPP_PMEWAITRECVF);
-    }
-
-    if (bDoForces && fr->bF_NoVirSum)
-    {
-        if (vsite)
-        {
-            /* Spread the mesh force on virtual sites to the other particles... 
-             * This is parallellized. MPI communication is performed
-             * if the constructing atoms aren't local.
-             */
-            wallcycle_start(wcycle,ewcVSITESPREAD);
-            spread_vsite_f(fplog,vsite,x,fr->f_novirsum,NULL,nrnb,
-                           &top->idef,fr->ePBC,fr->bMolPBC,graph,box,cr);
-            wallcycle_stop(wcycle,ewcVSITESPREAD);
-        }
-        if (flags & GMX_FORCE_VIRIAL)
-        {
-            /* Now add the forces, this is local */
-            if (fr->bDomDec)
-            {
-                sum_forces(0,fr->f_novirsum_n,f,fr->f_novirsum);
-            }
-            else
-            {
-                sum_forces(start,start+homenr,f,fr->f_novirsum);
-            }
-            if (EEL_FULL(fr->eeltype))
-            {
-                /* Add the mesh contribution to the virial */
-                m_add(vir_force,fr->vir_el_recip,vir_force);
-            }
-            if (debug)
-            {
-                pr_rvecs(debug,0,"vir_force",vir_force,DIM);
-            }
-        }
-    }
-    
-    /* Sum the potential energy terms from group contributions */
-    sum_epot(&(inputrec->opts),enerd);
-    
-    if (fr->print_force >= 0 && bDoForces)
-    {
-        print_large_forces(stderr,mdatoms,cr,step,fr->print_force,x,f);
-    }
-}
-
-void do_constrain_first(FILE *fplog,gmx_constr_t constr,
-                        t_inputrec *ir,t_mdatoms *md,
-                        t_state *state,rvec *f,
-                        t_graph *graph,t_commrec *cr,t_nrnb *nrnb,
-                        t_forcerec *fr, gmx_localtop_t *top, tensor shake_vir)
-{
-    int    i,m,start,end;
-    gmx_large_int_t step;
-    double mass,tmass,vcm[4];
-    real   dt=ir->delta_t;
-    real   dvdlambda;
-    rvec   *savex;
-    
-    snew(savex,state->natoms);
-
-    start = md->start;
-    end   = md->homenr + start;
-    
-    if (debug)
-        fprintf(debug,"vcm: start=%d, homenr=%d, end=%d\n",
-                start,md->homenr,end);
-    /* Do a first constrain to reset particles... */
-    step = ir->init_step;
-    if (fplog)
-    {
-        char buf[STEPSTRSIZE];
-        fprintf(fplog,"\nConstraining the starting coordinates (step %s)\n",
-                gmx_step_str(step,buf));
-    }
-    dvdlambda = 0;
-    
-    /* constrain the current position */
-    constrain(NULL,TRUE,FALSE,constr,&(top->idef),
-              ir,NULL,cr,step,0,md,
-              state->x,state->x,NULL,
-              state->box,state->lambda,&dvdlambda,
-              NULL,NULL,nrnb,econqCoord,ir->epc==epcMTTK,state->veta,state->veta);
-    if (EI_VV(ir->eI)) 
-    {
-        /* constrain the inital velocity, and save it */
-        /* also may be useful if we need the ekin from the halfstep for velocity verlet */
-        /* might not yet treat veta correctly */
-        constrain(NULL,TRUE,FALSE,constr,&(top->idef),
-                  ir,NULL,cr,step,0,md,
-                  state->x,state->v,state->v,
-                  state->box,state->lambda,&dvdlambda,
-                  NULL,NULL,nrnb,econqVeloc,ir->epc==epcMTTK,state->veta,state->veta);
-    }
-    /* constrain the inital velocities at t-dt/2 */
-    if (EI_STATE_VELOCITY(ir->eI) && ir->eI!=eiVV)
-    {
-        for(i=start; (i<end); i++) 
-        {
-            for(m=0; (m<DIM); m++) 
-            {
-                /* Reverse the velocity */
-                state->v[i][m] = -state->v[i][m];
-                /* Store the position at t-dt in buf */
-                savex[i][m] = state->x[i][m] + dt*state->v[i][m];
-            }
-        }
-    /* Shake the positions at t=-dt with the positions at t=0                        
-     * as reference coordinates.                                                     
-         */
-        if (fplog)
-        {
-            char buf[STEPSTRSIZE];
-            fprintf(fplog,"\nConstraining the coordinates at t0-dt (step %s)\n",
-                    gmx_step_str(step,buf));
-        }
-        dvdlambda = 0;
-        constrain(NULL,TRUE,FALSE,constr,&(top->idef),
-                  ir,NULL,cr,step,-1,md,
-                  state->x,savex,NULL,
-                  state->box,state->lambda,&dvdlambda,
-                  state->v,NULL,nrnb,econqCoord,ir->epc==epcMTTK,state->veta,state->veta);
-        
-        for(i=start; i<end; i++) {
-            for(m=0; m<DIM; m++) {
-                /* Re-reverse the velocities */
-                state->v[i][m] = -state->v[i][m];
-            }
-        }
-    }
-    
-    for(m=0; (m<4); m++)
-        vcm[m] = 0;
-    for(i=start; i<end; i++) {
-        mass = md->massT[i];
-        for(m=0; m<DIM; m++) {
-            vcm[m] += state->v[i][m]*mass;
-        }
-        vcm[3] += mass;
-    }
-    
-    if (ir->nstcomm != 0 || debug) {
-        /* Compute the global sum of vcm */
-        if (debug)
-            fprintf(debug,"vcm: %8.3f  %8.3f  %8.3f,"
-                    " total mass = %12.5e\n",vcm[XX],vcm[YY],vcm[ZZ],vcm[3]);
-        if (PAR(cr))
-            gmx_sumd(4,vcm,cr);
-        tmass = vcm[3];
-        for(m=0; (m<DIM); m++)
-            vcm[m] /= tmass;
-        if (debug) 
-            fprintf(debug,"vcm: %8.3f  %8.3f  %8.3f,"
-                    " total mass = %12.5e\n",vcm[XX],vcm[YY],vcm[ZZ],tmass);
-        if (ir->nstcomm != 0) {
-            /* Now we have the velocity of center of mass, let's remove it */
-            for(i=start; (i<end); i++) {
-                for(m=0; (m<DIM); m++)
-                    state->v[i][m] -= vcm[m];
-            }
-
-        }
-    }
-    sfree(savex);
-}
-
-void calc_enervirdiff(FILE *fplog,int eDispCorr,t_forcerec *fr)
-{
-  double eners[2],virs[2],enersum,virsum,y0,f,g,h;
-  double r0,r1,r,rc3,rc9,ea,eb,ec,pa,pb,pc,pd;
-  double invscale,invscale2,invscale3;
-  int    ri0,ri1,ri,i,offstart,offset;
-  real   scale,*vdwtab; 
-
-  fr->enershiftsix = 0;
-  fr->enershifttwelve = 0;
-  fr->enerdiffsix = 0;
-  fr->enerdifftwelve = 0;
-  fr->virdiffsix = 0;
-  fr->virdifftwelve = 0;
-
-  if (eDispCorr != edispcNO) {
-    for(i=0; i<2; i++) {
-      eners[i] = 0;
-      virs[i]  = 0;
-    }
-    if ((fr->vdwtype == evdwSWITCH) || (fr->vdwtype == evdwSHIFT)) {
-      if (fr->rvdw_switch == 0)
-       gmx_fatal(FARGS,
-                 "With dispersion correction rvdw-switch can not be zero "
-                 "for vdw-type = %s",evdw_names[fr->vdwtype]);
-
-      scale  = fr->nblists[0].tab.scale;
-      vdwtab = fr->nblists[0].vdwtab;
-
-      /* Round the cut-offs to exact table values for precision */
-      ri0 = floor(fr->rvdw_switch*scale);
-      ri1 = ceil(fr->rvdw*scale);
-      r0  = ri0/scale;
-      r1  = ri1/scale;
-      rc3 = r0*r0*r0;
-      rc9  = rc3*rc3*rc3;
-
-      if (fr->vdwtype == evdwSHIFT) {
-       /* Determine the constant energy shift below rvdw_switch */
-       fr->enershiftsix    = (real)(-1.0/(rc3*rc3)) - vdwtab[8*ri0];
-       fr->enershifttwelve = (real)( 1.0/(rc9*rc3)) - vdwtab[8*ri0 + 4];
-      }
-      /* Add the constant part from 0 to rvdw_switch.
-       * This integration from 0 to rvdw_switch overcounts the number
-       * of interactions by 1, as it also counts the self interaction.
-       * We will correct for this later.
-       */
-      eners[0] += 4.0*M_PI*fr->enershiftsix*rc3/3.0;
-      eners[1] += 4.0*M_PI*fr->enershifttwelve*rc3/3.0;
-      
-      invscale = 1.0/(scale);  
-      invscale2 = invscale*invscale;
-      invscale3 = invscale*invscale2;
-
-      /* following summation derived from cubic spline definition,
-       Numerical Recipies in C, second edition, p. 113-116.  Exact
-       for the cubic spline.  We first calculate the negative of
-       the energy from rvdw to rvdw_switch, assuming that g(r)=1,
-       and then add the more standard, abrupt cutoff correction to
-       that result, yielding the long-range correction for a
-       switched function.  We perform both the pressure and energy
-       loops at the same time for simplicity, as the computational
-       cost is low. */
-      
-      for (i=0;i<2;i++) {
-        enersum = 0.0; virsum = 0.0;
-        if (i==0)
-         offstart = 0;
-       else
-         offstart = 4;
-       for (ri=ri0; ri<ri1; ri++) {
-          r = ri*invscale;
-          ea = invscale3;
-          eb = 2.0*invscale2*r;
-          ec = invscale*r*r;
-          
-          pa = invscale3;
-          pb = 3.0*invscale2*r;
-          pc = 3.0*invscale*r*r;
-          pd = r*r*r;
-          
-          /* this "8" is from the packing in the vdwtab array - perhaps
-           should be #define'ed? */
-          offset = 8*ri + offstart;
-          y0 = vdwtab[offset];
-          f = vdwtab[offset+1];
-          g = vdwtab[offset+2];
-          h = vdwtab[offset+3];
-         
-          enersum += y0*(ea/3 + eb/2 + ec) + f*(ea/4 + eb/3 + ec/2)+
-            g*(ea/5 + eb/4 + ec/3) + h*(ea/6 + eb/5 + ec/4);  
-          virsum  +=  f*(pa/4 + pb/3 + pc/2 + pd) + 
-            2*g*(pa/5 + pb/4 + pc/3 + pd/2) + 3*h*(pa/6 + pb/5 + pc/4 + pd/3);
-         
-        }
-        enersum *= 4.0*M_PI;
-        virsum  *= 4.0*M_PI; 
-        eners[i] -= enersum;
-        virs[i]  -= virsum;
-      }
-
-      /* now add the correction for rvdw_switch to infinity */
-      eners[0] += -4.0*M_PI/(3.0*rc3);
-      eners[1] +=  4.0*M_PI/(9.0*rc9);
-      virs[0]  +=  8.0*M_PI/rc3;
-      virs[1]  += -16.0*M_PI/(3.0*rc9);
-    } 
-    else if ((fr->vdwtype == evdwCUT) || (fr->vdwtype == evdwUSER)) {
-      if (fr->vdwtype == evdwUSER && fplog)
-       fprintf(fplog,
-               "WARNING: using dispersion correction with user tables\n");
-      rc3  = fr->rvdw*fr->rvdw*fr->rvdw;
-      rc9  = rc3*rc3*rc3;
-      eners[0] += -4.0*M_PI/(3.0*rc3);
-      eners[1] +=  4.0*M_PI/(9.0*rc9);
-      virs[0]  +=  8.0*M_PI/rc3;
-      virs[1]  += -16.0*M_PI/(3.0*rc9);
-    } else {
-      gmx_fatal(FARGS,
-               "Dispersion correction is not implemented for vdw-type = %s",
-               evdw_names[fr->vdwtype]);
-    }
-    fr->enerdiffsix    = eners[0];
-    fr->enerdifftwelve = eners[1];
-    /* The 0.5 is due to the Gromacs definition of the virial */
-    fr->virdiffsix     = 0.5*virs[0];
-    fr->virdifftwelve  = 0.5*virs[1];
-  }
-}
-
-void calc_dispcorr(FILE *fplog,t_inputrec *ir,t_forcerec *fr,
-                   gmx_large_int_t step,int natoms,
-                   matrix box,real lambda,tensor pres,tensor virial,
-                   real *prescorr, real *enercorr, real *dvdlcorr)
-{
-    gmx_bool bCorrAll,bCorrPres;
-    real dvdlambda,invvol,dens,ninter,avcsix,avctwelve,enerdiff,svir=0,spres=0;
-    int  m;
-    
-    *prescorr = 0;
-    *enercorr = 0;
-    *dvdlcorr = 0;
-    
-    clear_mat(virial);
-    clear_mat(pres);
-    
-    if (ir->eDispCorr != edispcNO) {
-        bCorrAll  = (ir->eDispCorr == edispcAllEner ||
-                     ir->eDispCorr == edispcAllEnerPres);
-        bCorrPres = (ir->eDispCorr == edispcEnerPres ||
-                     ir->eDispCorr == edispcAllEnerPres);
-        
-        invvol = 1/det(box);
-        if (fr->n_tpi) 
-        {
-            /* Only correct for the interactions with the inserted molecule */
-            dens = (natoms - fr->n_tpi)*invvol;
-            ninter = fr->n_tpi;
-        } 
-        else 
-        {
-            dens = natoms*invvol;
-            ninter = 0.5*natoms;
-        }
-        
-        if (ir->efep == efepNO) 
-        {
-            avcsix    = fr->avcsix[0];
-            avctwelve = fr->avctwelve[0];
-        } 
-        else 
-        {
-            avcsix    = (1 - lambda)*fr->avcsix[0]    + lambda*fr->avcsix[1];
-            avctwelve = (1 - lambda)*fr->avctwelve[0] + lambda*fr->avctwelve[1];
-        }
-        
-        enerdiff = ninter*(dens*fr->enerdiffsix - fr->enershiftsix);
-        *enercorr += avcsix*enerdiff;
-        dvdlambda = 0.0;
-        if (ir->efep != efepNO) 
-        {
-            dvdlambda += (fr->avcsix[1] - fr->avcsix[0])*enerdiff;
-        }
-        if (bCorrAll) 
-        {
-            enerdiff = ninter*(dens*fr->enerdifftwelve - fr->enershifttwelve);
-            *enercorr += avctwelve*enerdiff;
-            if (fr->efep != efepNO) 
-            {
-                dvdlambda += (fr->avctwelve[1] - fr->avctwelve[0])*enerdiff;
-            }
-        }
-        
-        if (bCorrPres) 
-        {
-            svir = ninter*dens*avcsix*fr->virdiffsix/3.0;
-            if (ir->eDispCorr == edispcAllEnerPres)
-            {
-                svir += ninter*dens*avctwelve*fr->virdifftwelve/3.0;
-            }
-            /* The factor 2 is because of the Gromacs virial definition */
-            spres = -2.0*invvol*svir*PRESFAC;
-            
-            for(m=0; m<DIM; m++) {
-                virial[m][m] += svir;
-                pres[m][m] += spres;
-            }
-            *prescorr += spres;
-        }
-        
-        /* Can't currently control when it prints, for now, just print when degugging */
-        if (debug)
-        {
-            if (bCorrAll) {
-                fprintf(debug,"Long Range LJ corr.: <C6> %10.4e, <C12> %10.4e\n",
-                        avcsix,avctwelve);
-            }
-            if (bCorrPres) 
-            {
-                fprintf(debug,
-                        "Long Range LJ corr.: Epot %10g, Pres: %10g, Vir: %10g\n",
-                        *enercorr,spres,svir);
-            }
-            else
-            {
-                fprintf(debug,"Long Range LJ corr.: Epot %10g\n",*enercorr);
-            }
-        }
-        
-        if (fr->bSepDVDL && do_per_step(step,ir->nstlog))
-        {
-            fprintf(fplog,sepdvdlformat,"Dispersion correction",
-                    *enercorr,dvdlambda);
-        }
-        if (fr->efep != efepNO) 
-        {
-            *dvdlcorr += dvdlambda;
-        }
-    }
-}
-
-void do_pbc_first(FILE *fplog,matrix box,t_forcerec *fr,
-                 t_graph *graph,rvec x[])
-{
-  if (fplog)
-    fprintf(fplog,"Removing pbc first time\n");
-  calc_shifts(box,fr->shift_vec);
-  if (graph) {
-    mk_mshift(fplog,graph,fr->ePBC,box,x);
-    if (gmx_debug_at)
-      p_graph(debug,"do_pbc_first 1",graph);
-    shift_self(graph,box,x);
-    /* By doing an extra mk_mshift the molecules that are broken
-     * because they were e.g. imported from another software
-     * will be made whole again. Such are the healing powers
-     * of GROMACS.
-     */
-    mk_mshift(fplog,graph,fr->ePBC,box,x);
-    if (gmx_debug_at)
-      p_graph(debug,"do_pbc_first 2",graph);
-  }
-  if (fplog)
-    fprintf(fplog,"Done rmpbc\n");
-}
-
-static void low_do_pbc_mtop(FILE *fplog,int ePBC,matrix box,
-                           gmx_mtop_t *mtop,rvec x[],
-                           gmx_bool bFirst)
-{
-  t_graph *graph;
-  int mb,as,mol;
-  gmx_molblock_t *molb;
-
-  if (bFirst && fplog)
-    fprintf(fplog,"Removing pbc first time\n");
-
-  snew(graph,1);
-  as = 0;
-  for(mb=0; mb<mtop->nmolblock; mb++) {
-    molb = &mtop->molblock[mb];
-    if (molb->natoms_mol == 1 || 
-       (!bFirst && mtop->moltype[molb->type].cgs.nr == 1)) {
-      /* Just one atom or charge group in the molecule, no PBC required */
-      as += molb->nmol*molb->natoms_mol;
-    } else {
-      /* Pass NULL iso fplog to avoid graph prints for each molecule type */
-      mk_graph_ilist(NULL,mtop->moltype[molb->type].ilist,
-                    0,molb->natoms_mol,FALSE,FALSE,graph);
-      
-      for(mol=0; mol<molb->nmol; mol++) {
-       mk_mshift(fplog,graph,ePBC,box,x+as);
-       
-       shift_self(graph,box,x+as);
-       /* The molecule is whole now.
-        * We don't need the second mk_mshift call as in do_pbc_first,
-        * since we no longer need this graph.
-        */
-       
-       as += molb->natoms_mol;
-      }
-      done_graph(graph);
-    }
-  }
-  sfree(graph);
-}
-
-void do_pbc_first_mtop(FILE *fplog,int ePBC,matrix box,
-                      gmx_mtop_t *mtop,rvec x[])
-{
-  low_do_pbc_mtop(fplog,ePBC,box,mtop,x,TRUE);
-}
-
-void do_pbc_mtop(FILE *fplog,int ePBC,matrix box,
-                gmx_mtop_t *mtop,rvec x[])
-{
-  low_do_pbc_mtop(fplog,ePBC,box,mtop,x,FALSE);
-}
-
-void finish_run(FILE *fplog,t_commrec *cr,const char *confout,
-                t_inputrec *inputrec,
-                t_nrnb nrnb[],gmx_wallcycle_t wcycle,
-                gmx_runtime_t *runtime,
-                gmx_bool bWriteStat)
-{
-  int    i,j;
-  t_nrnb *nrnb_tot=NULL;
-  real   delta_t;
-  double nbfs,mflop;
-  double cycles[ewcNR];
-
-  wallcycle_sum(cr,wcycle,cycles);
-
-  if (cr->nnodes > 1) {
-    if (SIMMASTER(cr))
-      snew(nrnb_tot,1);
-#ifdef GMX_MPI
-    MPI_Reduce(nrnb->n,nrnb_tot->n,eNRNB,MPI_DOUBLE,MPI_SUM,
-               MASTERRANK(cr),cr->mpi_comm_mysim);
-#endif  
-  } else {
-    nrnb_tot = nrnb;
-  }
-    
-  if (SIMMASTER(cr)) {
-    print_flop(fplog,nrnb_tot,&nbfs,&mflop);
-    if (cr->nnodes > 1) {
-      sfree(nrnb_tot);
-    }
-  }
-
-  if ((cr->duty & DUTY_PP) && DOMAINDECOMP(cr)) {
-    print_dd_statistics(cr,inputrec,fplog);
-  }
-
-#ifdef GMX_MPI
-    if (PARTDECOMP(cr))
-    {
-        if (MASTER(cr))
-        {
-            t_nrnb     *nrnb_all;
-            int        s;
-            MPI_Status stat;
-
-            snew(nrnb_all,cr->nnodes);
-            nrnb_all[0] = *nrnb;
-            for(s=1; s<cr->nnodes; s++)
-            {
-                MPI_Recv(nrnb_all[s].n,eNRNB,MPI_DOUBLE,s,0,
-                         cr->mpi_comm_mysim,&stat);
-            }
-            pr_load(fplog,cr,nrnb_all);
-            sfree(nrnb_all);
-        }
-        else
-        {
-            MPI_Send(nrnb->n,eNRNB,MPI_DOUBLE,MASTERRANK(cr),0,
-                     cr->mpi_comm_mysim);
-        }
-    }
-#endif  
-
-  if (SIMMASTER(cr)) {
-    wallcycle_print(fplog,cr->nnodes,cr->npmenodes,runtime->realtime,
-                    wcycle,cycles);
-
-    if (EI_DYNAMICS(inputrec->eI)) {
-      delta_t = inputrec->delta_t;
-    } else {
-      delta_t = 0;
-    }
-    
-    if (fplog) {
-        print_perf(fplog,runtime->proctime,runtime->realtime,
-                   cr->nnodes-cr->npmenodes,
-                   runtime->nsteps_done,delta_t,nbfs,mflop);
-    }
-    if (bWriteStat) {
-        print_perf(stderr,runtime->proctime,runtime->realtime,
-                   cr->nnodes-cr->npmenodes,
-                   runtime->nsteps_done,delta_t,nbfs,mflop);
-    }
-
-    /*
-    runtime=inputrec->nsteps*inputrec->delta_t;
-    if (bWriteStat) {
-      if (cr->nnodes == 1)
-       fprintf(stderr,"\n\n");
-      print_perf(stderr,nodetime,realtime,runtime,&ntot,
-                cr->nnodes-cr->npmenodes,FALSE);
-    }
-    wallcycle_print(fplog,cr->nnodes,cr->npmenodes,realtime,wcycle,cycles);
-    print_perf(fplog,nodetime,realtime,runtime,&ntot,cr->nnodes-cr->npmenodes,
-              TRUE);
-    if (PARTDECOMP(cr))
-      pr_load(fplog,cr,nrnb_all);
-    if (cr->nnodes > 1)
-      sfree(nrnb_all);
-    */
-  }
-}
-
-void init_md(FILE *fplog,
-             t_commrec *cr,t_inputrec *ir,const output_env_t oenv,
-             double *t,double *t0,
-             real *lambda,double *lam0,
-             t_nrnb *nrnb,gmx_mtop_t *mtop,
-             gmx_update_t *upd,
-             int nfile,const t_filenm fnm[],
-             gmx_mdoutf_t **outf,t_mdebin **mdebin,
-             tensor force_vir,tensor shake_vir,rvec mu_tot,
-             gmx_bool *bSimAnn,t_vcm **vcm, t_state *state, unsigned long Flags)
-{
-    int  i,j,n;
-    real tmpt,mod;
-       
-    /* Initial values */
-    *t = *t0       = ir->init_t;
-    if (ir->efep != efepNO)
-    {
-        *lam0 = ir->init_lambda;
-        *lambda = *lam0 + ir->init_step*ir->delta_lambda;
-    }
-    else
-    {
-        *lambda = *lam0   = 0.0;
-    } 
-
-    *bSimAnn=FALSE;
-    for(i=0;i<ir->opts.ngtc;i++)
-    {
-        /* set bSimAnn if any group is being annealed */
-        if(ir->opts.annealing[i]!=eannNO)
-        {
-            *bSimAnn = TRUE;
-        }
-    }
-    if (*bSimAnn)
-    {
-        update_annealing_target_temp(&(ir->opts),ir->init_t);
-    }
-    
-    if (upd)
-    {
-        *upd = init_update(fplog,ir);
-    }
-    
-    if (vcm != NULL)
-    {
-        *vcm = init_vcm(fplog,&mtop->groups,ir);
-    }
-    
-    if (EI_DYNAMICS(ir->eI) && !(Flags & MD_APPENDFILES))
-    {
-        if (ir->etc == etcBERENDSEN)
-        {
-            please_cite(fplog,"Berendsen84a");
-        }
-        if (ir->etc == etcVRESCALE)
-        {
-            please_cite(fplog,"Bussi2007a");
-        }
-    }
-    
-    init_nrnb(nrnb);
-    
-    if (nfile != -1)
-    {
-        *outf = init_mdoutf(nfile,fnm,Flags,cr,ir,oenv);
-
-        *mdebin = init_mdebin((Flags & MD_APPENDFILES) ? NULL : (*outf)->fp_ene,
-                              mtop,ir, (*outf)->fp_dhdl);
-    }
-    
-    /* Initiate variables */  
-    clear_mat(force_vir);
-    clear_mat(shake_vir);
-    clear_rvec(mu_tot);
-    
-    debug_gmx();
-}
-
diff --git a/src/mdlib/tpi.c b/src/mdlib/tpi.c
deleted file mode 100644 (file)
index 8fb7353..0000000
+++ /dev/null
@@ -1,794 +0,0 @@
-/* -*- mode: c; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; c-file-style: "stroustrup"; -*-
- *
- * 
- *                This source code is part of
- * 
- *                 G   R   O   M   A   C   S
- * 
- *          GROningen MAchine for Chemical Simulations
- * 
- *                        VERSION 3.2.0
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
- * 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.
-
- * 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:
- * GROwing Monsters And Cloning Shrimps
- */
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <string.h>
-#include <time.h>
-#include <math.h>
-#include "sysstuff.h"
-#include "string2.h"
-#include "network.h"
-#include "confio.h"
-#include "copyrite.h"
-#include "smalloc.h"
-#include "nrnb.h"
-#include "main.h"
-#include "chargegroup.h"
-#include "force.h"
-#include "macros.h"
-#include "random.h"
-#include "names.h"
-#include "gmx_fatal.h"
-#include "txtdump.h"
-#include "typedefs.h"
-#include "update.h"
-#include "random.h"
-#include "constr.h"
-#include "vec.h"
-#include "statutil.h"
-#include "tgroup.h"
-#include "mdebin.h"
-#include "vsite.h"
-#include "force.h"
-#include "mdrun.h"
-#include "domdec.h"
-#include "partdec.h"
-#include "gmx_random.h"
-#include "physics.h"
-#include "xvgr.h"
-#include "mdatoms.h"
-#include "ns.h"
-#include "gmx_wallcycle.h"
-#include "mtop_util.h"
-#include "gmxfio.h"
-#include "pme.h"
-#include "gbutil.h"
-
-#if ( defined(GMX_IA32_SSE) || defined(GMX_X86_64_SSE) || defined(GMX_X86_64_SSE2) )
-#if defined(GMX_DOUBLE)
-#include "gmx_sse2_double.h"
-#else
-#include "gmx_sse2_single.h"
-#endif
-#endif
-
-
-static void global_max(t_commrec *cr,int *n)
-{
-  int *sum,i;
-
-  snew(sum,cr->nnodes);
-  sum[cr->nodeid] = *n;
-  gmx_sumi(cr->nnodes,sum,cr);
-  for(i=0; i<cr->nnodes; i++)
-    *n = max(*n,sum[i]);
-  
-  sfree(sum);
-}
-
-static void realloc_bins(double **bin,int *nbin,int nbin_new)
-{
-  int i;
-
-  if (nbin_new != *nbin) {
-    srenew(*bin,nbin_new);
-    for(i=*nbin; i<nbin_new; i++)
-      (*bin)[i] = 0;
-    *nbin = nbin_new;
-  }
-}
-
-double do_tpi(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 *inputrec,
-              gmx_mtop_t *top_global,t_fcdata *fcd,
-              t_state *state,
-              t_mdatoms *mdatoms,
-              t_nrnb *nrnb,gmx_wallcycle_t wcycle,
-              gmx_edsam_t ed,
-              t_forcerec *fr,
-              int repl_ex_nst,int repl_ex_seed,
-              real cpt_period,real max_hours,
-              const char *deviceOptions,
-              unsigned long Flags,
-              gmx_runtime_t *runtime)
-{
-  const char *TPI="Test Particle Insertion"; 
-  gmx_localtop_t *top;
-  gmx_groups_t *groups;
-  gmx_enerdata_t *enerd;
-  rvec   *f;
-  real   lambda,t,temp,beta,drmax,epot;
-  double embU,sum_embU,*sum_UgembU,V,V_all,VembU_all;
-  t_trxstatus   *status;
-  t_trxframe rerun_fr;
-  gmx_bool   bDispCorr,bCharge,bRFExcl,bNotLastFrame,bStateChanged,bNS,bOurStep;
-  tensor force_vir,shake_vir,vir,pres;
-  int    cg_tp,a_tp0,a_tp1,ngid,gid_tp,nener,e;
-  rvec   *x_mol;
-  rvec   mu_tot,x_init,dx,x_tp;
-  int    nnodes,frame,nsteps,step;
-  int    i,start,end;
-  gmx_rng_t tpi_rand;
-  FILE   *fp_tpi=NULL;
-  char   *ptr,*dump_pdb,**leg,str[STRLEN],str2[STRLEN];
-  double dbl,dump_ener;
-  gmx_bool   bCavity;
-  int    nat_cavity=0,d;
-  real   *mass_cavity=NULL,mass_tot;
-  int    nbin;
-  double invbinw,*bin,refvolshift,logV,bUlogV;
-  real dvdl,prescorr,enercorr,dvdlcorr;
-  gmx_bool bEnergyOutOfBounds;
-  const char *tpid_leg[2]={"direct","reweighted"};
-
-  /* Since there is no upper limit to the insertion energies,
-   * we need to set an upper limit for the distribution output.
-   */
-  real bU_bin_limit      = 50;
-  real bU_logV_bin_limit = bU_bin_limit + 10;
-
-  nnodes = cr->nnodes;
-
-  top = gmx_mtop_generate_local_top(top_global,inputrec);
-
-  groups = &top_global->groups;
-
-  bCavity = (inputrec->eI == eiTPIC);
-  if (bCavity) {
-    ptr = getenv("GMX_TPIC_MASSES");
-    if (ptr == NULL) {
-      nat_cavity = 1;
-    } else {
-      /* Read (multiple) masses from env var GMX_TPIC_MASSES,
-       * The center of mass of the last atoms is then used for TPIC.
-       */
-      nat_cavity = 0;
-      while (sscanf(ptr,"%lf%n",&dbl,&i) > 0) {
-       srenew(mass_cavity,nat_cavity+1);
-       mass_cavity[nat_cavity] = dbl;
-       fprintf(fplog,"mass[%d] = %f\n",
-               nat_cavity+1,mass_cavity[nat_cavity]);
-       nat_cavity++;
-       ptr += i;
-      }
-      if (nat_cavity == 0)
-       gmx_fatal(FARGS,"Found %d masses in GMX_TPIC_MASSES",nat_cavity);
-    }
-  }
-
-  /*
-  init_em(fplog,TPI,inputrec,&lambda,nrnb,mu_tot,
-  state->box,fr,mdatoms,top,cr,nfile,fnm,NULL,NULL);*/
-  /* We never need full pbc for TPI */
-  fr->ePBC = epbcXYZ;
-  /* Determine the temperature for the Boltzmann weighting */
-  temp = inputrec->opts.ref_t[0];
-  if (fplog) {
-    for(i=1; (i<inputrec->opts.ngtc); i++) {
-      if (inputrec->opts.ref_t[i] != temp) {
-       fprintf(fplog,"\nWARNING: The temperatures of the different temperature coupling groups are not identical\n\n");
-       fprintf(stderr,"\nWARNING: The temperatures of the different temperature coupling groups are not identical\n\n");
-      }
-    }
-    fprintf(fplog,
-           "\n  The temperature for test particle insertion is %.3f K\n\n",
-           temp);
-  }
-  beta = 1.0/(BOLTZ*temp);
-
-  /* Number of insertions per frame */
-  nsteps = inputrec->nsteps; 
-
-  /* Use the same neighborlist with more insertions points
-   * in a sphere of radius drmax around the initial point
-   */
-  /* This should be a proper mdp parameter */
-  drmax = inputrec->rtpi;
-
-  /* An environment variable can be set to dump all configurations
-   * to pdb with an insertion energy <= this value.
-   */
-  dump_pdb = getenv("GMX_TPI_DUMP");
-  dump_ener = 0;
-  if (dump_pdb)
-    sscanf(dump_pdb,"%lf",&dump_ener);
-
-  atoms2md(top_global,inputrec,0,NULL,0,top_global->natoms,mdatoms);
-  update_mdatoms(mdatoms,inputrec->init_lambda);
-
-  snew(enerd,1);
-  init_enerdata(groups->grps[egcENER].nr,inputrec->n_flambda,enerd);
-  snew(f,top_global->natoms);
-
-  /* Print to log file  */
-  runtime_start(runtime);
-  print_date_and_time(fplog,cr->nodeid,
-                      "Started Test Particle Insertion",runtime); 
-  wallcycle_start(wcycle,ewcRUN);
-
-  /* The last charge group is the group to be inserted */
-  cg_tp = top->cgs.nr - 1;
-  a_tp0 = top->cgs.index[cg_tp];
-  a_tp1 = top->cgs.index[cg_tp+1];
-  if (debug)
-    fprintf(debug,"TPI cg %d, atoms %d-%d\n",cg_tp,a_tp0,a_tp1);
-  if (a_tp1 - a_tp0 > 1 &&
-      (inputrec->rlist < inputrec->rcoulomb ||
-       inputrec->rlist < inputrec->rvdw))
-    gmx_fatal(FARGS,"Can not do TPI for multi-atom molecule with a twin-range cut-off");
-  snew(x_mol,a_tp1-a_tp0);
-
-  bDispCorr = (inputrec->eDispCorr != edispcNO);
-  bCharge = FALSE;
-  for(i=a_tp0; i<a_tp1; i++) {
-    /* Copy the coordinates of the molecule to be insterted */
-    copy_rvec(state->x[i],x_mol[i-a_tp0]);
-    /* Check if we need to print electrostatic energies */
-    bCharge |= (mdatoms->chargeA[i] != 0 ||
-               (mdatoms->chargeB && mdatoms->chargeB[i] != 0));
-  }
-  bRFExcl = (bCharge && EEL_RF(fr->eeltype) && fr->eeltype!=eelRF_NEC);
-
-  calc_cgcm(fplog,cg_tp,cg_tp+1,&(top->cgs),state->x,fr->cg_cm);
-  if (bCavity) {
-    if (norm(fr->cg_cm[cg_tp]) > 0.5*inputrec->rlist && fplog) {
-      fprintf(fplog, "WARNING: Your TPI molecule is not centered at 0,0,0\n");
-      fprintf(stderr,"WARNING: Your TPI molecule is not centered at 0,0,0\n");
-    }
-  } else {
-    /* Center the molecule to be inserted at zero */
-     for(i=0; i<a_tp1-a_tp0; i++)
-      rvec_dec(x_mol[i],fr->cg_cm[cg_tp]);
-  }
-
-  if (fplog) {
-    fprintf(fplog,"\nWill insert %d atoms %s partial charges\n",
-           a_tp1-a_tp0,bCharge ? "with" : "without");
-    
-    fprintf(fplog,"\nWill insert %d times in each frame of %s\n",
-           nsteps,opt2fn("-rerun",nfile,fnm));
-  }
-  
-    if (!bCavity)
-    {
-        if (inputrec->nstlist > 1)
-        {
-            if (drmax==0 && a_tp1-a_tp0==1)
-            {
-                gmx_fatal(FARGS,"Re-using the neighborlist %d times for insertions of a single atom in a sphere of radius %f does not make sense",inputrec->nstlist,drmax);
-            }
-            if (fplog)
-            {
-                fprintf(fplog,"Will use the same neighborlist for %d insertions in a sphere of radius %f\n",inputrec->nstlist,drmax);
-            }
-        }
-    }
-    else
-    {
-        if (fplog)
-        {
-            fprintf(fplog,"Will insert randomly in a sphere of radius %f around the center of the cavity\n",drmax);
-        }
-    }
-
-  ngid = groups->grps[egcENER].nr;
-  gid_tp = GET_CGINFO_GID(fr->cginfo[cg_tp]);
-  nener = 1 + ngid;
-  if (bDispCorr)
-    nener += 1;
-  if (bCharge) {
-    nener += ngid;
-    if (bRFExcl)
-      nener += 1;
-    if (EEL_FULL(fr->eeltype))
-      nener += 1;
-  }
-  snew(sum_UgembU,nener);
-
-  /* Initialize random generator */
-  tpi_rand = gmx_rng_init(inputrec->ld_seed);
-
-  if (MASTER(cr)) {
-    fp_tpi = xvgropen(opt2fn("-tpi",nfile,fnm),
-                     "TPI energies","Time (ps)",
-                     "(kJ mol\\S-1\\N) / (nm\\S3\\N)",oenv);
-    xvgr_subtitle(fp_tpi,"f. are averages over one frame",oenv);
-    snew(leg,4+nener);
-    e = 0;
-    sprintf(str,"-kT log(<Ve\\S-\\betaU\\N>/<V>)");
-    leg[e++] = strdup(str);
-    sprintf(str,"f. -kT log<e\\S-\\betaU\\N>");
-    leg[e++] = strdup(str);
-    sprintf(str,"f. <e\\S-\\betaU\\N>");
-    leg[e++] = strdup(str);
-    sprintf(str,"f. V");
-    leg[e++] = strdup(str);
-    sprintf(str,"f. <Ue\\S-\\betaU\\N>");
-    leg[e++] = strdup(str);
-    for(i=0; i<ngid; i++) {
-      sprintf(str,"f. <U\\sVdW %s\\Ne\\S-\\betaU\\N>",
-             *(groups->grpname[groups->grps[egcENER].nm_ind[i]]));
-      leg[e++] = strdup(str);
-    }
-    if (bDispCorr) {
-      sprintf(str,"f. <U\\sdisp c\\Ne\\S-\\betaU\\N>");
-      leg[e++] = strdup(str);
-    }
-    if (bCharge) {
-      for(i=0; i<ngid; i++) {
-       sprintf(str,"f. <U\\sCoul %s\\Ne\\S-\\betaU\\N>",
-               *(groups->grpname[groups->grps[egcENER].nm_ind[i]]));
-       leg[e++] = strdup(str);
-      }
-      if (bRFExcl) {
-       sprintf(str,"f. <U\\sRF excl\\Ne\\S-\\betaU\\N>");
-       leg[e++] = strdup(str);
-      }
-      if (EEL_FULL(fr->eeltype)) {
-       sprintf(str,"f. <U\\sCoul recip\\Ne\\S-\\betaU\\N>");
-       leg[e++] = strdup(str);
-      }
-    }
-    xvgr_legend(fp_tpi,4+nener,(const char**)leg,oenv);
-    for(i=0; i<4+nener; i++)
-      sfree(leg[i]);
-    sfree(leg);
-  }
-  clear_rvec(x_init);
-  V_all = 0;
-  VembU_all = 0;
-
-  invbinw = 10;
-  nbin = 10;
-  snew(bin,nbin);
-
-  bNotLastFrame = read_first_frame(oenv,&status,opt2fn("-rerun",nfile,fnm),
-                                  &rerun_fr,TRX_NEED_X);
-  frame = 0;
-
-  if (rerun_fr.natoms - (bCavity ? nat_cavity : 0) !=
-      mdatoms->nr - (a_tp1 - a_tp0))
-    gmx_fatal(FARGS,"Number of atoms in trajectory (%d)%s "
-             "is not equal the number in the run input file (%d) "
-             "minus the number of atoms to insert (%d)\n",
-             rerun_fr.natoms,bCavity ? " minus one" : "",
-             mdatoms->nr,a_tp1-a_tp0);
-
-  refvolshift = log(det(rerun_fr.box));
-
-#if ( defined(GMX_IA32_SSE) || defined(GMX_X86_64_SSE) || defined(GMX_X86_64_SSE2) )
-    /* Make sure we don't detect SSE overflow generated before this point */
-    gmx_mm_check_and_reset_overflow();
-#endif
-
-    while (bNotLastFrame)
-    {
-        lambda = rerun_fr.lambda;
-        t = rerun_fr.time;
-        
-        sum_embU = 0;
-        for(e=0; e<nener; e++)
-        {
-            sum_UgembU[e] = 0;
-        }
-        
-        /* Copy the coordinates from the input trajectory */
-        for(i=0; i<rerun_fr.natoms; i++)
-        {
-            copy_rvec(rerun_fr.x[i],state->x[i]);
-        }
-        
-        V = det(rerun_fr.box);
-        logV = log(V);
-        
-        bStateChanged = TRUE;
-        bNS = TRUE;
-        for(step=0; step<nsteps; step++)
-        {
-            /* In parallel all nodes generate all random configurations.
-             * In that way the result is identical to a single cpu tpi run.
-             */
-            if (!bCavity)
-            {
-                /* Random insertion in the whole volume */
-                bNS = (step % inputrec->nstlist == 0);
-                if (bNS)
-                {
-                    /* Generate a random position in the box */
-                    x_init[XX] = gmx_rng_uniform_real(tpi_rand)*state->box[XX][XX];
-                    x_init[YY] = gmx_rng_uniform_real(tpi_rand)*state->box[YY][YY];
-                    x_init[ZZ] = gmx_rng_uniform_real(tpi_rand)*state->box[ZZ][ZZ];
-                }
-                if (inputrec->nstlist == 1)
-                {
-                    copy_rvec(x_init,x_tp);
-                }
-                else
-                {
-                    /* Generate coordinates within |dx|=drmax of x_init */
-                    do
-                    {
-                        dx[XX] = (2*gmx_rng_uniform_real(tpi_rand) - 1)*drmax;
-                        dx[YY] = (2*gmx_rng_uniform_real(tpi_rand) - 1)*drmax;
-                        dx[ZZ] = (2*gmx_rng_uniform_real(tpi_rand) - 1)*drmax;
-                    }
-                    while (norm2(dx) > drmax*drmax);
-                    rvec_add(x_init,dx,x_tp);
-                }
-            }
-            else
-            {
-                /* Random insertion around a cavity location
-                 * given by the last coordinate of the trajectory.
-                 */
-                if (step == 0)
-                {
-                    if (nat_cavity == 1)
-                    {
-                        /* Copy the location of the cavity */
-                        copy_rvec(rerun_fr.x[rerun_fr.natoms-1],x_init);
-                    }
-                    else
-                    {
-                        /* Determine the center of mass of the last molecule */
-                        clear_rvec(x_init);
-                        mass_tot = 0;
-                        for(i=0; i<nat_cavity; i++)
-                        {
-                            for(d=0; d<DIM; d++)
-                            {
-                                x_init[d] +=
-                                    mass_cavity[i]*rerun_fr.x[rerun_fr.natoms-nat_cavity+i][d];
-                            }
-                            mass_tot += mass_cavity[i];
-                        }
-                        for(d=0; d<DIM; d++)
-                        {
-                            x_init[d] /= mass_tot;
-                        }
-                    }
-                }
-                /* Generate coordinates within |dx|=drmax of x_init */
-                do
-                {
-                    dx[XX] = (2*gmx_rng_uniform_real(tpi_rand) - 1)*drmax;
-                    dx[YY] = (2*gmx_rng_uniform_real(tpi_rand) - 1)*drmax;
-                    dx[ZZ] = (2*gmx_rng_uniform_real(tpi_rand) - 1)*drmax;
-                }
-                while (norm2(dx) > drmax*drmax);
-                rvec_add(x_init,dx,x_tp);
-            }
-            
-            if (a_tp1 - a_tp0 == 1)
-            {
-                /* Insert a single atom, just copy the insertion location */
-       copy_rvec(x_tp,state->x[a_tp0]);
-            }
-            else
-            {
-                /* Copy the coordinates from the top file */
-                for(i=a_tp0; i<a_tp1; i++)
-                {
-                    copy_rvec(x_mol[i-a_tp0],state->x[i]);
-                }
-                /* Rotate the molecule randomly */
-                rotate_conf(a_tp1-a_tp0,state->x+a_tp0,NULL,
-                            2*M_PI*gmx_rng_uniform_real(tpi_rand),
-                            2*M_PI*gmx_rng_uniform_real(tpi_rand),
-                            2*M_PI*gmx_rng_uniform_real(tpi_rand));
-                /* Shift to the insertion location */
-                for(i=a_tp0; i<a_tp1; i++)
-                {
-                    rvec_inc(state->x[i],x_tp);
-                }
-            }
-            
-            /* Check if this insertion belongs to this node */
-            bOurStep = TRUE;
-            if (PAR(cr))
-            {
-                switch (inputrec->eI)
-                {
-                case eiTPI:
-                    bOurStep = ((step / inputrec->nstlist) % nnodes == cr->nodeid);
-                    break;
-                case eiTPIC:
-                    bOurStep = (step % nnodes == cr->nodeid);
-                    break;
-                default:
-                    gmx_fatal(FARGS,"Unknown integrator %s",ei_names[inputrec->eI]);
-                }
-            }
-            if (bOurStep)
-            {
-                /* Clear some matrix variables  */
-                clear_mat(force_vir); 
-                clear_mat(shake_vir);
-                clear_mat(vir);
-                clear_mat(pres);
-                
-                /* Set the charge group center of mass of the test particle */
-                copy_rvec(x_init,fr->cg_cm[top->cgs.nr-1]);
-                
-                /* Calc energy (no forces) on new positions.
-                 * Since we only need the intermolecular energy
-                 * and the RF exclusion terms of the inserted molecule occur
-                 * within a single charge group we can pass NULL for the graph.
-                 * This also avoids shifts that would move charge groups
-                 * out of the box.
-                 *
-                 * Some checks above ensure than we can not have
-                 * twin-range interactions together with nstlist > 1,
-                 * therefore we do not need to remember the LR energies.
-                 */
-                /* Make do_force do a single node force calculation */
-                cr->nnodes = 1;
-                do_force(fplog,cr,inputrec,
-                         step,nrnb,wcycle,top,top_global,&top_global->groups,
-                         rerun_fr.box,state->x,&state->hist,
-                         f,force_vir,mdatoms,enerd,fcd,
-                         lambda,NULL,fr,NULL,mu_tot,t,NULL,NULL,FALSE,
-                         GMX_FORCE_NONBONDED |
-                         (bNS ? GMX_FORCE_NS | GMX_FORCE_DOLR : 0) |
-                         (bStateChanged ? GMX_FORCE_STATECHANGED : 0)); 
-                cr->nnodes = nnodes;
-                bStateChanged = FALSE;
-                bNS = FALSE;
-                
-                /* Calculate long range corrections to pressure and energy */
-                calc_dispcorr(fplog,inputrec,fr,step,top_global->natoms,rerun_fr.box,
-                              lambda,pres,vir,&prescorr,&enercorr,&dvdlcorr);
-                /* figure out how to rearrange the next 4 lines MRS 8/4/2009 */
-                enerd->term[F_DISPCORR] = enercorr;
-                enerd->term[F_EPOT] += enercorr;
-                enerd->term[F_PRES] += prescorr;
-                enerd->term[F_DVDL] += dvdlcorr;
-
-                epot = enerd->term[F_EPOT];
-                bEnergyOutOfBounds = FALSE;
-#if ( defined(GMX_IA32_SSE) || defined(GMX_X86_64_SSE) || defined(GMX_X86_64_SSE2) )
-                /* With SSE the energy can overflow, check for this */
-                if (gmx_mm_check_and_reset_overflow())
-                {
-                    if (debug)
-                    {
-                        fprintf(debug,"Found an SSE overflow, assuming the energy is out of bounds\n");
-                    }
-                    bEnergyOutOfBounds = TRUE;
-                }
-#endif
-                /* If the compiler doesn't optimize this check away
-                 * we catch the NAN energies.
-                 * The epot>GMX_REAL_MAX check catches inf values,
-                 * which should nicely result in embU=0 through the exp below,
-                 * but it does not hurt to check anyhow.
-                 */
-                /* Non-bonded Interaction usually diverge at r=0.
-                 * With tabulated interaction functions the first few entries
-                 * should be capped in a consistent fashion between
-                 * repulsion, dispersion and Coulomb to avoid accidental
-                 * negative values in the total energy.
-                 * The table generation code in tables.c does this.
-                 * With user tbales the user should take care of this.
-                 */
-                if (epot != epot || epot > GMX_REAL_MAX)
-                {
-                    bEnergyOutOfBounds = TRUE;
-                }
-                if (bEnergyOutOfBounds)
-                {
-                    if (debug)
-                    {
-                        fprintf(debug,"\n  time %.3f, step %d: non-finite energy %f, using exp(-bU)=0\n",t,step,epot);
-                    }
-                    embU = 0;
-                }
-                else
-                {
-                    embU = exp(-beta*epot);
-                    sum_embU += embU;
-                    /* Determine the weighted energy contributions of each energy group */
-                    e = 0;
-                    sum_UgembU[e++] += epot*embU;
-                    if (fr->bBHAM)
-                    {
-                        for(i=0; i<ngid; i++)
-                        {
-                            sum_UgembU[e++] +=
-                                (enerd->grpp.ener[egBHAMSR][GID(i,gid_tp,ngid)] +
-                                 enerd->grpp.ener[egBHAMLR][GID(i,gid_tp,ngid)])*embU;
-                        }
-                    }
-                    else
-                    {
-                        for(i=0; i<ngid; i++)
-                        {
-                            sum_UgembU[e++] +=
-                                (enerd->grpp.ener[egLJSR][GID(i,gid_tp,ngid)] +
-                                 enerd->grpp.ener[egLJLR][GID(i,gid_tp,ngid)])*embU;
-                        }
-                    }
-                    if (bDispCorr)
-                    {
-                        sum_UgembU[e++] += enerd->term[F_DISPCORR]*embU;
-                    }
-                    if (bCharge)
-                    {
-                        for(i=0; i<ngid; i++)
-                        {
-                            sum_UgembU[e++] +=
-                                (enerd->grpp.ener[egCOULSR][GID(i,gid_tp,ngid)] +
-                                 enerd->grpp.ener[egCOULLR][GID(i,gid_tp,ngid)])*embU;
-                        }
-                        if (bRFExcl)
-                        {
-                            sum_UgembU[e++] += enerd->term[F_RF_EXCL]*embU;
-                        }
-                        if (EEL_FULL(fr->eeltype))
-                        {
-                            sum_UgembU[e++] += enerd->term[F_COUL_RECIP]*embU;
-                        }
-                    }
-                }
-                
-                if (embU == 0 || beta*epot > bU_bin_limit)
-                {
-                    bin[0]++;
-                }
-                else
-                {
-                    i = (int)((bU_logV_bin_limit
-                               - (beta*epot - logV + refvolshift))*invbinw
-                              + 0.5);
-                    if (i < 0)
-                    {
-                        i = 0;
-                    }
-                    if (i >= nbin)
-                    {
-                        realloc_bins(&bin,&nbin,i+10);
-                    }
-                    bin[i]++;
-                }
-                
-                if (debug)
-                {
-                    fprintf(debug,"TPI %7d %12.5e %12.5f %12.5f %12.5f\n",
-                            step,epot,x_tp[XX],x_tp[YY],x_tp[ZZ]);
-                }
-
-                if (dump_pdb && epot <= dump_ener)
-                {
-                    sprintf(str,"t%g_step%d.pdb",t,step);
-                    sprintf(str2,"t: %f step %d ener: %f",t,step,epot);
-                    write_sto_conf_mtop(str,str2,top_global,state->x,state->v,
-                                        inputrec->ePBC,state->box);
-                }
-            }
-        }
-        
-        if (PAR(cr))
-        {
-            /* When running in parallel sum the energies over the processes */
-            gmx_sumd(1,    &sum_embU, cr);
-            gmx_sumd(nener,sum_UgembU,cr);
-        }
-
-        frame++;
-        V_all += V;
-        VembU_all += V*sum_embU/nsteps;
-        
-        if (fp_tpi)
-        {
-            if (bVerbose || frame%10==0 || frame<10)
-            {
-                fprintf(stderr,"mu %10.3e <mu> %10.3e\n",
-                        -log(sum_embU/nsteps)/beta,-log(VembU_all/V_all)/beta);
-            }
-            
-            fprintf(fp_tpi,"%10.3f %12.5e %12.5e %12.5e %12.5e",
-                    t,
-                    VembU_all==0 ? 20/beta : -log(VembU_all/V_all)/beta,
-                    sum_embU==0  ? 20/beta : -log(sum_embU/nsteps)/beta,
-                    sum_embU/nsteps,V);
-            for(e=0; e<nener; e++)
-            {
-                fprintf(fp_tpi," %12.5e",sum_UgembU[e]/nsteps);
-            }
-            fprintf(fp_tpi,"\n");
-            fflush(fp_tpi);
-        }
-        
-        bNotLastFrame = read_next_frame(oenv, status,&rerun_fr);
-    } /* End of the loop  */
-    runtime_end(runtime);
-
-    close_trj(status);
-
-    if (fp_tpi != NULL)
-    {
-        gmx_fio_fclose(fp_tpi);
-    }
-
-    if (fplog != NULL)
-    {
-        fprintf(fplog,"\n");
-        fprintf(fplog,"  <V>  = %12.5e nm^3\n",V_all/frame);
-        fprintf(fplog,"  <mu> = %12.5e kJ/mol\n",-log(VembU_all/V_all)/beta);
-    }
-  
-    /* Write the Boltzmann factor histogram */
-    if (PAR(cr))
-    {
-        /* When running in parallel sum the bins over the processes */
-        i = nbin;
-        global_max(cr,&i);
-        realloc_bins(&bin,&nbin,i);
-        gmx_sumd(nbin,bin,cr);
-    }
-    if (MASTER(cr))
-    {
-        fp_tpi = xvgropen(opt2fn("-tpid",nfile,fnm),
-                          "TPI energy distribution",
-                          "\\betaU - log(V/<V>)","count",oenv);
-        sprintf(str,"number \\betaU > %g: %9.3e",bU_bin_limit,bin[0]);
-        xvgr_subtitle(fp_tpi,str,oenv);
-        xvgr_legend(fp_tpi,2,(const char **)tpid_leg,oenv);
-        for(i=nbin-1; i>0; i--)
-        {
-            bUlogV = -i/invbinw + bU_logV_bin_limit - refvolshift + log(V_all/frame);
-            fprintf(fp_tpi,"%6.2f %10d %12.5e\n",
-                    bUlogV,
-                    (int)(bin[i]+0.5),
-                    bin[i]*exp(-bUlogV)*V_all/VembU_all);
-        }
-        gmx_fio_fclose(fp_tpi);
-    }
-    sfree(bin);
-
-    sfree(sum_UgembU);
-
-    runtime->nsteps_done = frame*inputrec->nsteps;
-
-    return 0;
-}
diff --git a/src/ngmx/.cvsignore b/src/ngmx/.cvsignore
deleted file mode 100644 (file)
index eccc86b..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-Makefile
-Makefile.in
-.deps
-.libs
\ No newline at end of file
index c8b084350e7b3971e61645f3434f15451f5b00e0..4ee1e86940570d01dd27b0d07516df27a2d99c31 100644 (file)
@@ -1,2 +1,6 @@
 .deps
 .libs
+g_highway
+g_logo
+g_xrama
+ngmx
diff --git a/src/programs/CMakeLists.txt b/src/programs/CMakeLists.txt
new file mode 100644 (file)
index 0000000..07e32ba
--- /dev/null
@@ -0,0 +1 @@
+add_subdirectory(g_ana)
diff --git a/src/programs/g_ana/.gitignore b/src/programs/g_ana/.gitignore
new file mode 100644 (file)
index 0000000..e25cc71
--- /dev/null
@@ -0,0 +1 @@
+g_ana
diff --git a/src/programs/g_ana/CMakeLists.txt b/src/programs/g_ana/CMakeLists.txt
new file mode 100644 (file)
index 0000000..7491aca
--- /dev/null
@@ -0,0 +1,6 @@
+add_executable(g_ana g_ana.cpp)
+target_link_libraries(g_ana libgromacs)
+set_target_properties(g_ana PROPERTIES OUTPUT_NAME "g_ana${GMX_BINARY_SUFFIX}")
+
+install(TARGETS g_ana
+        RUNTIME DESTINATION ${BIN_INSTALL_DIR})
diff --git a/src/programs/g_ana/g_ana.cpp b/src/programs/g_ana/g_ana.cpp
new file mode 100644 (file)
index 0000000..b580576
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \brief
+ * Implements the g_ana tool.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ */
+#include <copyrite.h>
+
+#include "gromacs/fatalerror.h"
+#include "gromacs/trajectoryanalysis/cmdlinerunner.h"
+#include "gromacs/trajectoryanalysis/modules.h"
+
+int
+main(int argc, char *argv[])
+{
+    if (argc < 2)
+    {
+        CopyRight(stderr, argv[0]);
+        GMX_ERROR(gmx::eeInvalidInput,
+                  "Not enough command-line arguments");
+    }
+
+    gmx::TrajectoryAnalysisModule *mod
+        = gmx::createTrajectoryAnalysisModule(argv[1]);
+    if (mod == NULL)
+    {
+        CopyRight(stderr, argv[0]);
+        GMX_ERROR(gmx::eeInvalidInput,
+                  "Unknown analysis module given as the first command-line argument");
+    }
+    --argc;
+    ++argv;
+
+    gmx::TrajectoryAnalysisCommandLineRunner runner(mod);
+    return runner.run(argc, argv);
+}
diff --git a/src/tools/.cvsignore b/src/tools/.cvsignore
deleted file mode 100644 (file)
index eccc86b..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-Makefile
-Makefile.in
-.deps
-.libs
\ No newline at end of file
index c8b084350e7b3971e61645f3434f15451f5b00e0..5a69a3ab2700be30baa85dec48cf5d95b71023b3 100644 (file)
@@ -1,2 +1,83 @@
 .deps
 .libs
+do_dssp
+editconf
+eneconv
+g_anadock
+g_anaeig
+g_analyze
+g_angle
+g_bar
+g_bond
+g_bundle
+g_chi
+g_cluster
+g_clustsize
+g_confrms
+g_covar
+g_current
+g_density
+g_densmap
+g_dielectric
+g_dih
+g_dipoles
+g_disre
+g_dist
+g_dyndom
+g_enemat
+g_energy
+g_filter
+g_gyrate
+g_h2order
+g_hbond
+g_helix
+g_helixorient
+g_kinetics
+g_lie
+g_mdmat
+g_membed
+g_mindist
+g_morph
+g_msd
+g_nmeig
+g_nmens
+g_nmtraj
+g_order
+g_polystat
+g_potential
+g_principal
+g_rama
+g_rdf
+g_rms
+g_rmsdist
+g_rmsf
+g_rotacf
+g_rotmat
+g_saltbr
+g_sas
+g_sdf
+g_select
+g_sgangle
+g_sham
+g_sigeps
+g_sorient
+g_spatial
+g_spol
+g_tcaf
+g_traj
+g_tune_pme
+g_vanhove
+g_velacc
+g_wham
+g_wheel
+genbox
+genconf
+genion
+genrestr
+make_edi
+make_ndx
+mk_angndx
+trjcat
+trjconv
+trjorder
+xpm2ps
index 0308d69d5ce0f7743e8d4dd42eb3912f02af1fc8..cf1dda43c06dc8ac0688ba3ec71af5f75a7cc090 100644 (file)
@@ -1,4 +1,3 @@
-
 add_library(gmxana 
             autocorr.c      expfit.c        polynomials.c   levenmar.c      
             anadih.c        pp2shift.c      dlist.c         
@@ -20,7 +19,7 @@ add_library(gmxana
             gmx_polystat.c  gmx_potential.c gmx_rama.c      
             gmx_rdf.c       gmx_rms.c       gmx_rmsf.c      
             gmx_rotacf.c    gmx_saltbr.c    gmx_sas.c              
-            gmx_select.c       gmx_rmsdist.c   gmx_rotmat.c
+            gmx_rmsdist.c      gmx_rotmat.c
             gmx_sgangle.c   gmx_sorient.c   gmx_spol.c      gmx_tcaf.c      
             gmx_traj.c      gmx_velacc.c    gmx_helixorient.c 
             gmx_clustsize.c gmx_mdmat.c     gmx_wham.c      
@@ -29,10 +28,10 @@ add_library(gmxana
             gmx_editconf.c  gmx_genbox.c    gmx_genion.c    gmx_genconf.c   
             gmx_genpr.c     gmx_eneconv.c   gmx_vanhove.c   gmx_wheel.c     
             addconf.c       calcpot.c       edittop.c       gmx_bar.c
-            gmx_membed.c       gmx_pme_error.c )
+            gmx_pme_error.c    )
 
 
-target_link_libraries(gmxana md gmx)
+target_link_libraries(gmxana libgromacs)
 set_target_properties(gmxana PROPERTIES OUTPUT_NAME "gmxana${GMX_LIBS_SUFFIX}" SOVERSION ${SOVERSION} INSTALL_NAME_DIR "${LIB_INSTALL_DIR}")
 
 # List of programs with single corresponding .c source file,
@@ -48,10 +47,10 @@ set(GMX_TOOLS_PROGRAMS
     g_dyndom g_enemat g_energy g_lie g_filter g_gyrate
     g_h2order g_hbond g_helix g_mindist g_msd g_morph g_nmeig
     g_nmens g_order g_kinetics g_polystat g_potential g_rama g_rdf g_rms
-    g_rmsf g_rotacf g_saltbr g_sas g_select g_sgangle g_sham g_sorient
+    g_rmsf g_rotacf g_saltbr g_sas g_sgangle g_sham g_sorient
     g_spol g_spatial g_tcaf g_traj g_tune_pme g_vanhove
     g_velacc g_clustsize g_mdmat g_wham g_sigeps g_bar
-    g_membed g_pme_error g_rmsdist g_rotmat)
+    g_pme_error g_rmsdist g_rotmat)
 
 
 
index 6c92fb869053c8067844764aa0039a32094cb862..9241a65c96624533618cb5c476eb7505f9887d71 100644 (file)
@@ -37,7 +37,7 @@ libgmxana@LIBSUFFIX@_la_SOURCES = \
        gmx_polystat.c  gmx_potential.c gmx_rama.c      \
        gmx_rdf.c       gmx_rms.c       gmx_rmsdist.c   gmx_rmsf.c      \
        gmx_rotacf.c    gmx_rotmat.c    gmx_saltbr.c    gmx_sas.c       \
-       gmx_select.c    gmx_pme_error.c \
+       gmx_select.c    gmx_pme_error.c gmx_membed.c    \
        gmx_sgangle.c   gmx_sorient.c   gmx_spol.c      gmx_tcaf.c      \
        gmx_traj.c      gmx_velacc.c    gmx_helixorient.c \
        gmx_clustsize.c gmx_mdmat.c     gmx_wham.c      eigio.h         \
@@ -45,7 +45,7 @@ libgmxana@LIBSUFFIX@_la_SOURCES = \
        gmx_trjconv.c   gmx_trjcat.c    gmx_trjorder.c  gmx_xpm2ps.c    \
        gmx_editconf.c  gmx_genbox.c    gmx_genion.c    gmx_genconf.c   \
        gmx_genpr.c     gmx_eneconv.c   gmx_vanhove.c   gmx_wheel.c     \
-       addconf.c       addconf.h       gmx_tune_pme.c  gmx_membed.c    \
+       addconf.c       addconf.h       gmx_tune_pme.c  \
        calcpot.c       calcpot.h       edittop.c
 
 bin_PROGRAMS = \
@@ -64,7 +64,7 @@ bin_PROGRAMS = \
        g_enemat        g_energy        g_lie           g_filter        \
        g_gyrate        g_h2order       g_hbond         g_helix         \
        g_mindist       g_msd           g_morph         g_nmeig         \
-       g_nmens         g_order         g_kinetics      \
+       g_nmens         g_order         g_kinetics      g_membed        \
        g_polystat      g_potential     g_rama          \
        g_rdf           g_rms           g_rmsdist       g_rmsf          \
        g_rotacf        g_rotmat        g_saltbr        g_sas           \
@@ -72,7 +72,7 @@ bin_PROGRAMS = \
        g_sham          g_sorient       g_spol          \
        g_spatial       g_pme_error     \
        g_tcaf          g_traj          g_tune_pme   \
-       g_vanhove       g_velacc        g_membed      \
+       g_vanhove       g_velacc        \
        g_clustsize     g_mdmat         g_wham          \
        g_sigeps
 
index 3923a97611d5df32bb2ac11f6a571518a99b5686..86df2a18ff74603854ea486c1efba8c3885636b9 100644 (file)
 #include <signal.h>
 #include <stdlib.h>
 #include "typedefs.h"
-#include "smalloc.h"
 #include "sysstuff.h"
-#include "vec.h"
 #include "statutil.h"
 #include "macros.h"
 #include "copyrite.h"
 #include "main.h"
-#include "futil.h"
-#include "edsam.h"
-#include "checkpoint.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 "confio.h"
-#include "network.h"
-#include "pull.h"
-#include "xvgr.h"
-#include "physics.h"
-#include "names.h"
-#include "disre.h"
-#include "orires.h"
-#include "dihre.h"
-#include "pppm.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 "shellfc.h"
-#include "mvdata.h"
-#include "checkpoint.h"
-#include "mtop_util.h"
-#include "tpxio.h"
-#include "string2.h"
-#include "sighandler.h"
 #include "gmx_ana.h"
 
-#ifdef GMX_LIB_MPI
-#include <mpi.h>
-#endif
-#ifdef GMX_THREADS
-#include "tmpi.h"
-#endif
-
-/* afm stuf */
-#include "pull.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   snew_bc(cr,d,nr) { if (!MASTER(cr)) snew((d),(nr)); }
-
-/* The following two variables and the signal_handler function
- * is used from pme.c as well
- */
-
-typedef struct {
-       t_state s;
-       rvec    *f;
-       real    epot;
-       real    fnorm;
-       real    fmax;
-       int     a_fmax;
-} em_state_t;
-
-typedef struct {
-       int    it_xy;
-       int    it_z;
-       int    xy_step;
-       int    z_step;
-       rvec    xmin;
-       rvec    xmax;
-       rvec    *geom_cent;
-       int    pieces;
-       int    *nidx;
-       atom_id **subindex;
-} pos_ins_t;
-
-typedef struct {
-       int             id;
-       char    *name;
-       int     nr;
-       int     natoms;     /*nr of atoms per lipid*/
-       int     mol1;       /*id of the first lipid molecule*/
-       real    area;
-} lip_t;
-
-typedef struct {
-       char    *name;
-       t_block mem_at;
-       int             *mol_id;
-       int             nmol;
-       real    lip_area;
-       real    zmin;
-       real    zmax;
-       real    zmed;
-} mem_t;
-
-typedef struct {
-       int             *mol;
-       int             *block;
-       int     nr;
-} rm_t;
-
-int search_string(char *s,int ng,char ***gn)
-{
-       int i;
-
-       for(i=0; (i<ng); i++)
-               if (gmx_strcasecmp(s,*gn[i]) == 0)
-                       return i;
-
-       gmx_fatal(FARGS,"Group %s not found in indexfile.\nMaybe you have non-default groups in your mdp file, while not using the '-n' option of grompp.\nIn that case use the '-n' option.\n",s);
-
-       return -1;
-}
-
-int get_mol_id(int at,int nmblock,gmx_molblock_t *mblock, int *type, int *block)
-{
-       int mol_id=0;
-       int i;
-
-       for(i=0;i<nmblock;i++)
-       {
-               if(at<(mblock[i].nmol*mblock[i].natoms_mol))
-               {
-                       mol_id+=at/mblock[i].natoms_mol;
-                       *type = mblock[i].type;
-                       *block = i;
-                       return mol_id;
-               } else {
-                       at-= mblock[i].nmol*mblock[i].natoms_mol;
-                       mol_id+=mblock[i].nmol;
-               }
-       }
-
-       gmx_fatal(FARGS,"Something is wrong in mol ids, at %d, mol_id %d",at,mol_id);
-
-       return -1;
-}
-
-int get_block(int mol_id,int nmblock,gmx_molblock_t *mblock)
-{
-       int i;
-       int nmol=0;
-
-       for(i=0;i<nmblock;i++)
-       {
-               nmol+=mblock[i].nmol;
-               if(mol_id<nmol)
-                       return i;
-       }
-
-       gmx_fatal(FARGS,"mol_id %d larger than total number of molecules %d.\n",mol_id,nmol);
-
-       return -1;
-}
-
-int get_tpr_version(const char *infile)
-{
-       char    buf[STRLEN];
-       gmx_bool        bDouble;
-       int     precision,fver;
-        t_fileio *fio;
-
-       fio = open_tpx(infile,"r");
-       gmx_fio_checktype(fio);
-
-       precision = sizeof(real);
-
-       gmx_fio_do_string(fio,buf);
-       if (strncmp(buf,"VERSION",7))
-               gmx_fatal(FARGS,"Can not read file %s,\n"
-                               "             this file is from a Gromacs version which is older than 2.0\n"
-                               "             Make a new one with grompp or use a gro or pdb file, if possible",
-                               gmx_fio_getname(fio));
-       gmx_fio_do_int(fio,precision);
-       bDouble = (precision == sizeof(double));
-       if ((precision != sizeof(float)) && !bDouble)
-               gmx_fatal(FARGS,"Unknown precision in file %s: real is %d bytes "
-                               "instead of %d or %d",
-                               gmx_fio_getname(fio),precision,sizeof(float),sizeof(double));
-       gmx_fio_setprecision(fio,bDouble);
-       fprintf(stderr,"Reading file %s, %s (%s precision)\n",
-                       gmx_fio_getname(fio),buf,bDouble ? "double" : "single");
-
-       gmx_fio_do_int(fio,fver);
-
-       close_tpx(fio);
-
-       return fver;
-}
-
-void set_inbox(int natom, rvec *x)
-{
-       rvec tmp;
-       int  i;
-
-       tmp[XX]=tmp[YY]=tmp[ZZ]=0.0;
-       for(i=0;i<natom;i++)
-       {
-               if(x[i][XX]<tmp[XX])            tmp[XX]=x[i][XX];
-               if(x[i][YY]<tmp[YY])            tmp[YY]=x[i][YY];
-               if(x[i][ZZ]<tmp[ZZ])            tmp[ZZ]=x[i][ZZ];
-       }
-
-       for(i=0;i<natom;i++)
-                       rvec_inc(x[i],tmp);
-}
-
-int get_mtype_list(t_block *at, gmx_mtop_t *mtop, t_block *tlist)
-{
-       int i,j,nr,mol_id;
-        int type=0,block=0;
-       gmx_bool bNEW;
-
-       nr=0;
-       snew(tlist->index,at->nr);
-       for (i=0;i<at->nr;i++)
-       {
-               bNEW=TRUE;
-               mol_id = get_mol_id(at->index[i],mtop->nmolblock,mtop->molblock,&type,&block);
-               for(j=0;j<nr;j++)
-               {
-                       if(tlist->index[j]==type)
-                                               bNEW=FALSE;
-               }
-               if(bNEW==TRUE)
-               {
-                       tlist->index[nr]=type;
-                       nr++;
-               }
-       }
-
-       srenew(tlist->index,nr);
-       return nr;
-}
-
-void check_types(t_block *ins_at,t_block *rest_at,gmx_mtop_t *mtop)
-{
-       t_block         *ins_mtype,*rest_mtype;
-       int                     i,j;
-
-       snew(ins_mtype,1);
-       snew(rest_mtype,1);
-    ins_mtype->nr  = get_mtype_list(ins_at , mtop, ins_mtype );
-    rest_mtype->nr = get_mtype_list(rest_at, mtop, rest_mtype);
-
-    for(i=0;i<ins_mtype->nr;i++)
-    {
-       for(j=0;j<rest_mtype->nr;j++)
-       {
-               if(ins_mtype->index[i]==rest_mtype->index[j])
-                       gmx_fatal(FARGS,"Moleculetype %s is found both in the group to insert and the rest of the system.\n"
-                                       "Because we need to exclude all interactions between the atoms in the group to\n"
-                                       "insert, the same moleculetype can not be used in both groups. Change the\n"
-                                       "moleculetype of the molecules %s in the inserted group. Do not forget to provide\n"
-                                       "an appropriate *.itp file",*(mtop->moltype[rest_mtype->index[j]].name),
-                                       *(mtop->moltype[rest_mtype->index[j]].name));
-       }
-    }
-
-    sfree(ins_mtype->index);
-    sfree(rest_mtype->index);
-    sfree(ins_mtype);
-    sfree(rest_mtype);
-}
-
-int init_ins_at(t_block *ins_at,t_block *rest_at,t_state *state, pos_ins_t *pos_ins,gmx_groups_t *groups,int ins_grp_id, real xy_max)
-{
-       int i,gid,c=0;
-       real x,xmin,xmax,y,ymin,ymax,z,zmin,zmax;
-
-       snew(rest_at->index,state->natoms);
-
-       xmin=xmax=state->x[ins_at->index[0]][XX];
-       ymin=ymax=state->x[ins_at->index[0]][YY];
-       zmin=zmax=state->x[ins_at->index[0]][ZZ];
-
-       for(i=0;i<state->natoms;i++)
-       {
-               gid = groups->grpnr[egcFREEZE][i];
-               if(groups->grps[egcFREEZE].nm_ind[gid]==ins_grp_id)
-               {
-                       x=state->x[i][XX];
-                       if (x<xmin)                     xmin=x;
-                       if (x>xmax)                     xmax=x;
-                       y=state->x[i][YY];
-                       if (y<ymin)                             ymin=y;
-                       if (y>ymax)                             ymax=y;
-                       z=state->x[i][ZZ];
-                       if (z<zmin)                             zmin=z;
-                       if (z>zmax)                             zmax=z;
-               } else {
-                       rest_at->index[c]=i;
-                       c++;
-               }
-       }
-
-       rest_at->nr=c;
-       srenew(rest_at->index,c);
-
-       if(xy_max>1.000001)
-       {
-               pos_ins->xmin[XX]=xmin-((xmax-xmin)*xy_max-(xmax-xmin))/2;
-               pos_ins->xmin[YY]=ymin-((ymax-ymin)*xy_max-(ymax-ymin))/2;
-
-               pos_ins->xmax[XX]=xmax+((xmax-xmin)*xy_max-(xmax-xmin))/2;
-               pos_ins->xmax[YY]=ymax+((ymax-ymin)*xy_max-(ymax-ymin))/2;
-       } else {
-               pos_ins->xmin[XX]=xmin;
-               pos_ins->xmin[YY]=ymin;
-
-               pos_ins->xmax[XX]=xmax;
-               pos_ins->xmax[YY]=ymax;
-       }
-
-       /* 6.0 is estimated thickness of bilayer */
-       if( (zmax-zmin) < 6.0 )
-       {
-               pos_ins->xmin[ZZ]=zmin+(zmax-zmin)/2.0-3.0;
-               pos_ins->xmax[ZZ]=zmin+(zmax-zmin)/2.0+3.0;
-       } else {
-               pos_ins->xmin[ZZ]=zmin;
-               pos_ins->xmax[ZZ]=zmax;
-       }
-
-       return c;
-}
-
-real est_prot_area(pos_ins_t *pos_ins,rvec *r,t_block *ins_at, mem_t *mem_p)
-{
-       real x,y,dx=0.15,dy=0.15,area=0.0;
-       real add;
-       int c,at;
-
-       for(x=pos_ins->xmin[XX];x<pos_ins->xmax[XX];x+=dx)
-       {
-               for(y=pos_ins->xmin[YY];y<pos_ins->xmax[YY];y+=dy)
-               {
-                       c=0;
-                       add=0.0;
-                       do
-                       {
-                               at=ins_at->index[c];
-                               if ( (r[at][XX]>=x) && (r[at][XX]<x+dx) &&
-                                               (r[at][YY]>=y) && (r[at][YY]<y+dy) &&
-                                               (r[at][ZZ]>mem_p->zmin+1.0) && (r[at][ZZ]<mem_p->zmax-1.0) )
-                                       add=1.0;
-                               c++;
-                       } while ( (c<ins_at->nr) && (add<0.5) );
-                       area+=add;
-               }
-       }
-       area=area*dx*dy;
-
-       return area;
-}
-
-void init_lip(matrix box, gmx_mtop_t *mtop, lip_t *lip)
-{
-       int i;
-       real mem_area;
-       int mol1=0;
-
-       mem_area = box[XX][XX]*box[YY][YY]-box[XX][YY]*box[YY][XX];
-       for(i=0;i<mtop->nmolblock;i++)
-       {
-               if(mtop->molblock[i].type == lip->id)
-               {
-                       lip->nr=mtop->molblock[i].nmol;
-                       lip->natoms=mtop->molblock[i].natoms_mol;
-               }
-       }
-       lip->area=2.0*mem_area/(double)lip->nr;
-
-       for (i=0;i<lip->id;i++)
-               mol1+=mtop->molblock[i].nmol;
-       lip->mol1=mol1;
-}
-
-int init_mem_at(mem_t *mem_p, gmx_mtop_t *mtop, rvec *r, matrix box, pos_ins_t *pos_ins)
-{
-       int i,j,at,mol,nmol,nmolbox,count;
-       t_block *mem_a;
-       real z,zmin,zmax,mem_area;
-       gmx_bool bNew;
-       atom_id *mol_id;
-       int type=0,block=0;
-
-       nmol=count=0;
-       mem_a=&(mem_p->mem_at);
-       snew(mol_id,mem_a->nr);
-/*     snew(index,mem_a->nr); */
-       zmin=pos_ins->xmax[ZZ];
-       zmax=pos_ins->xmin[ZZ];
-       for(i=0;i<mem_a->nr;i++)
-       {
-               at=mem_a->index[i];
-               if(     (r[at][XX]>pos_ins->xmin[XX]) && (r[at][XX]<pos_ins->xmax[XX]) &&
-                       (r[at][YY]>pos_ins->xmin[YY]) && (r[at][YY]<pos_ins->xmax[YY]) &&
-                       (r[at][ZZ]>pos_ins->xmin[ZZ]) && (r[at][ZZ]<pos_ins->xmax[ZZ]) )
-               {
-                       mol = get_mol_id(at,mtop->nmolblock,mtop->molblock,&type,&block);
-
-                       bNew=TRUE;
-                       for(j=0;j<nmol;j++)
-                               if(mol == mol_id[j])
-                                       bNew=FALSE;
-
-                       if(bNew)
-                       {
-                               mol_id[nmol]=mol;
-                               nmol++;
-                       }
-
-                       z=r[at][ZZ];
-                       if(z<zmin)                                      zmin=z;
-                       if(z>zmax)                                      zmax=z;
-
-/*                     index[count]=at;*/
-                       count++;
-               }
-       }
-
-       mem_p->nmol=nmol;
-       srenew(mol_id,nmol);
-       mem_p->mol_id=mol_id;
-/*     srenew(index,count);*/
-/*     mem_p->mem_at.nr=count;*/
-/*     sfree(mem_p->mem_at.index);*/
-/*     mem_p->mem_at.index=index;*/
-
-       if((zmax-zmin)>(box[ZZ][ZZ]-0.5))
-               gmx_fatal(FARGS,"Something is wrong with your membrane. Max and min z values are %f and %f.\n"
-                               "Maybe your membrane is not centered in the box, but located at the box edge in the z-direction,\n"
-                               "so that one membrane is distributed over two periodic box images. Another possibility is that\n"
-                               "your water layer is not thick enough.\n",zmax,zmin);
-       mem_p->zmin=zmin;
-       mem_p->zmax=zmax;
-       mem_p->zmed=(zmax-zmin)/2+zmin;
-
-       /*number of membrane molecules in protein box*/
-       nmolbox = count/mtop->molblock[block].natoms_mol;
-       /*mem_area = box[XX][XX]*box[YY][YY]-box[XX][YY]*box[YY][XX];
-       mem_p->lip_area = 2.0*mem_area/(double)mem_p->nmol;*/
-       mem_area = (pos_ins->xmax[XX]-pos_ins->xmin[XX])*(pos_ins->xmax[YY]-pos_ins->xmin[YY]);
-       mem_p->lip_area = 2.0*mem_area/(double)nmolbox;
-
-       return mem_p->mem_at.nr;
-}
-
-void init_resize(t_block *ins_at,rvec *r_ins,pos_ins_t *pos_ins,mem_t *mem_p,rvec *r, gmx_bool bALLOW_ASYMMETRY)
-{
-       int i,j,at,c,outsidesum,gctr=0;
-    int idxsum=0;
-
-    /*sanity check*/
-    for (i=0;i<pos_ins->pieces;i++)
-          idxsum+=pos_ins->nidx[i];
-    if (idxsum!=ins_at->nr)
-          gmx_fatal(FARGS,"Piecewise sum of inserted atoms not same as size of group selected to insert.");
-
-    snew(pos_ins->geom_cent,pos_ins->pieces);
-    for (i=0;i<pos_ins->pieces;i++)
-    {
-       c=0;
-       outsidesum=0;
-       for(j=0;j<DIM;j++)
-               pos_ins->geom_cent[i][j]=0;
-
-       for(j=0;j<DIM;j++)
-               pos_ins->geom_cent[i][j]=0;
-       for (j=0;j<pos_ins->nidx[i];j++)
-       {
-               at=pos_ins->subindex[i][j];
-               copy_rvec(r[at],r_ins[gctr]);
-               if( (r_ins[gctr][ZZ]<mem_p->zmax) && (r_ins[gctr][ZZ]>mem_p->zmin) )
-               {
-                       rvec_inc(pos_ins->geom_cent[i],r_ins[gctr]);
-                       c++;
-               }
-               else
-                       outsidesum++;
-               gctr++;
-       }
-       if (c>0)
-               svmul(1/(double)c,pos_ins->geom_cent[i],pos_ins->geom_cent[i]);
-       if (!bALLOW_ASYMMETRY)
-               pos_ins->geom_cent[i][ZZ]=mem_p->zmed;
-
-       fprintf(stderr,"Embedding piece %d with center of geometry: %f %f %f\n",i,pos_ins->geom_cent[i][XX],pos_ins->geom_cent[i][YY],pos_ins->geom_cent[i][ZZ]);
-    }
-    fprintf(stderr,"\n");
-}
-
-void resize(t_block *ins_at, rvec *r_ins, rvec *r, pos_ins_t *pos_ins,rvec fac)
-{
-       int i,j,k,at,c=0;
-       for (k=0;k<pos_ins->pieces;k++)
-               for(i=0;i<pos_ins->nidx[k];i++)
-               {
-                       at=pos_ins->subindex[k][i];
-                       for(j=0;j<DIM;j++)
-                               r[at][j]=pos_ins->geom_cent[k][j]+fac[j]*(r_ins[c][j]-pos_ins->geom_cent[k][j]);
-                       c++;
-               }
-}
-
-int gen_rm_list(rm_t *rm_p,t_block *ins_at,t_block *rest_at,t_pbc *pbc, gmx_mtop_t *mtop,
-               rvec *r, rvec *r_ins, mem_t *mem_p, pos_ins_t *pos_ins, real probe_rad, int low_up_rm, gmx_bool bALLOW_ASYMMETRY)
-{
-       int i,j,k,l,at,at2,mol_id;
-        int type=0,block=0;
-       int nrm,nupper,nlower;
-       real r_min_rad,z_lip,min_norm;
-       gmx_bool bRM;
-       rvec dr,dr_tmp;
-       real *dist;
-       int *order;
-
-       r_min_rad=probe_rad*probe_rad;
-       snew(rm_p->mol,mtop->mols.nr);
-       snew(rm_p->block,mtop->mols.nr);
-       nrm=nupper=0;
-       nlower=low_up_rm;
-       for(i=0;i<ins_at->nr;i++)
-       {
-               at=ins_at->index[i];
-               for(j=0;j<rest_at->nr;j++)
-               {
-                       at2=rest_at->index[j];
-                       pbc_dx(pbc,r[at],r[at2],dr);
-
-                       if(norm2(dr)<r_min_rad)
-                       {
-                               mol_id = get_mol_id(at2,mtop->nmolblock,mtop->molblock,&type,&block);
-                               bRM=TRUE;
-                               for(l=0;l<nrm;l++)
-                                       if(rm_p->mol[l]==mol_id)
-                                               bRM=FALSE;
-                               if(bRM)
-                               {
-                                       /*fprintf(stderr,"%d wordt toegevoegd\n",mol_id);*/
-                                       rm_p->mol[nrm]=mol_id;
-                                       rm_p->block[nrm]=block;
-                                       nrm++;
-                                       z_lip=0.0;
-                                       for(l=0;l<mem_p->nmol;l++)
-                                       {
-                                               if(mol_id==mem_p->mol_id[l])
-                                               {
-                                                       for(k=mtop->mols.index[mol_id];k<mtop->mols.index[mol_id+1];k++)
-                                                               z_lip+=r[k][ZZ];
-                                                       z_lip/=mtop->molblock[block].natoms_mol;
-                                                       if(z_lip<mem_p->zmed)
-                                                               nlower++;
-                                                       else
-                                                               nupper++;
-                                               }
-                                       }
-                               }
-                       }
-               }
-       }
-
-       /*make sure equal number of lipids from upper and lower layer are removed */
-       if( (nupper!=nlower) && (!bALLOW_ASYMMETRY) )
-       {
-               snew(dist,mem_p->nmol);
-               snew(order,mem_p->nmol);
-               for(i=0;i<mem_p->nmol;i++)
-               {
-                       at = mtop->mols.index[mem_p->mol_id[i]];
-                       pbc_dx(pbc,r[at],pos_ins->geom_cent[0],dr);
-                       if (pos_ins->pieces>1)
-                       {
-                               /*minimum dr value*/
-                               min_norm=norm2(dr);
-                               for (k=1;k<pos_ins->pieces;k++)
-                               {
-                                       pbc_dx(pbc,r[at],pos_ins->geom_cent[k],dr_tmp);
-                                       if (norm2(dr_tmp) < min_norm)
-                                       {
-                                               min_norm=norm2(dr_tmp);
-                                               copy_rvec(dr_tmp,dr);
-                                       }
-                               }
-                       }
-                       dist[i]=dr[XX]*dr[XX]+dr[YY]*dr[YY];
-                       j=i-1;
-                       while (j>=0 && dist[i]<dist[order[j]])
-                       {
-                               order[j+1]=order[j];
-                               j--;
-                       }
-                       order[j+1]=i;
-               }
-
-               i=0;
-               while(nupper!=nlower)
-               {
-                       mol_id=mem_p->mol_id[order[i]];
-                       block=get_block(mol_id,mtop->nmolblock,mtop->molblock);
-
-                       bRM=TRUE;
-                       for(l=0;l<nrm;l++)
-                               if(rm_p->mol[l]==mol_id)
-                                       bRM=FALSE;
-                       if(bRM)
-                       {
-                               z_lip=0;
-                               for(k=mtop->mols.index[mol_id];k<mtop->mols.index[mol_id+1];k++)
-                                       z_lip+=r[k][ZZ];
-                               z_lip/=mtop->molblock[block].natoms_mol;
-                               if(nupper>nlower && z_lip<mem_p->zmed)
-                               {
-                                       rm_p->mol[nrm]=mol_id;
-                                       rm_p->block[nrm]=block;
-                                       nrm++;
-                                       nlower++;
-                               }
-                               else if (nupper<nlower && z_lip>mem_p->zmed)
-                               {
-                                       rm_p->mol[nrm]=mol_id;
-                                       rm_p->block[nrm]=block;
-                                       nrm++;
-                                       nupper++;
-                               }
-                       }
-                       i++;
-
-                       if(i>mem_p->nmol)
-                               gmx_fatal(FARGS,"Trying to remove more lipid molecules than there are in the membrane");
-               }
-               sfree(dist);
-               sfree(order);
-       }
-
-       rm_p->nr=nrm;
-       srenew(rm_p->mol,nrm);
-       srenew(rm_p->block,nrm);
-
-       return nupper+nlower;
-}
-
-void rm_group(t_inputrec *ir, gmx_groups_t *groups, gmx_mtop_t *mtop, rm_t *rm_p, t_state *state, t_block *ins_at, pos_ins_t *pos_ins)
-{
-       int i,j,k,n,rm,mol_id,at,block;
-       rvec *x_tmp,*v_tmp;
-       atom_id *list,*new_mols;
-       unsigned char  *new_egrp[egcNR];
-       gmx_bool bRM;
-
-       snew(list,state->natoms);
-       n=0;
-       for(i=0;i<rm_p->nr;i++)
-       {
-               mol_id=rm_p->mol[i];
-               at=mtop->mols.index[mol_id];
-               block =rm_p->block[i];
-               mtop->molblock[block].nmol--;
-               for(j=0;j<mtop->molblock[block].natoms_mol;j++)
-               {
-                       list[n]=at+j;
-                       n++;
-               }
-
-               mtop->mols.index[mol_id]=-1;
-       }
-
-       mtop->mols.nr-=rm_p->nr;
-       mtop->mols.nalloc_index-=rm_p->nr;
-       snew(new_mols,mtop->mols.nr);
-       for(i=0;i<mtop->mols.nr+rm_p->nr;i++)
-       {
-               j=0;
-               if(mtop->mols.index[i]!=-1)
-               {
-                       new_mols[j]=mtop->mols.index[i];
-                       j++;
-               }
-       }
-       sfree(mtop->mols.index);
-       mtop->mols.index=new_mols;
-
-
-       mtop->natoms-=n;
-       state->natoms-=n;
-       state->nalloc=state->natoms;
-       snew(x_tmp,state->nalloc);
-       snew(v_tmp,state->nalloc);
-
-       for(i=0;i<egcNR;i++)
-       {
-               if(groups->grpnr[i]!=NULL)
-               {
-                       groups->ngrpnr[i]=state->natoms;
-                       snew(new_egrp[i],state->natoms);
-               }
-       }
-
-       rm=0;
-       for (i=0;i<state->natoms+n;i++)
-       {
-               bRM=FALSE;
-               for(j=0;j<n;j++)
-               {
-                       if(i==list[j])
-                       {
-                               bRM=TRUE;
-                               rm++;
-                       }
-               }
-
-               if(!bRM)
-               {
-                       for(j=0;j<egcNR;j++)
-                       {
-                               if(groups->grpnr[j]!=NULL)
-                               {
-                                       new_egrp[j][i-rm]=groups->grpnr[j][i];
-                               }
-                       }
-                       copy_rvec(state->x[i],x_tmp[i-rm]);
-                       copy_rvec(state->v[i],v_tmp[i-rm]);
-                       for(j=0;j<ins_at->nr;j++)
-                       {
-                               if (i==ins_at->index[j])
-                                       ins_at->index[j]=i-rm;
-                       }
-                       for(j=0;j<pos_ins->pieces;j++)
-                       {
-                               for(k=0;k<pos_ins->nidx[j];k++)
-                               {
-                                       if (i==pos_ins->subindex[j][k])
-                                               pos_ins->subindex[j][k]=i-rm;
-                               }
-                       }
-               }
-       }
-       sfree(state->x);
-       state->x=x_tmp;
-       sfree(state->v);
-       state->v=v_tmp;
-
-       for(i=0;i<egcNR;i++)
-       {
-               if(groups->grpnr[i]!=NULL)
-               {
-                       sfree(groups->grpnr[i]);
-                       groups->grpnr[i]=new_egrp[i];
-               }
-       }
-}
-
-int rm_bonded(t_block *ins_at, gmx_mtop_t *mtop)
-{
-       int i,j,m;
-       int type,natom,nmol,at,atom1=0,rm_at=0;
-       gmx_bool *bRM,bINS;
-       /*this routine lives dangerously by assuming that all molecules of a given type are in order in the structure*/
-       /*this routine does not live as dangerously as it seems. There is namely a check in mdrunner_membed to make
-         *sure that g_membed exits with a warning when there are molecules of the same type not in the 
-        *ins_at index group. MGWolf 050710 */
-
-
-       snew(bRM,mtop->nmoltype);
-       for (i=0;i<mtop->nmoltype;i++)
-       {
-               bRM[i]=TRUE;
-       }
-
-       for (i=0;i<mtop->nmolblock;i++) 
-       {
-           /*loop over molecule blocks*/
-               type        =mtop->molblock[i].type;
-               natom       =mtop->molblock[i].natoms_mol;
-               nmol            =mtop->molblock[i].nmol;
-
-               for(j=0;j<natom*nmol && bRM[type]==TRUE;j++) 
-               {
-                   /*loop over atoms in the block*/
-                       at=j+atom1; /*atom index = block index + offset*/
-                       bINS=FALSE;
-
-                       for (m=0;(m<ins_at->nr) && (bINS==FALSE);m++)
-                       {
-                           /*loop over atoms in insertion index group to determine if we're inserting one*/
-                               if(at==ins_at->index[m])
-                               {
-                                       bINS=TRUE;
-                               }
-                       }
-                       bRM[type]=bINS;
-               }
-               atom1+=natom*nmol; /*update offset*/
-               if(bRM[type])
-               {
-                       rm_at+=natom*nmol; /*increment bonded removal counter by # atoms in block*/
-               }
-       }
-
-       for(i=0;i<mtop->nmoltype;i++)
-       {
-               if(bRM[i])
-               {
-                       for(j=0;j<F_LJ;j++)
-                       {
-                               mtop->moltype[i].ilist[j].nr=0;
-                       }
-                       for(j=F_POSRES;j<=F_VSITEN;j++)
-                       {
-                               mtop->moltype[i].ilist[j].nr=0;
-                       }
-               }
-       }
-       sfree(bRM);
-
-       return rm_at;
-}
-
-void top_update(const char *topfile, char *ins, rm_t *rm_p, gmx_mtop_t *mtop)
-{
-#define TEMP_FILENM "temp.top"
-       int     bMolecules=0;
-       FILE    *fpin,*fpout;
-       char    buf[STRLEN],buf2[STRLEN],*temp;
-       int             i,*nmol_rm,nmol,line;
-
-       fpin  = ffopen(topfile,"r");
-       fpout = ffopen(TEMP_FILENM,"w");
-
-       snew(nmol_rm,mtop->nmoltype);
-       for(i=0;i<rm_p->nr;i++)
-               nmol_rm[rm_p->block[i]]++;
-
-       line=0;
-       while(fgets(buf,STRLEN,fpin))
-       {
-               line++;
-               if(buf[0]!=';')
-               {
-                       strcpy(buf2,buf);
-                       if ((temp=strchr(buf2,'\n')) != NULL)
-                               temp[0]='\0';
-                       ltrim(buf2);
-
-                       if (buf2[0]=='[')
-                       {
-                               buf2[0]=' ';
-                               if ((temp=strchr(buf2,'\n')) != NULL)
-                                       temp[0]='\0';
-                               rtrim(buf2);
-                               if (buf2[strlen(buf2)-1]==']')
-                               {
-                                       buf2[strlen(buf2)-1]='\0';
-                                       ltrim(buf2);
-                                       rtrim(buf2);
-                                       if (gmx_strcasecmp(buf2,"molecules")==0)
-                                               bMolecules=1;
-                               }
-                               fprintf(fpout,"%s",buf);
-                       } else if (bMolecules==1)
-                       {
-                               for(i=0;i<mtop->nmolblock;i++)
-                               {
-                                       nmol=mtop->molblock[i].nmol;
-                                       sprintf(buf,"%-15s %5d\n",*(mtop->moltype[mtop->molblock[i].type].name),nmol);
-                                       fprintf(fpout,"%s",buf);
-                               }
-                               bMolecules=2;
-                       } else if (bMolecules==2)
-                       {
-                               /* print nothing */
-                       } else 
-                       {
-                               fprintf(fpout,"%s",buf);
-                       }
-               } else 
-               {
-                       fprintf(fpout,"%s",buf);
-               }
-       }
-
-       fclose(fpout);
-       /* use ffopen to generate backup of topinout */
-       fpout=ffopen(topfile,"w");
-       fclose(fpout);
-       rename(TEMP_FILENM,topfile);
-#undef TEMP_FILENM
-}
-
-void md_print_warning(const t_commrec *cr,FILE *fplog,const char *buf)
-{
-    if (MASTER(cr))
-    {
-        fprintf(stderr,"\n%s\n",buf);
-    }
-    if (fplog)
-    {
-        fprintf(fplog,"\n%s\n",buf);
-    }
-}
-
-/*  simulation conditions to transmit. Keep in mind that they are
-    transmitted to other nodes through an MPI_Reduce after
-    casting them to a real (so the signals can be sent together with other
-    data). This means that the only meaningful values are positive,
-    negative or zero. */
-enum { eglsNABNSB, eglsCHKPT, eglsSTOPCOND, eglsRESETCOUNTERS, eglsNR };
-/* Is the signal in one simulation independent of other simulations? */
-gmx_bool gs_simlocal[eglsNR] = { TRUE, FALSE, FALSE, TRUE };
-
-typedef struct {
-    int nstms;       /* The frequency for intersimulation communication */
-    int sig[eglsNR]; /* The signal set by one process in do_md */
-    int set[eglsNR]; /* The communicated signal, equal for all processes */
-} globsig_t;
-
-
-static int multisim_min(const gmx_multisim_t *ms,int nmin,int n)
-{
-    int  *buf;
-    gmx_bool bPos,bEqual;
-    int  s,d;
-
-    snew(buf,ms->nsim);
-    buf[ms->sim] = n;
-    gmx_sumi_sim(ms->nsim,buf,ms);
-    bPos   = TRUE;
-    bEqual = TRUE;
-    for(s=0; s<ms->nsim; s++)
-    {
-        bPos   = bPos   && (buf[s] > 0);
-        bEqual = bEqual && (buf[s] == buf[0]);
-    }
-    if (bPos)
-    {
-        if (bEqual)
-        {
-            nmin = min(nmin,buf[0]);
-        }
-        else
-        {
-            /* Find the least common multiple */
-            for(d=2; d<nmin; d++)
-            {
-                s = 0;
-                while (s < ms->nsim && d % buf[s] == 0)
-                {
-                    s++;
-                }
-                if (s == ms->nsim)
-                {
-                    /* We found the LCM and it is less than nmin */
-                    nmin = d;
-                    break;
-                }
-            }
-        }
-    }
-    sfree(buf);
-
-    return nmin;
-}
-
-static int multisim_nstsimsync(const t_commrec *cr,
-                               const t_inputrec *ir,int repl_ex_nst)
-{
-    int nmin;
-
-    if (MASTER(cr))
-    {
-        nmin = INT_MAX;
-        nmin = multisim_min(cr->ms,nmin,ir->nstlist);
-        nmin = multisim_min(cr->ms,nmin,ir->nstcalcenergy);
-        nmin = multisim_min(cr->ms,nmin,repl_ex_nst);
-        if (nmin == INT_MAX)
-        {
-            gmx_fatal(FARGS,"Can not find an appropriate interval for inter-simulation communication, since nstlist, nstcalcenergy and -replex are all <= 0");
-        }
-        /* Avoid inter-simulation communication at every (second) step */
-        if (nmin <= 2)
-        {
-            nmin = 10;
-        }
-    }
-
-    gmx_bcast(sizeof(int),&nmin,cr);
-
-    return nmin;
-}
-
-static void init_global_signals(globsig_t *gs,const t_commrec *cr,
-                                const t_inputrec *ir,int repl_ex_nst)
-{
-    int i;
-
-    if (MULTISIM(cr))
-    {
-        gs->nstms = multisim_nstsimsync(cr,ir,repl_ex_nst);
-        if (debug)
-        {
-            fprintf(debug,"Syncing simulations for checkpointing and termination every %d steps\n",gs->nstms);
-        }
-    }
-    else
-    {
-        gs->nstms = 1;
-    }
-
-    for(i=0; i<eglsNR; i++)
-    {
-        gs->sig[i] = 0;
-        gs->set[i] = 0;
-    }
-}
-
-static void copy_coupling_state(t_state *statea,t_state *stateb,
-                                gmx_ekindata_t *ekinda,gmx_ekindata_t *ekindb, t_grpopts* opts)
-{
-
-    /* MRS note -- might be able to get rid of some of the arguments.  Look over it when it's all debugged */
-
-    int i,j,nc;
-
-    /* Make sure we have enough space for x and v */
-    if (statea->nalloc > stateb->nalloc)
-    {
-        stateb->nalloc = statea->nalloc;
-        srenew(stateb->x,stateb->nalloc);
-        srenew(stateb->v,stateb->nalloc);
-    }
-
-    stateb->natoms     = statea->natoms;
-    stateb->ngtc       = statea->ngtc;
-    stateb->nnhpres    = statea->nnhpres;
-    stateb->veta       = statea->veta;
-    if (ekinda)
-    {
-        copy_mat(ekinda->ekin,ekindb->ekin);
-        for (i=0; i<stateb->ngtc; i++)
-        {
-            ekindb->tcstat[i].T = ekinda->tcstat[i].T;
-            ekindb->tcstat[i].Th = ekinda->tcstat[i].Th;
-            copy_mat(ekinda->tcstat[i].ekinh,ekindb->tcstat[i].ekinh);
-            copy_mat(ekinda->tcstat[i].ekinf,ekindb->tcstat[i].ekinf);
-            ekindb->tcstat[i].ekinscalef_nhc =  ekinda->tcstat[i].ekinscalef_nhc;
-            ekindb->tcstat[i].ekinscaleh_nhc =  ekinda->tcstat[i].ekinscaleh_nhc;
-            ekindb->tcstat[i].vscale_nhc =  ekinda->tcstat[i].vscale_nhc;
-        }
-    }
-    copy_rvecn(statea->x,stateb->x,0,stateb->natoms);
-    copy_rvecn(statea->v,stateb->v,0,stateb->natoms);
-    copy_mat(statea->box,stateb->box);
-    copy_mat(statea->box_rel,stateb->box_rel);
-    copy_mat(statea->boxv,stateb->boxv);
-
-    for (i = 0; i<stateb->ngtc; i++)
-    {
-        nc = i*opts->nhchainlength;
-        for (j=0; j<opts->nhchainlength; j++)
-        {
-            stateb->nosehoover_xi[nc+j]  = statea->nosehoover_xi[nc+j];
-            stateb->nosehoover_vxi[nc+j] = statea->nosehoover_vxi[nc+j];
-        }
-    }
-    if (stateb->nhpres_xi != NULL)
-    {
-        for (i = 0; i<stateb->nnhpres; i++)
-        {
-            nc = i*opts->nhchainlength;
-            for (j=0; j<opts->nhchainlength; j++)
-            {
-                stateb->nhpres_xi[nc+j]  = statea->nhpres_xi[nc+j];
-                stateb->nhpres_vxi[nc+j] = statea->nhpres_vxi[nc+j];
-            }
-        }
-    }
-}
-
-static void compute_globals(FILE *fplog, gmx_global_stat_t gstat, t_commrec *cr, t_inputrec *ir,
-                            t_forcerec *fr, gmx_ekindata_t *ekind,
-                            t_state *state, t_state *state_global, t_mdatoms *mdatoms,
-                            t_nrnb *nrnb, t_vcm *vcm, gmx_wallcycle_t wcycle,
-                            gmx_enerdata_t *enerd,tensor force_vir, tensor shake_vir, tensor total_vir,
-                            tensor pres, rvec mu_tot, gmx_constr_t constr,
-                            globsig_t *gs,gmx_bool bInterSimGS,
-                            matrix box, gmx_mtop_t *top_global, real *pcurr,
-                            int natoms, gmx_bool *bSumEkinhOld, int flags)
-{
-    int  i,gsi;
-    real gs_buf[eglsNR];
-    tensor corr_vir,corr_pres;
-    gmx_bool bEner,bPres,bTemp;
-    gmx_bool bRerunMD, bStopCM, bGStat, bIterate,
-        bFirstIterate,bReadEkin,bEkinAveVel,bScaleEkin, bConstrain;
-    real prescorr,enercorr,dvdlcorr;
-
-    /* translate CGLO flags to gmx_booleans */
-    bRerunMD = flags & CGLO_RERUNMD;
-    bStopCM = flags & CGLO_STOPCM;
-    bGStat = flags & CGLO_GSTAT;
-    bReadEkin = (flags & CGLO_READEKIN);
-    bScaleEkin = (flags & CGLO_SCALEEKIN);
-    bEner = flags & CGLO_ENERGY;
-    bTemp = flags & CGLO_TEMPERATURE;
-    bPres  = (flags & CGLO_PRESSURE);
-    bConstrain = (flags & CGLO_CONSTRAINT);
-    bIterate = (flags & CGLO_ITERATE);
-    bFirstIterate = (flags & CGLO_FIRSTITERATE);
-
-    /* we calculate a full state kinetic energy either with full-step velocity verlet
-       or half step where we need the pressure */
-    bEkinAveVel = (ir->eI==eiVV || (ir->eI==eiVVAK && IR_NPT_TROTTER(ir) && bPres) || bReadEkin);
-
-    /* in initalization, it sums the shake virial in vv, and to
-       sums ekinh_old in leapfrog (or if we are calculating ekinh_old for other reasons */
-
-    /* ########## Kinetic energy  ############## */
-
-    if (bTemp)
-    {
-        /* Non-equilibrium MD: this is parallellized, but only does communication
-         * when there really is NEMD.
-         */
-
-        if (PAR(cr) && (ekind->bNEMD))
-        {
-            accumulate_u(cr,&(ir->opts),ekind);
-        }
-        debug_gmx();
-        if (bReadEkin)
-        {
-            restore_ekinstate_from_state(cr,ekind,&state_global->ekinstate);
-        }
-        else
-        {
-
-            calc_ke_part(state,&(ir->opts),mdatoms,ekind,nrnb,bEkinAveVel,bIterate);
-        }
-
-        debug_gmx();
-
-        /* Calculate center of mass velocity if necessary, also parallellized */
-        if (bStopCM && !bRerunMD && bEner)
-        {
-            calc_vcm_grp(fplog,mdatoms->start,mdatoms->homenr,mdatoms,
-                         state->x,state->v,vcm);
-        }
-    }
-
-    if (bTemp || bPres || bEner || bConstrain)
-    {
-        if (!bGStat)
-        {
-            /* We will not sum ekinh_old,
-             * so signal that we still have to do it.
-             */
-            *bSumEkinhOld = TRUE;
-
-        }
-        else
-        {
-            if (gs != NULL)
-            {
-                for(i=0; i<eglsNR; i++)
-                {
-                    gs_buf[i] = gs->sig[i];
-                }
-            }
-            if (PAR(cr))
-            {
-                wallcycle_start(wcycle,ewcMoveE);
-                GMX_MPE_LOG(ev_global_stat_start);
-                global_stat(fplog,gstat,cr,enerd,force_vir,shake_vir,mu_tot,
-                            ir,ekind,constr,vcm,
-                            gs != NULL ? eglsNR : 0,gs_buf,
-                            top_global,state,
-                            *bSumEkinhOld,flags);
-                GMX_MPE_LOG(ev_global_stat_finish);
-                wallcycle_stop(wcycle,ewcMoveE);
-            }
-            if (gs != NULL)
-            {
-                if (MULTISIM(cr) && bInterSimGS)
-                {
-                    if (MASTER(cr))
-                    {
-                        /* Communicate the signals between the simulations */
-                        gmx_sum_sim(eglsNR,gs_buf,cr->ms);
-                    }
-                    /* Communicate the signals form the master to the others */
-                    gmx_bcast(eglsNR*sizeof(gs_buf[0]),gs_buf,cr);
-                }
-                for(i=0; i<eglsNR; i++)
-                {
-                    if (bInterSimGS || gs_simlocal[i])
-                    {
-                        /* Set the communicated signal only when it is non-zero,
-                         * since signals might not be processed at each MD step.
-                         */
-                        gsi = (gs_buf[i] >= 0 ?
-                               (int)(gs_buf[i] + 0.5) :
-                               (int)(gs_buf[i] - 0.5));
-                        if (gsi != 0)
-                        {
-                            gs->set[i] = gsi;
-                        }
-                        /* Turn off the local signal */
-                        gs->sig[i] = 0;
-                    }
-                }
-            }
-            *bSumEkinhOld = FALSE;
-        }
-    }
-
-    if (!ekind->bNEMD && debug && bTemp && (vcm->nr > 0))
-    {
-        correct_ekin(debug,
-                     mdatoms->start,mdatoms->start+mdatoms->homenr,
-                     state->v,vcm->group_p[0],
-                     mdatoms->massT,mdatoms->tmass,ekind->ekin);
-    }
-
-    if (bEner) {
-        /* Do center of mass motion removal */
-        if (bStopCM && !bRerunMD) /* is this correct?  Does it get called too often with this logic? */
-        {
-            check_cm_grp(fplog,vcm,ir,1);
-            do_stopcm_grp(fplog,mdatoms->start,mdatoms->homenr,mdatoms->cVCM,
-                          state->x,state->v,vcm);
-            inc_nrnb(nrnb,eNR_STOPCM,mdatoms->homenr);
-        }
-    }
-
-    if (bTemp)
-    {
-        /* Sum the kinetic energies of the groups & calc temp */
-        /* compute full step kinetic energies if vv, or if vv-avek and we are computing the pressure with IR_NPT_TROTTER */
-        /* three maincase:  VV with AveVel (md-vv), vv with AveEkin (md-vv-avek), leap with AveEkin (md).
-           Leap with AveVel is also an option for the future but not supported now.
-           bEkinAveVel: If TRUE, we simply multiply ekin by ekinscale to get a full step kinetic energy.
-           If FALSE, we average ekinh_old and ekinh*ekinscale_nhc to get an averaged half step kinetic energy.
-           bSaveEkinOld: If TRUE (in the case of iteration = bIterate is TRUE), we don't reset the ekinscale_nhc.
-           If FALSE, we go ahead and erase over it.
-        */
-        enerd->term[F_TEMP] = sum_ekin(&(ir->opts),ekind,&(enerd->term[F_DKDL]),
-                                       bEkinAveVel,bIterate,bScaleEkin);
-
-        enerd->term[F_EKIN] = trace(ekind->ekin);
-    }
-
-    /* ##########  Long range energy information ###### */
-
-    if (bEner || bPres || bConstrain)
-    {
-        calc_dispcorr(fplog,ir,fr,0,top_global->natoms,box,state->lambda,
-                      corr_pres,corr_vir,&prescorr,&enercorr,&dvdlcorr);
-    }
-
-    if (bEner && bFirstIterate)
-    {
-        enerd->term[F_DISPCORR] = enercorr;
-        enerd->term[F_EPOT] += enercorr;
-        enerd->term[F_DVDL] += dvdlcorr;
-        if (fr->efep != efepNO) {
-            enerd->dvdl_lin += dvdlcorr;
-        }
-    }
-
-    /* ########## Now pressure ############## */
-    if (bPres || bConstrain)
-    {
-
-        m_add(force_vir,shake_vir,total_vir);
-
-        /* Calculate pressure and apply LR correction if PPPM is used.
-         * Use the box from last timestep since we already called update().
-         */
-
-        enerd->term[F_PRES] = calc_pres(fr->ePBC,ir->nwall,box,ekind->ekin,total_vir,pres,
-                                        (fr->eeltype==eelPPPM)?enerd->term[F_COUL_RECIP]:0.0);
-
-        /* Calculate long range corrections to pressure and energy */
-        /* this adds to enerd->term[F_PRES] and enerd->term[F_ETOT],
-           and computes enerd->term[F_DISPCORR].  Also modifies the
-           total_vir and pres tesors */
-
-        m_add(total_vir,corr_vir,total_vir);
-        m_add(pres,corr_pres,pres);
-        enerd->term[F_PDISPCORR] = prescorr;
-        enerd->term[F_PRES] += prescorr;
-        *pcurr = enerd->term[F_PRES];
-        /* calculate temperature using virial */
-        enerd->term[F_VTEMP] = calc_temp(trace(total_vir),ir->opts.nrdf[0]);
-
-    }
-}
-
-
-/* Definitions for convergence of iterated constraints */
-
-/* iterate constraints up to 50 times  */
-#define MAXITERCONST       50
-
-/* data type */
-typedef struct
-{
-    real f,fprev,x,xprev;
-    int iter_i;
-    gmx_bool bIterate;
-    real allrelerr[MAXITERCONST+2];
-    int num_close; /* number of "close" violations, caused by limited precision. */
-} gmx_iterate_t;
-
-#ifdef GMX_DOUBLE
-#define CONVERGEITER  0.000000001
-#define CLOSE_ENOUGH  0.000001000
-#else
-#define CONVERGEITER  0.0001
-#define CLOSE_ENOUGH  0.0050
-#endif
-
-/* we want to keep track of the close calls.  If there are too many, there might be some other issues.
-   so we make sure that it's either less than some predetermined number, or if more than that number,
-   only some small fraction of the total. */
-#define MAX_NUMBER_CLOSE        50
-#define FRACTION_CLOSE       0.001
-
-/* maximum length of cyclic traps to check, emerging from limited numerical precision  */
-#define CYCLEMAX            20
-
-static void gmx_iterate_init(gmx_iterate_t *iterate,gmx_bool bIterate)
-{
-    int i;
-
-    iterate->iter_i = 0;
-    iterate->bIterate = bIterate;
-    iterate->num_close = 0;
-    for (i=0;i<MAXITERCONST+2;i++)
-    {
-        iterate->allrelerr[i] = 0;
-    }
-}
-
-static gmx_bool done_iterating(const t_commrec *cr,FILE *fplog, int nsteps, gmx_iterate_t *iterate, gmx_bool bFirstIterate, real fom, real *newf)
-{
-    /* monitor convergence, and use a secant search to propose new
-       values.
-                                                                  x_{i} - x_{i-1}
-       The secant method computes x_{i+1} = x_{i} - f(x_{i}) * ---------------------
-                                                                f(x_{i}) - f(x_{i-1})
-
-       The function we are trying to zero is fom-x, where fom is the
-       "figure of merit" which is the pressure (or the veta value) we
-       would get by putting in an old value of the pressure or veta into
-       the incrementor function for the step or half step.  I have
-       verified that this gives the same answer as self consistent
-       iteration, usually in many fewer steps, especially for small tau_p.
-
-       We could possibly eliminate an iteration with proper use
-       of the value from the previous step, but that would take a bit
-       more bookkeeping, especially for veta, since tests indicate the
-       function of veta on the last step is not sufficiently close to
-       guarantee convergence this step. This is
-       good enough for now.  On my tests, I could use tau_p down to
-       0.02, which is smaller that would ever be necessary in
-       practice. Generally, 3-5 iterations will be sufficient */
-
-    real relerr,err;
-    char buf[256];
-    int i;
-    gmx_bool incycle;
-
-    if (bFirstIterate)
-    {
-        iterate->x = fom;
-        iterate->f = fom-iterate->x;
-        iterate->xprev = 0;
-        iterate->fprev = 0;
-        *newf = fom;
-    }
-    else
-    {
-        iterate->f = fom-iterate->x; /* we want to zero this difference */
-        if ((iterate->iter_i > 1) && (iterate->iter_i < MAXITERCONST))
-        {
-            if (iterate->f==iterate->fprev)
-            {
-                *newf = iterate->f;
-            }
-            else
-            {
-                *newf = iterate->x - (iterate->x-iterate->xprev)*(iterate->f)/(iterate->f-iterate->fprev);
-            }
-        }
-        else
-        {
-            /* just use self-consistent iteration the first step to initialize, or
-               if it's not converging (which happens occasionally -- need to investigate why) */
-            *newf = fom;
-        }
-    }
-    /* Consider a slight shortcut allowing us to exit one sooner -- we check the
-       difference between the closest of x and xprev to the new
-       value. To be 100% certain, we should check the difference between
-       the last result, and the previous result, or
-
-       relerr = (fabs((x-xprev)/fom));
-
-       but this is pretty much never necessary under typical conditions.
-       Checking numerically, it seems to lead to almost exactly the same
-       trajectories, but there are small differences out a few decimal
-       places in the pressure, and eventually in the v_eta, but it could
-       save an interation.
-
-       if (fabs(*newf-x) < fabs(*newf - xprev)) { xmin = x;} else { xmin = xprev;}
-       relerr = (fabs((*newf-xmin) / *newf));
-    */
-
-    err = fabs((iterate->f-iterate->fprev));
-    relerr = fabs(err/fom);
-
-    iterate->allrelerr[iterate->iter_i] = relerr;
-
-    if (iterate->iter_i > 0)
-    {
-        if (debug)
-        {
-            fprintf(debug,"Iterating NPT constraints: %6i %20.12f%14.6g%20.12f\n",
-                    iterate->iter_i,fom,relerr,*newf);
-        }
-
-        if ((relerr < CONVERGEITER) || (err < CONVERGEITER) || (fom==0) || ((iterate->x == iterate->xprev) && iterate->iter_i > 1))
-        {
-            iterate->bIterate = FALSE;
-            if (debug)
-            {
-                fprintf(debug,"Iterating NPT constraints: CONVERGED\n");
-            }
-            return TRUE;
-        }
-        if (iterate->iter_i > MAXITERCONST)
-        {
-            if (relerr < CLOSE_ENOUGH)
-            {
-                incycle = FALSE;
-                for (i=1;i<CYCLEMAX;i++) {
-                    if ((iterate->allrelerr[iterate->iter_i-(1+i)] == iterate->allrelerr[iterate->iter_i-1]) &&
-                        (iterate->allrelerr[iterate->iter_i-(1+i)] == iterate->allrelerr[iterate->iter_i-(1+2*i)])) {
-                        incycle = TRUE;
-                        if (debug)
-                        {
-                            fprintf(debug,"Exiting from an NPT iterating cycle of length %d\n",i);
-                        }
-                        break;
-                    }
-                }
-
-                if (incycle) {
-                    /* step 1: trapped in a numerical attractor */
-                    /* we are trapped in a numerical attractor, and can't converge any more, and are close to the final result.
-                       Better to give up convergence here than have the simulation die.
-                    */
-                    iterate->num_close++;
-                    return TRUE;
-                }
-                else
-                {
-                    /* Step #2: test if we are reasonably close for other reasons, then monitor the number.  If not, die */
-
-                    /* how many close calls have we had?  If less than a few, we're OK */
-                    if (iterate->num_close < MAX_NUMBER_CLOSE)
-                    {
-                        sprintf(buf,"Slight numerical convergence deviation with NPT at step %d, relative error only %10.5g, likely not a problem, continuing\n",nsteps,relerr);
-                        md_print_warning(cr,fplog,buf);
-                        iterate->num_close++;
-                        return TRUE;
-                        /* if more than a few, check the total fraction.  If too high, die. */
-                    } else if (iterate->num_close/(double)nsteps > FRACTION_CLOSE) {
-                        gmx_fatal(FARGS,"Could not converge NPT constraints, too many exceptions (%d%%\n",iterate->num_close/(double)nsteps);
-                    }
-                }
-            }
-            else
-            {
-                gmx_fatal(FARGS,"Could not converge NPT constraints\n");
-            }
-        }
-    }
-
-    iterate->xprev = iterate->x;
-    iterate->x = *newf;
-    iterate->fprev = iterate->f;
-    iterate->iter_i++;
-
-    return FALSE;
-}
-
-static void check_nst_param(FILE *fplog,t_commrec *cr,
-                            const char *desc_nst,int nst,
-                            const char *desc_p,int *p)
-{
-    char buf[STRLEN];
-
-    if (*p > 0 && *p % nst != 0)
-    {
-        /* Round up to the next multiple of nst */
-        *p = ((*p)/nst + 1)*nst;
-        sprintf(buf,"NOTE: %s changes %s to %d\n",desc_nst,desc_p,*p);
-        md_print_warning(cr,fplog,buf);
-    }
-}
-
-static void reset_all_counters(FILE *fplog,t_commrec *cr,
-                               gmx_large_int_t step,
-                               gmx_large_int_t *step_rel,t_inputrec *ir,
-                               gmx_wallcycle_t wcycle,t_nrnb *nrnb,
-                               gmx_runtime_t *runtime)
-{
-    char buf[STRLEN],sbuf[STEPSTRSIZE];
-
-    /* Reset all the counters related to performance over the run */
-    sprintf(buf,"Step %s: resetting all time and cycle counters\n",
-            gmx_step_str(step,sbuf));
-    md_print_warning(cr,fplog,buf);
-
-    wallcycle_stop(wcycle,ewcRUN);
-    wallcycle_reset_all(wcycle);
-    if (DOMAINDECOMP(cr))
-    {
-        reset_dd_statistics_counters(cr->dd);
-    }
-    init_nrnb(nrnb);
-    ir->init_step += *step_rel;
-    ir->nsteps    -= *step_rel;
-    *step_rel = 0;
-    wallcycle_start(wcycle,ewcRUN);
-    runtime_start(runtime);
-    print_date_and_time(fplog,cr->nodeid,"Restarted time",runtime);
-}
-
-static int check_nstglobalcomm(FILE *fplog,t_commrec *cr,
-                               int nstglobalcomm,t_inputrec *ir)
-{
-    char buf[STRLEN];
-
-    if (!EI_DYNAMICS(ir->eI))
-    {
-        nstglobalcomm = 1;
-    }
-
-    if (nstglobalcomm == -1)
-    {
-        if (ir->nstcalcenergy == 0 && ir->nstlist == 0)
-        {
-            nstglobalcomm = 10;
-            if (ir->nstenergy > 0 && ir->nstenergy < nstglobalcomm)
-            {
-                nstglobalcomm = ir->nstenergy;
-            }
-        }
-        else
-        {
-            /* We assume that if nstcalcenergy > nstlist,
-             * nstcalcenergy is a multiple of nstlist.
-             */
-            if (ir->nstcalcenergy == 0 ||
-                (ir->nstlist > 0 && ir->nstlist < ir->nstcalcenergy))
-            {
-                nstglobalcomm = ir->nstlist;
-            }
-            else
-            {
-                nstglobalcomm = ir->nstcalcenergy;
-            }
-        }
-    }
-    else
-    {
-        if (ir->nstlist > 0 &&
-            nstglobalcomm > ir->nstlist && nstglobalcomm % ir->nstlist != 0)
-        {
-            nstglobalcomm = (nstglobalcomm / ir->nstlist)*ir->nstlist;
-            sprintf(buf,"WARNING: nstglobalcomm is larger than nstlist, but not a multiple, setting it to %d\n",nstglobalcomm);
-            md_print_warning(cr,fplog,buf);
-        }
-        if (nstglobalcomm > ir->nstcalcenergy)
-        {
-            check_nst_param(fplog,cr,"-gcom",nstglobalcomm,
-                            "nstcalcenergy",&ir->nstcalcenergy);
-        }
-
-        check_nst_param(fplog,cr,"-gcom",nstglobalcomm,
-                        "nstenergy",&ir->nstenergy);
-
-        check_nst_param(fplog,cr,"-gcom",nstglobalcomm,
-                        "nstlog",&ir->nstlog);
-    }
-
-    if (ir->comm_mode != ecmNO && ir->nstcomm < nstglobalcomm)
-    {
-        sprintf(buf,"WARNING: Changing nstcomm from %d to %d\n",
-                ir->nstcomm,nstglobalcomm);
-        md_print_warning(cr,fplog,buf);
-        ir->nstcomm = nstglobalcomm;
-    }
-
-    return nstglobalcomm;
-}
-
-void check_ir_old_tpx_versions(t_commrec *cr,FILE *fplog,
-                               t_inputrec *ir,gmx_mtop_t *mtop)
-{
-    /* Check required for old tpx files */
-    if (IR_TWINRANGE(*ir) && ir->nstlist > 1 &&
-        ir->nstcalcenergy % ir->nstlist != 0)
-    {
-        md_print_warning(cr,fplog,"Old tpr file with twin-range settings: modifying energy calculation and/or T/P-coupling frequencies");
-
-        if (gmx_mtop_ftype_count(mtop,F_CONSTR) +
-            gmx_mtop_ftype_count(mtop,F_CONSTRNC) > 0 &&
-            ir->eConstrAlg == econtSHAKE)
-        {
-            md_print_warning(cr,fplog,"With twin-range cut-off's and SHAKE the virial and pressure are incorrect");
-            if (ir->epc != epcNO)
-            {
-                gmx_fatal(FARGS,"Can not do pressure coupling with twin-range cut-off's and SHAKE");
-            }
-        }
-        check_nst_param(fplog,cr,"nstlist",ir->nstlist,
-                        "nstcalcenergy",&ir->nstcalcenergy);
-       check_nst_param(fplog,cr,"nstcalcenergy",ir->nstcalcenergy,
-                       "nstenergy",&ir->nstenergy);
-        check_nst_param(fplog,cr,"nstcalcenergy",ir->nstcalcenergy,
-                        "nstlog",&ir->nstlog);
-        if (ir->efep != efepNO)
-        {
-            check_nst_param(fplog,cr,"nstcalcenergy",ir->nstcalcenergy,
-                            "nstdhdl",&ir->nstdhdl);
-        }
-    }
-}
-
-typedef struct {
-    gmx_bool       bGStatEveryStep;
-    gmx_large_int_t step_ns;
-    gmx_large_int_t step_nscheck;
-    gmx_large_int_t nns;
-    matrix     scale_tot;
-    int        nabnsb;
-    double     s1;
-    double     s2;
-    double     ab;
-    double     lt_runav;
-    double     lt_runav2;
-} gmx_nlheur_t;
-
-static void reset_nlistheuristics(gmx_nlheur_t *nlh,gmx_large_int_t step)
-{
-    nlh->lt_runav  = 0;
-    nlh->lt_runav2 = 0;
-    nlh->step_nscheck = step;
-}
-
-static void init_nlistheuristics(gmx_nlheur_t *nlh,
-                                 gmx_bool bGStatEveryStep,gmx_large_int_t step)
-{
-    nlh->bGStatEveryStep = bGStatEveryStep;
-    nlh->nns       = 0;
-    nlh->nabnsb    = 0;
-    nlh->s1        = 0;
-    nlh->s2        = 0;
-    nlh->ab        = 0;
-
-    reset_nlistheuristics(nlh,step);
-}
-
-static void update_nliststatistics(gmx_nlheur_t *nlh,gmx_large_int_t step)
-{
-    gmx_large_int_t nl_lt;
-    char sbuf[STEPSTRSIZE],sbuf2[STEPSTRSIZE];
-
-    /* Determine the neighbor list life time */
-    nl_lt = step - nlh->step_ns;
-    if (debug)
-    {
-        fprintf(debug,"%d atoms beyond ns buffer, updating neighbor list after %s steps\n",nlh->nabnsb,gmx_step_str(nl_lt,sbuf));
-    }
-    nlh->nns++;
-    nlh->s1 += nl_lt;
-    nlh->s2 += nl_lt*nl_lt;
-    nlh->ab += nlh->nabnsb;
-    if (nlh->lt_runav == 0)
-    {
-        nlh->lt_runav  = nl_lt;
-        /* Initialize the fluctuation average
-         * such that at startup we check after 0 steps.
-         */
-        nlh->lt_runav2 = sqr(nl_lt/2.0);
-    }
-    /* Running average with 0.9 gives an exp. history of 9.5 */
-    nlh->lt_runav2 = 0.9*nlh->lt_runav2 + 0.1*sqr(nlh->lt_runav - nl_lt);
-    nlh->lt_runav  = 0.9*nlh->lt_runav  + 0.1*nl_lt;
-    if (nlh->bGStatEveryStep)
-    {
-        /* Always check the nlist validity */
-        nlh->step_nscheck = step;
-    }
-    else
-    {
-        /* We check after:  <life time> - 2*sigma
-         * The factor 2 is quite conservative,
-         * but we assume that with nstlist=-1 the user
-         * prefers exact integration over performance.
-         */
-        nlh->step_nscheck = step
-                  + (int)(nlh->lt_runav - 2.0*sqrt(nlh->lt_runav2)) - 1;
-    }
-    if (debug)
-    {
-        fprintf(debug,"nlist life time %s run av. %4.1f sig %3.1f check %s check with -gcom %d\n",
-                gmx_step_str(nl_lt,sbuf),nlh->lt_runav,sqrt(nlh->lt_runav2),
-                gmx_step_str(nlh->step_nscheck-step+1,sbuf2),
-                (int)(nlh->lt_runav - 2.0*sqrt(nlh->lt_runav2)));
-    }
-}
-
-static void set_nlistheuristics(gmx_nlheur_t *nlh,gmx_bool bReset,gmx_large_int_t step)
-{
-    int d;
-
-    if (bReset)
-    {
-        reset_nlistheuristics(nlh,step);
-    }
-    else
-    {
-        update_nliststatistics(nlh,step);
-    }
-
-    nlh->step_ns = step;
-    /* Initialize the cumulative coordinate scaling matrix */
-    clear_mat(nlh->scale_tot);
-    for(d=0; d<DIM; d++)
-    {
-        nlh->scale_tot[d][d] = 1.0;
-    }
-}
-
-double do_md_membed(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_seed,
-             real cpt_period,real max_hours,
-             const char *deviceOptions,
-             unsigned long Flags,
-             gmx_runtime_t *runtime,
-             rvec fac, rvec *r_ins, pos_ins_t *pos_ins, t_block *ins_at,
-             real xy_step, real z_step, int it_xy, int it_z)
-{
-    gmx_mdoutf_t *outf;
-    gmx_large_int_t step,step_rel;
-    double     run_time;
-    double     t,t0,lam0;
-    gmx_bool       bGStatEveryStep,bGStat,bNstEner,bCalcEnerPres;
-    gmx_bool       bNS,bNStList,bSimAnn,bStopCM,bRerunMD,bNotLastFrame=FALSE,
-               bFirstStep,bStateFromTPX,bInitStep,bLastStep,
-               bBornRadii,bStartingFromCpt;
-    gmx_bool       bDoDHDL=FALSE;
-    gmx_bool       do_ene,do_log,do_verbose,bRerunWarnNoV=TRUE,
-               bForceUpdate=FALSE,bCPT;
-    int        mdof_flags;
-    gmx_bool       bMasterState;
-    int        force_flags,cglo_flags;
-    tensor     force_vir,shake_vir,total_vir,tmp_vir,pres;
-    int        i,m;
-    t_trxstatus *status;
-    rvec       mu_tot;
-    t_vcm      *vcm;
-    t_state    *bufstate=NULL;
-    matrix     *scale_tot,pcoupl_mu,M,ebox;
-    gmx_nlheur_t nlh;
-    t_trxframe rerun_fr;
-/*    gmx_repl_ex_t repl_ex=NULL;*/
-    int        nchkpt=1;
-
-    gmx_localtop_t *top;
-    t_mdebin *mdebin=NULL;
-    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_bool        bFFscan;
-    gmx_groups_t *groups;
-    gmx_ekindata_t *ekind, *ekind_save;
-    gmx_shellfc_t shellfc;
-    int         count,nconverged=0;
-    real        timestep=0;
-    double      tcount=0;
-    gmx_bool        bIonize=FALSE;
-    gmx_bool        bTCR=FALSE,bConverged=TRUE,bOK,bSumEkinhOld,bExchanged;
-    gmx_bool        bAppend;
-    gmx_bool        bResetCountersHalfMaxH=FALSE;
-    gmx_bool        bVV,bIterations,bIterate,bFirstIterate,bTemp,bPres,bTrotter;
-    real        temp0,dvdl;
-    int         a0,a1,ii;
-    rvec        *xcopy=NULL,*vcopy=NULL,*cbuf=NULL;
-    matrix      boxcopy={{0}},lastbox;
-       real        veta_save,pcurr,scalevir,tracevir;
-       real        vetanew = 0;
-    double      cycles;
-       real        last_conserved = 0;
-    real        last_ekin = 0;
-       t_extmass   MassQ;
-    int         **trotter_seq;
-    char        sbuf[STEPSTRSIZE],sbuf2[STEPSTRSIZE];
-    int         handled_stop_condition=gmx_stop_cond_none; /* compare to get_stop_condition*/
-    gmx_iterate_t iterate;
-#ifdef GMX_FAHCORE
-    /* Temporary addition for FAHCORE checkpointing */
-    int chkpt_ret;
-#endif
-
-    /* Check for special mdrun options */
-    bRerunMD = (Flags & MD_RERUN);
-    bIonize  = (Flags & MD_IONIZE);
-    bFFscan  = (Flags & MD_FFSCAN);
-    bAppend  = (Flags & MD_APPENDFILES);
-    bGStatEveryStep = FALSE;
-    if (Flags & MD_RESETCOUNTERSHALFWAY)
-    {
-        if (ir->nsteps > 0)
-        {
-            /* Signal to reset the counters half the simulation steps. */
-            wcycle_set_reset_counters(wcycle,ir->nsteps/2);
-        }
-        /* Signal to reset the counters halfway the simulation time. */
-        bResetCountersHalfMaxH = (max_hours > 0);
-    }
-
-    /* md-vv uses averaged full step velocities for T-control
-       md-vv-avek uses averaged half step velocities for T-control (but full step ekin for P control)
-       md uses averaged half step kinetic energies to determine temperature unless defined otherwise by GMX_EKIN_AVE_VEL; */
-    bVV = EI_VV(ir->eI);
-    if (bVV) /* to store the initial velocities while computing virial */
-    {
-        snew(cbuf,top_global->natoms);
-    }
-    /* all the iteratative cases - only if there are constraints */
-    bIterations = ((IR_NPT_TROTTER(ir)) && (constr) && (!bRerunMD));
-    bTrotter = (bVV && (IR_NPT_TROTTER(ir) || (IR_NVT_TROTTER(ir))));
-
-    if (bRerunMD)
-    {
-        /* Since we don't know if the frames read are related in any way,
-         * rebuild the neighborlist at every step.
-         */
-        ir->nstlist       = 1;
-        ir->nstcalcenergy = 1;
-        nstglobalcomm     = 1;
-    }
-
-    check_ir_old_tpx_versions(cr,fplog,ir,top_global);
-
-    nstglobalcomm = check_nstglobalcomm(fplog,cr,nstglobalcomm,ir);
-    /*bGStatEveryStep = (nstglobalcomm == 1);*/
-    bGStatEveryStep = FALSE;
-
-    if (!bGStatEveryStep && ir->nstlist == -1 && fplog != NULL)
-    {
-        fprintf(fplog,
-                "To reduce the energy communication with nstlist = -1\n"
-                "the neighbor list validity should not be checked at every step,\n"
-                "this means that exact integration is not guaranteed.\n"
-                "The neighbor list validity is checked after:\n"
-                "  <n.list life time> - 2*std.dev.(n.list life time)  steps.\n"
-                "In most cases this will result in exact integration.\n"
-                "This reduces the energy communication by a factor of 2 to 3.\n"
-                "If you want less energy communication, set nstlist > 3.\n\n");
-    }
-
-    if (bRerunMD || bFFscan)
-    {
-        ir->nstxtcout = 0;
-    }
-    groups = &top_global->groups;
-
-    /* Initial values */
-    init_md(fplog,cr,ir,oenv,&t,&t0,&state_global->lambda,&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->n_flambda,enerd);
-    if (DOMAINDECOMP(cr))
-    {
-        f = NULL;
-    }
-    else
-    {
-        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();
-
-    /* Check for polarizable models and flexible constraints */
-    shellfc = init_shell_flexcon(fplog,
-                                 top_global,n_flexible_constraints(constr),
-                                 (ir->bContinuation ||
-                                  (DOMAINDECOMP(cr) && !MASTER(cr))) ?
-                                 NULL : state_global->x);
-
-/*    if (DEFORM(*ir))
-    {
-#ifdef GMX_THREADS
-        tMPI_Thread_mutex_lock(&deform_init_box_mutex);
-#endif
-        set_deform_reference_box(upd,
-                                 deform_init_init_step_tpx,
-                                 deform_init_box_tpx);
-#ifdef GMX_THREADS
-        tMPI_Thread_mutex_unlock(&deform_init_box_mutex);
-#endif
-    }*/
-
-/*    {
-        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);
-    }*/
-
-    if (DOMAINDECOMP(cr)) {
-        top = dd_init_local_top(top_global);
-
-        snew(state,1);
-        dd_init_local_state(cr->dd,state_global,state);
-
-        if (DDMASTER(cr->dd) && ir->nstfout) {
-            snew(f_global,state_global->natoms);
-        }
-    } else {
-        if (PAR(cr)) {
-            /* Initialize the particle decomposition and split the topology */
-            top = split_system(fplog,top_global,ir,cr);
-
-            pd_cg_range(cr,&fr->cg0,&fr->hcg);
-            pd_at_range(cr,&a0,&a1);
-        } else {
-            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);
-        }
-
-        if (shellfc) {
-            make_local_shells(cr,mdatoms,shellfc);
-        }
-
-        if (ir->pull && PAR(cr)) {
-            dd_make_local_pull_groups(NULL,ir->pull,mdatoms);
-        }
-    }
-
-    if (DOMAINDECOMP(cr))
-    {
-        /* Distribute the charge groups over the nodes from the master node */
-        dd_partition_system(fplog,ir->init_step,cr,TRUE,1,
-                            state_global,top_global,ir,
-                            state,&f,mdatoms,top,fr,
-                            vsite,shellfc,constr,
-                            nrnb,wcycle,FALSE);
-    }
-
-    update_mdatoms(mdatoms,state->lambda);
-
-    if (MASTER(cr))
-    {
-        if (opt2bSet("-cpi",nfile,fnm))
-        {
-            /* Update mdebin with energy history if appending to output files */
-            if ( Flags & MD_APPENDFILES )
-            {
-                restore_energyhistory_from_state(mdebin,&state_global->enerhist);
-            }
-            else
-            {
-                /* We might have read an energy history from checkpoint,
-                 * free the allocated memory and reset the counts.
-                 */
-                done_energyhistory(&state_global->enerhist);
-                init_energyhistory(&state_global->enerhist);
-            }
-        }
-        /* Set the initial energy history in state by updating once */
-        update_energyhistory(&state_global->enerhist,mdebin);
-    }
-
-    if ((state->flags & (1<<estLD_RNG)) && (Flags & MD_READ_RNG)) {
-        /* Set the random state if we read a checkpoint file */
-        set_stochd_state(upd,state);
-    }
-
-    /* Initialize constraints */
-    if (constr) {
-        if (!DOMAINDECOMP(cr))
-            set_constraints(constr,top,ir,mdatoms,cr);
-    }
-
-    /* Check whether we have to GCT stuff */
- /*   bTCR = ftp2bSet(efGCT,nfile,fnm);
-    if (bTCR) {
-        if (MASTER(cr)) {
-            fprintf(stderr,"Will do General Coupling Theory!\n");
-        }
-        gnx = top_global->mols.nr;
-        snew(grpindex,gnx);
-        for(i=0; (i<gnx); i++) {
-            grpindex[i] = i;
-        }
-    }*/
-
-/*    if (repl_ex_nst > 0 && MASTER(cr))
-        repl_ex = init_replica_exchange(fplog,cr->ms,state_global,ir,
-                                        repl_ex_nst,repl_ex_seed);*/
-
-    if (!ir->bContinuation && !bRerunMD)
-    {
-        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();
-
-    /* I'm assuming we need global communication the first time! MRS */
-    cglo_flags = (CGLO_TEMPERATURE | CGLO_GSTAT
-                  | (bVV ? CGLO_PRESSURE:0)
-                  | (bVV ? CGLO_CONSTRAINT:0)
-                  | (bRerunMD ? CGLO_RERUNMD:0)
-                  | ((Flags & MD_READ_EKIN) ? CGLO_READEKIN:0));
-
-    bSumEkinhOld = FALSE;
-    compute_globals(fplog,gstat,cr,ir,fr,ekind,state,state_global,mdatoms,nrnb,vcm,
-                    wcycle,enerd,force_vir,shake_vir,total_vir,pres,mu_tot,
-                    constr,NULL,FALSE,state->box,
-                    top_global,&pcurr,top_global->natoms,&bSumEkinhOld,cglo_flags);
-    if (ir->eI == eiVVAK) {
-        /* a second call to get the half step temperature initialized as well */
-        /* we do the same call as above, but turn the pressure off -- internally, this
-           is recognized as a velocity verlet half-step kinetic energy calculation.
-           This minimized excess variables, but perhaps loses some logic?*/
-
-        compute_globals(fplog,gstat,cr,ir,fr,ekind,state,state_global,mdatoms,nrnb,vcm,
-                        wcycle,enerd,force_vir,shake_vir,total_vir,pres,mu_tot,
-                        constr,NULL,FALSE,state->box,
-                        top_global,&pcurr,top_global->natoms,&bSumEkinhOld,
-                        cglo_flags &~ CGLO_PRESSURE);
-    }
-
-    /* Calculate the initial half step temperature, and save the ekinh_old */
-    if (!(Flags & MD_STARTFROMCPT))
-    {
-        for(i=0; (i<ir->opts.ngtc); i++)
-        {
-            copy_mat(ekind->tcstat[i].ekinh,ekind->tcstat[i].ekinh_old);
-        }
-    }
-    if (ir->eI != eiVV) 
-    {
-        enerd->term[F_TEMP] *= 2; /* result of averages being done over previous and current step,
-                                     and there is no previous step */
-    }
-    temp0 = enerd->term[F_TEMP];
-
-    /* if using an iterative algorithm, we need to create a working directory for the state. */
-    if (bIterations)
-    {
-            bufstate = init_bufstate(state);
-    }
-    if (bFFscan)
-    {
-        snew(xcopy,state->natoms);
-        snew(vcopy,state->natoms);
-        copy_rvecn(state->x,xcopy,0,state->natoms);
-        copy_rvecn(state->v,vcopy,0,state->natoms);
-        copy_mat(state->box,boxcopy);
-    }
-
-    /* need to make an initiation call to get the Trotter variables set, as well as other constants for non-trotter
-       temperature control */
-    trotter_seq = init_npt_vars(ir,state,&MassQ,bTrotter);
-
-    if (MASTER(cr))
-    {
-        if (constr && !ir->bContinuation && ir->eConstrAlg == econtLINCS)
-        {
-            fprintf(fplog,
-                    "RMS relative constraint deviation after constraining: %.2e\n",
-                    constr_rmsd(constr,FALSE));
-        }
-        fprintf(fplog,"Initial temperature: %g K\n",enerd->term[F_TEMP]);
-        if (bRerunMD)
-        {
-            fprintf(stderr,"starting md rerun '%s', reading coordinates from"
-                    " input trajectory '%s'\n\n",
-                    *(top_global->name),opt2fn("-rerun",nfile,fnm));
-            if (bVerbose)
-            {
-                fprintf(stderr,"Calculated time to finish depends on nsteps from "
-                        "run input file,\nwhich may not correspond to the time "
-                        "needed to process input trajectory.\n\n");
-            }
-        }
-        else
-        {
-            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 */
-/*#ifdef GMX_FAHCORE
-    chkpt_ret=fcCheckPointParallel( cr->nodeid,
-                                    NULL,0);
-    if ( chkpt_ret == 0 )
-        gmx_fatal( 3,__FILE__,__LINE__, "Checkpoint error on step %d\n", 0 );
-#endif*/
-
-    debug_gmx();
-    /***********************************************************
-     *
-     *             Loop over MD steps
-     *
-     ************************************************************/
-
-    /* if rerunMD then read coordinates and velocities from input trajectory */
-    if (bRerunMD)
-    {
-        if (getenv("GMX_FORCE_UPDATE"))
-        {
-            bForceUpdate = TRUE;
-        }
-
-        bNotLastFrame = read_first_frame(oenv,&status,
-                                         opt2fn("-rerun",nfile,fnm),
-                                         &rerun_fr,TRX_NEED_X | TRX_READ_V);
-        if (rerun_fr.natoms != top_global->natoms)
-        {
-            gmx_fatal(FARGS,
-                      "Number of atoms in trajectory (%d) does not match the "
-                      "run input file (%d)\n",
-                      rerun_fr.natoms,top_global->natoms);
-        }
-        if (ir->ePBC != epbcNONE)
-        {
-            if (!rerun_fr.bBox)
-            {
-                gmx_fatal(FARGS,"Rerun trajectory frame step %d time %f does not contain a box, while pbc is used",rerun_fr.step,rerun_fr.time);
-            }
-            if (max_cutoff2(ir->ePBC,rerun_fr.box) < sqr(fr->rlistlong))
-            {
-                gmx_fatal(FARGS,"Rerun trajectory frame step %d time %f has too small box dimensions",rerun_fr.step,rerun_fr.time);
-            }
-
-            /* Set the shift vectors.
-             * Necessary here when have a static box different from the tpr box.
-             */
-            calc_shifts(rerun_fr.box,fr->shift_vec);
-        }
-    }
-
-    /* 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 || bVV);
-    bStartingFromCpt = (Flags & MD_STARTFROMCPT) && bInitStep;
-    bLastStep    = FALSE;
-    bSumEkinhOld = FALSE;
-    bExchanged   = FALSE;
-
-    init_global_signals(&gs,cr,ir,repl_ex_nst);
-
-    step = ir->init_step;
-    step_rel = 0;
-
-    if (ir->nstlist == -1)
-    {
-        init_nlistheuristics(&nlh,bGStatEveryStep,step);
-    }
-
-    bLastStep = (bRerunMD || (ir->nsteps >= 0 && step_rel > ir->nsteps));
-    while (!bLastStep || (bRerunMD && bNotLastFrame)) {
-
-        wallcycle_start(wcycle,ewcSTEP);
-
-        GMX_MPE_LOG(ev_timestep1);
-
-        if (bRerunMD) {
-            if (rerun_fr.bStep) {
-                step = rerun_fr.step;
-                step_rel = step - ir->init_step;
-            }
-            if (rerun_fr.bTime) {
-                t = rerun_fr.time;
-            }
-            else
-            {
-                t = step;
-            }
-        }
-        else
-        {
-            bLastStep = (step_rel == ir->nsteps);
-            t = t0 + step*ir->delta_t;
-        }
-
-        if (ir->efep != efepNO)
-        {
-            if (bRerunMD && rerun_fr.bLambda && (ir->delta_lambda!=0))
-            {
-                state_global->lambda = rerun_fr.lambda;
-            }
-            else
-            {
-                state_global->lambda = lam0 + step*ir->delta_lambda;
-            }
-            state->lambda = state_global->lambda;
-            bDoDHDL = do_per_step(step,ir->nstdhdl);
-        }
-
-        if (bSimAnn)
-        {
-            update_annealing_target_temp(&(ir->opts),t);
-        }
-
-        if (bRerunMD)
-        {
-            if (!(DOMAINDECOMP(cr) && !MASTER(cr)))
-            {
-                for(i=0; i<state_global->natoms; i++)
-                {
-                    copy_rvec(rerun_fr.x[i],state_global->x[i]);
-                }
-                if (rerun_fr.bV)
-                {
-                    for(i=0; i<state_global->natoms; i++)
-                    {
-                        copy_rvec(rerun_fr.v[i],state_global->v[i]);
-                    }
-                }
-                else
-                {
-                    for(i=0; i<state_global->natoms; i++)
-                    {
-                        clear_rvec(state_global->v[i]);
-                    }
-                    if (bRerunWarnNoV)
-                    {
-                        fprintf(stderr,"\nWARNING: Some frames do not contain velocities.\n"
-                                "         Ekin, temperature and pressure are incorrect,\n"
-                                "         the virial will be incorrect when constraints are present.\n"
-                                "\n");
-                        bRerunWarnNoV = FALSE;
-                    }
-                }
-            }
-            copy_mat(rerun_fr.box,state_global->box);
-            copy_mat(state_global->box,state->box);
-
-            if (vsite && (Flags & MD_RERUN_VSITE))
-            {
-                if (DOMAINDECOMP(cr))
-                {
-                    gmx_fatal(FARGS,"Vsite recalculation with -rerun is not implemented for domain decomposition, use particle decomposition");
-                }
-                if (graph)
-                {
-                    /* Following is necessary because the graph may get out of sync
-                     * with the coordinates if we only have every N'th coordinate set
-                     */
-                    mk_mshift(fplog,graph,fr->ePBC,state->box,state->x);
-                    shift_self(graph,state->box,state->x);
-                }
-                construct_vsites(fplog,vsite,state->x,nrnb,ir->delta_t,state->v,
-                                 top->idef.iparams,top->idef.il,
-                                 fr->ePBC,fr->bMolPBC,graph,cr,state->box);
-                if (graph)
-                {
-                    unshift_self(graph,state->box,state->x);
-                }
-            }
-        }
-
-        /* Stop Center of Mass motion */
-        bStopCM = (ir->comm_mode != ecmNO && do_per_step(step,ir->nstcomm));
-
-        /* Copy back starting coordinates in case we're doing a forcefield scan */
-        if (bFFscan)
-        {
-            for(ii=0; (ii<state->natoms); ii++)
-            {
-                copy_rvec(xcopy[ii],state->x[ii]);
-                copy_rvec(vcopy[ii],state->v[ii]);
-            }
-            copy_mat(boxcopy,state->box);
-        }
-
-        if (bRerunMD)
-        {
-            /* for rerun MD always do Neighbour Searching */
-            bNS = (bFirstStep || ir->nstlist != 0);
-            bNStList = bNS;
-        }
-        else
-        {
-            /* Determine whether or not to do Neighbour Searching and LR */
-            bNStList = (ir->nstlist > 0  && step % ir->nstlist == 0);
-
-            bNS = (bFirstStep || bExchanged || bNStList ||
-                   (ir->nstlist == -1 && nlh.nabnsb > 0));
-
-            if (bNS && ir->nstlist == -1)
-            {
-                set_nlistheuristics(&nlh,bFirstStep || bExchanged,step);
-            }
-        }
-
-        /* < 0 means stop at next step, > 0 means stop at next NS step */
-        if ( (gs.set[eglsSTOPCOND] < 0 ) ||
-             ( (gs.set[eglsSTOPCOND] > 0 ) && ( bNS || ir->nstlist==0)) )
-        {
-            bLastStep = TRUE;
-        }
-
-        /* Determine whether or not to update the Born radii if doing GB */
-        bBornRadii=bFirstStep;
-        if (ir->implicit_solvent && (step % ir->nstgbradii==0))
-        {
-            bBornRadii=TRUE;
-        }
-
-        do_log = do_per_step(step,ir->nstlog) || bFirstStep || bLastStep;
-        do_verbose = bVerbose &&
-                  (step % stepout == 0 || bFirstStep || bLastStep);
-
-        if (bNS && !(bFirstStep && ir->bContinuation && !bRerunMD))
-        {
-            if (bRerunMD)
-            {
-                bMasterState = TRUE;
-            }
-            else
-            {
-                bMasterState = FALSE;
-                /* Correct the new box if it is too skewed */
-                if (DYNAMIC_BOX(*ir))
-                {
-                    if (correct_box(fplog,step,state->box,graph))
-                    {
-                        bMasterState = TRUE;
-                    }
-                }
-                if (DOMAINDECOMP(cr) && bMasterState)
-                {
-                    dd_collect_state(cr->dd,state,state_global);
-                }
-            }
-
-            if (DOMAINDECOMP(cr))
-            {
-                /* Repartition the domain decomposition */
-                wallcycle_start(wcycle,ewcDOMDEC);
-                dd_partition_system(fplog,step,cr,
-                                    bMasterState,nstglobalcomm,
-                                    state_global,top_global,ir,
-                                    state,&f,mdatoms,top,fr,
-                                    vsite,shellfc,constr,
-                                    nrnb,wcycle,do_verbose);
-                wallcycle_stop(wcycle,ewcDOMDEC);
-                /* If using an iterative integrator, reallocate space to match the decomposition */
-            }
-        }
-
-        if (MASTER(cr) && do_log && !bFFscan)
-        {
-            print_ebin_header(fplog,step,t,state->lambda);
-        }
-
-        if (ir->efep != efepNO)
-        {
-            update_mdatoms(mdatoms,state->lambda);
-        }
-
-        if (bRerunMD && rerun_fr.bV)
-        {
-
-            /* We need the kinetic energy at minus the half step for determining
-             * the full step kinetic energy and possibly for T-coupling.*/
-            /* This may not be quite working correctly yet . . . . */
-            compute_globals(fplog,gstat,cr,ir,fr,ekind,state,state_global,mdatoms,nrnb,vcm,
-                            wcycle,enerd,NULL,NULL,NULL,NULL,mu_tot,
-                            constr,NULL,FALSE,state->box,
-                            top_global,&pcurr,top_global->natoms,&bSumEkinhOld,
-                            CGLO_RERUNMD | CGLO_GSTAT | CGLO_TEMPERATURE);
-        }
-        clear_mat(force_vir);
-
-        /* Ionize the atoms if necessary */
-/*        if (bIonize)
-        {
-            ionize(fplog,oenv,mdatoms,top_global,t,ir,state->x,state->v,
-                   mdatoms->start,mdatoms->start+mdatoms->homenr,state->box,cr);
-        }*/
-
-        /* Update force field in ffscan program */
-/*        if (bFFscan)
-        {
-            if (update_forcefield(fplog,
-                                  nfile,fnm,fr,
-                                  mdatoms->nr,state->x,state->box)) {
-                if (gmx_parallel_env_initialized())
-                {
-                    gmx_finalize();
-                }
-                exit(0);
-            }
-        }*/
-
-        GMX_MPE_LOG(ev_timestep2);
-
-        /* We write a checkpoint at this MD step when:
-         * either at an NS step when we signalled through gs,
-         * or at the last step (but not when we do not want confout),
-         * but never at the first step or with rerun.
-         */
-/*        bCPT = (((gs.set[eglsCHKPT] && bNS) ||
-                 (bLastStep && (Flags & MD_CONFOUT))) &&
-                step > ir->init_step && !bRerunMD);
-        if (bCPT)
-        {
-            gs.set[eglsCHKPT] = 0;
-        }*/
-
-        /* Determine the energy and pressure:
-         * at nstcalcenergy steps and at energy output steps (set below).
-         */
-        bNstEner = (bGStatEveryStep || do_per_step(step,ir->nstcalcenergy));
-        bCalcEnerPres = bNstEner;
-
-        /* Do we need global communication ? */
-        bGStat = (bCalcEnerPres || bStopCM ||
-                  (ir->nstlist == -1 && !bRerunMD && step >= nlh.step_nscheck));
-
-        do_ene = (do_per_step(step,ir->nstenergy) || bLastStep);
-
-        if (do_ene || do_log)
-        {
-            bCalcEnerPres = TRUE;
-            bGStat    = TRUE;
-        }
-
-        /* these CGLO_ options remain the same throughout the iteration */
-        cglo_flags = ((bRerunMD ? CGLO_RERUNMD : 0) |
-                      (bStopCM ? CGLO_STOPCM : 0) |
-                      (bGStat ? CGLO_GSTAT : 0)
-            );
-
-        force_flags = (GMX_FORCE_STATECHANGED |
-                       ((DYNAMIC_BOX(*ir) || bRerunMD) ? GMX_FORCE_DYNAMICBOX : 0) |
-                       GMX_FORCE_ALLFORCES |
-                       (bNStList ? GMX_FORCE_DOLR : 0) |
-                       GMX_FORCE_SEPLRF |
-                       (bCalcEnerPres ? GMX_FORCE_VIRIAL : 0) |
-                       (bDoDHDL ? GMX_FORCE_DHDL : 0)
-            );
-
-        if (shellfc)
-        {
-            /* Now is the time to relax the shells */
-            count=relax_shell_flexcon(fplog,cr,bVerbose,bFFscan ? step+1 : step,
-                                      ir,bNS,force_flags,
-                                      bStopCM,top,top_global,
-                                      constr,enerd,fcd,
-                                      state,f,force_vir,mdatoms,
-                                      nrnb,wcycle,graph,groups,
-                                      shellfc,fr,bBornRadii,t,mu_tot,
-                                      state->natoms,&bConverged,vsite,
-                                      outf->fp_field);
-            tcount+=count;
-
-            if (bConverged)
-            {
-                nconverged++;
-            }
-        }
-        else
-        {
-            /* The coordinates (x) are shifted (to get whole molecules)
-             * in do_force.
-             * This is parallellized as well, and does communication too.
-             * Check comments in sim_util.c
-             */
-
-            do_force(fplog,cr,ir,step,nrnb,wcycle,top,top_global,groups,
-                     state->box,state->x,&state->hist,
-                     f,force_vir,mdatoms,enerd,fcd,
-                     state->lambda,graph,
-                     fr,vsite,mu_tot,t,outf->fp_field,ed,bBornRadii,
-                     (bNS ? GMX_FORCE_NS : 0) | force_flags);
-        }
-
-        GMX_BARRIER(cr->mpi_comm_mygroup);
-
- /*       if (bTCR)
-        {
-            mu_aver = calc_mu_aver(cr,state->x,mdatoms->chargeA,
-                                   mu_tot,&top_global->mols,mdatoms,gnx,grpindex);
-        }
-
-        if (bTCR && bFirstStep)
-        {
-            tcr=init_coupling(fplog,nfile,fnm,cr,fr,mdatoms,&(top->idef));
-            fprintf(fplog,"Done init_coupling\n");
-            fflush(fplog);
-        }*/
-
-        /*  ############### START FIRST UPDATE HALF-STEP ############### */
-
-        if (bVV && !bStartingFromCpt && !bRerunMD)
-        {
-            if (ir->eI == eiVV)
-            {
-                if (bInitStep)
-                {
-                    /* if using velocity verlet with full time step Ekin,
-                     * take the first half step only to compute the
-                     * virial for the first step. From there,
-                     * revert back to the initial coordinates
-                     * so that the input is actually the initial step.
-                     */
-                    copy_rvecn(state->v,cbuf,0,state->natoms); /* should make this better for parallelizing? */
-                }
-
-                /* this is for NHC in the Ekin(t+dt/2) version of vv */
-                if (!bInitStep)
-                {
-                 trotter_update(ir,step,ekind,enerd,state,total_vir,mdatoms,&MassQ,trotter_seq,ettTSEQ2);
-                }
-
-               if (ir->eI == eiVVAK)
-               {
-                 update_tcouple(fplog,step,ir,state,ekind,wcycle,upd,&MassQ,mdatoms);
-               }
-
-                update_coords(fplog,step,ir,mdatoms,state,
-                              f,fr->bTwinRange && bNStList,fr->f_twin,fcd,
-                              ekind,M,wcycle,upd,bInitStep,etrtVELOCITY1,
-                              cr,nrnb,constr,&top->idef);
-
-                if (bIterations)
-                {
-                    gmx_iterate_init(&iterate,bIterations && !bInitStep);
-                }
-                /* for iterations, we save these vectors, as we will be self-consistently iterating
-                   the calculations */
-                /*#### UPDATE EXTENDED VARIABLES IN TROTTER FORMULATION */
-
-                /* save the state */
-                if (bIterations && iterate.bIterate) {
-                    copy_coupling_state(state,bufstate,ekind,ekind_save,&(ir->opts));
-                }
-            }
-
-            bFirstIterate = TRUE;
-            while (bFirstIterate || (bIterations && iterate.bIterate))
-            {
-                if (bIterations && iterate.bIterate)
-                {
-                    copy_coupling_state(bufstate,state,ekind_save,ekind,&(ir->opts));
-                    if (bFirstIterate && bTrotter)
-                    {
-                        /* The first time through, we need a decent first estimate
-                           of veta(t+dt) to compute the constraints.  Do
-                           this by computing the box volume part of the
-                           trotter integration at this time. Nothing else
-                           should be changed by this routine here.  If
-                           !(first time), we start with the previous value
-                           of veta.  */
-
-                        veta_save = state->veta;
-                        trotter_update(ir,step,ekind,enerd,state,total_vir,mdatoms,&MassQ,trotter_seq,ettTSEQ0);
-                        vetanew = state->veta;
-                        state->veta = veta_save;
-                    }
-                }
-
-                bOK = TRUE;
-                if ( !bRerunMD || rerun_fr.bV || bForceUpdate) {  /* Why is rerun_fr.bV here?  Unclear. */
-                    dvdl = 0;
-
-                    update_constraints(fplog,step,&dvdl,ir,ekind,mdatoms,state,graph,f,
-                                       &top->idef,shake_vir,NULL,
-                                       cr,nrnb,wcycle,upd,constr,
-                                       bInitStep,TRUE,bCalcEnerPres,vetanew);
-
-                    if (!bOK && !bFFscan)
-                    {
-                        gmx_fatal(FARGS,"Constraint error: Shake, Lincs or Settle could not solve the constrains");
-                    }
-
-                }
-                else if (graph)
-                { /* Need to unshift here if a do_force has been
-                     called in the previous step */
-                    unshift_self(graph,state->box,state->x);
-                }
-
-
-                if (bVV) {
-                    /* if VV, compute the pressure and constraints */
-                    /* if VV2, the pressure and constraints only if using pressure control.*/
-                    bPres = (ir->eI==eiVV || IR_NPT_TROTTER(ir));
-                    bTemp = ((ir->eI==eiVV &&(!bInitStep)) || (ir->eI==eiVVAK && IR_NPT_TROTTER(ir)));
-                    compute_globals(fplog,gstat,cr,ir,fr,ekind,state,state_global,mdatoms,nrnb,vcm,
-                                    wcycle,enerd,force_vir,shake_vir,total_vir,pres,mu_tot,
-                                    constr,NULL,FALSE,state->box,
-                                    top_global,&pcurr,top_global->natoms,&bSumEkinhOld,
-                                    cglo_flags
-                                    | CGLO_ENERGY
-                                    | (bTemp ? CGLO_TEMPERATURE:0)
-                                    | (bPres ? CGLO_PRESSURE : 0)
-                                    | (bPres ? CGLO_CONSTRAINT : 0)
-                                    | (iterate.bIterate ? CGLO_ITERATE : 0)
-                                    | (bFirstIterate ? CGLO_FIRSTITERATE : 0)
-                                    | CGLO_SCALEEKIN
-                        );
-                }
-                /* explanation of above:
-                   a) We compute Ekin at the full time step
-                   if 1) we are using the AveVel Ekin, and it's not the
-                   initial step, or 2) if we are using AveEkin, but need the full
-                   time step kinetic energy for the pressure.
-                   b) If we are using EkinAveEkin for the kinetic energy for the temperture control, we still feed in
-                   EkinAveVel because it's needed for the pressure */
-
-                /* temperature scaling and pressure scaling to produce the extended variables at t+dt */
-                if (bVV && !bInitStep)
-                {
-                 trotter_update(ir,step,ekind,enerd,state,total_vir,mdatoms,&MassQ, trotter_seq,ettTSEQ2);
-                }
-
-                if (bIterations &&
-                    done_iterating(cr,fplog,step,&iterate,bFirstIterate,
-                                   state->veta,&vetanew))
-                {
-                    break;
-                }
-                bFirstIterate = FALSE;
-            }
-
-            if (bTrotter && !bInitStep) {
-                copy_mat(shake_vir,state->svir_prev);
-                copy_mat(force_vir,state->fvir_prev);
-                if (IR_NVT_TROTTER(ir) && ir->eI==eiVV) {
-                    /* update temperature and kinetic energy now that step is over - this is the v(t+dt) point */
-                    enerd->term[F_TEMP] = sum_ekin(&(ir->opts),ekind,NULL,(ir->eI==eiVV),FALSE,FALSE);
-                    enerd->term[F_EKIN] = trace(ekind->ekin);
-                }
-            }
-            /* if it's the initial step, we performed this first step just to get the constraint virial */
-            if (bInitStep && ir->eI==eiVV) {
-                copy_rvecn(cbuf,state->v,0,state->natoms);
-            }
-
-            if (fr->bSepDVDL && fplog && do_log)
-            {
-                fprintf(fplog,sepdvdlformat,"Constraint",0.0,dvdl);
-            }
-            enerd->term[F_DHDL_CON] += dvdl;
-
-            GMX_MPE_LOG(ev_timestep1);
-
-        }
-
-        /* MRS -- now done iterating -- compute the conserved quantity */
-        if (bVV) {
-            last_conserved = 0;
-            if (IR_NVT_TROTTER(ir) || IR_NPT_TROTTER(ir))
-            {
-                last_conserved =
-                    NPT_energy(ir,state,&MassQ);
-                if ((ir->eDispCorr != edispcEnerPres) && (ir->eDispCorr != edispcAllEnerPres))
-                {
-                    last_conserved -= enerd->term[F_DISPCORR];
-                }
-            }
-            if (ir->eI==eiVV) {
-                last_ekin = enerd->term[F_EKIN]; /* does this get preserved through checkpointing? */
-            }
-        }
-
-        /* ########  END FIRST UPDATE STEP  ############## */
-        /* ########  If doing VV, we now have v(dt) ###### */
-
-        /* ################## START TRAJECTORY OUTPUT ################# */
-
-        /* 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; };*/
-
-#ifdef GMX_FAHCORE
-        if (MASTER(cr))
-            fcReportProgress( ir->nsteps, step );
-
-        if (bLastStep)
-        {
-            /* Enforce writing positions and velocities at end of run */
-            mdof_flags |= (MDOF_X | MDOF_V);
-        }
-            /* sync bCPT and fc record-keeping */
-/*            if (bCPT && MASTER(cr))
-                fcRequestCheckPoint();*/
-#endif
-
-        if (mdof_flags != 0)
-        {
-            wallcycle_start(wcycle,ewcTRAJ);
-/*            if (bCPT)
-            {
-                if (state->flags & (1<<estLD_RNG))
-                {
-                    get_stochd_state(upd,state);
-                }
-                if (MASTER(cr))
-                {
-                    if (bSumEkinhOld)
-                    {
-                        state_global->ekinstate.bUpToDate = FALSE;
-                    }
-                    else
-                    {
-                        update_ekinstate(&state_global->ekinstate,ekind);
-                        state_global->ekinstate.bUpToDate = TRUE;
-                    }
-                    update_energyhistory(&state_global->enerhist,mdebin);
-                }
-            }*/
-            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) &&
-                !bRerunMD && !bFFscan)
-            {
-                /* 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 &&
-                    DOMAINDECOMP(cr))
-                {
-                    /* 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);
-
-        /* kludge -- virial is lost with restart for NPT control. Must restart */
-        if (bStartingFromCpt && bVV)
-        {
-            copy_mat(state->svir_prev,shake_vir);
-            copy_mat(state->fvir_prev,force_vir);
-        }
-        /*  ################## END TRAJECTORY OUTPUT ################ */
-
-        /* Determine the pressure:
-         * always when we want exact averages in the energy file,
-         * at ns steps when we have pressure coupling,
-         * otherwise only at energy output steps (set below).
-         */
-
-        bNstEner = (bGStatEveryStep || do_per_step(step,ir->nstcalcenergy));
-        bCalcEnerPres = bNstEner;
-
-        /* Do we need global communication ? */
-        bGStat = (bGStatEveryStep || bStopCM || bNS ||
-                  (ir->nstlist == -1 && !bRerunMD && step >= nlh.step_nscheck));
-
-        do_ene = (do_per_step(step,ir->nstenergy) || bLastStep);
-
-        if (do_ene || do_log)
-        {
-            bCalcEnerPres = TRUE;
-            bGStat        = TRUE;
-        }
-
-        /* 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_THREADS
-           && 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 */
-            if ( gmx_get_stop_condition() == gmx_stop_cond_next_ns )
-                gs.sig[eglsSTOPCOND]=1;
-            if ( gmx_get_stop_condition() == gmx_stop_cond_next )
-                gs.sig[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) && (bNS || ir->nstlist <= 0) &&
-                 (max_hours > 0 && run_time > max_hours*60.0*60.0*0.99) &&
-                 gs.sig[eglsSTOPCOND] == 0 && gs.set[eglsSTOPCOND] == 0)
-        {
-            /* Signal to terminate the run */
-            gs.sig[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);
-        }
-
-        if (bResetCountersHalfMaxH && MASTER(cr) &&
-            run_time > max_hours*60.0*60.0*0.495)
-        {
-            gs.sig[eglsRESETCOUNTERS] = 1;
-        }
-
-        if (ir->nstlist == -1 && !bRerunMD)
-        {
-            /* When bGStatEveryStep=FALSE, global_stat is only called
-             * when we check the atom displacements, not at NS steps.
-             * This means that also the bonded interaction count check is not
-             * performed immediately after NS. Therefore a few MD steps could
-             * be performed with missing interactions.
-             * But wrong energies are never written to file,
-             * since energies are only written after global_stat
-             * has been called.
-             */
-            if (step >= nlh.step_nscheck)
-            {
-                nlh.nabnsb = natoms_beyond_ns_buffer(ir,fr,&top->cgs,
-                                                     nlh.scale_tot,state->x);
-            }
-            else
-            {
-                /* This is not necessarily true,
-                 * but step_nscheck is determined quite conservatively.
-                 */
-                nlh.nabnsb = 0;
-            }
-        }
-
-        /* In parallel we only have to check for checkpointing in steps
-         * where we do global communication,
-         *  otherwise the other nodes don't know.
-         */
-        if (MASTER(cr) && ((bGStat || !PAR(cr)) &&
-                           cpt_period >= 0 &&
-                           (cpt_period == 0 ||
-                            run_time >= nchkpt*cpt_period*60.0)) &&
-            gs.set[eglsCHKPT] == 0)
-        {
-            gs.sig[eglsCHKPT] = 1;
-        }
-
-        if (bIterations)
-        {
-            gmx_iterate_init(&iterate,bIterations);
-        }
-
-        /* for iterations, we save these vectors, as we will be redoing the calculations */
-        if (bIterations && iterate.bIterate)
-        {
-            copy_coupling_state(state,bufstate,ekind,ekind_save,&(ir->opts));
-        }
-        bFirstIterate = TRUE;
-        while (bFirstIterate || (bIterations && iterate.bIterate))
-        {
-            /* We now restore these vectors to redo the calculation with improved extended variables */
-            if (bIterations)
-            {
-                copy_coupling_state(bufstate,state,ekind_save,ekind,&(ir->opts));
-            }
-
-            /* We make the decision to break or not -after- the calculation of Ekin and Pressure,
-               so scroll down for that logic */
-
-            /* #########   START SECOND UPDATE STEP ################# */
-            GMX_MPE_LOG(ev_update_start);
-            bOK = TRUE;
-            if (!bRerunMD || rerun_fr.bV || bForceUpdate)
-            {
-                wallcycle_start(wcycle,ewcUPDATE);
-                dvdl = 0;
-                /* Box is changed in update() when we do pressure coupling,
-                 * but we should still use the old box for energy corrections and when
-                 * writing it to the energy file, so it matches the trajectory files for
-                 * the same timestep above. Make a copy in a separate array.
-                 */
-                copy_mat(state->box,lastbox);
-                /* UPDATE PRESSURE VARIABLES IN TROTTER FORMULATION WITH CONSTRAINTS */
-                if (bTrotter)
-                {
-                    if (bIterations && iterate.bIterate)
-                    {
-                        if (bFirstIterate)
-                        {
-                            scalevir = 1;
-                        }
-                        else
-                        {
-                            /* we use a new value of scalevir to converge the iterations faster */
-                            scalevir = tracevir/trace(shake_vir);
-                        }
-                        msmul(shake_vir,scalevir,shake_vir);
-                        m_add(force_vir,shake_vir,total_vir);
-                        clear_mat(shake_vir);
-                    }
-                    trotter_update(ir,step,ekind,enerd,state,total_vir,mdatoms,&MassQ, trotter_seq,ettTSEQ3);
-                }
-                /* We can only do Berendsen coupling after we have summed
-                 * the kinetic energy or virial. Since the happens
-                 * in global_state after update, we should only do it at
-                 * step % nstlist = 1 with bGStatEveryStep=FALSE.
-                 */
-
-               if (ir->eI != eiVVAK)
-                {
-                 update_tcouple(fplog,step,ir,state,ekind,wcycle,upd,&MassQ,mdatoms);
-                }
-                update_pcouple(fplog,step,ir,state,pcoupl_mu,M,wcycle,
-                                upd,bInitStep);
-
-               if (bVV)
-               {
-                   /* velocity half-step update */
-                   update_coords(fplog,step,ir,mdatoms,state,f,fr->bTwinRange && bNStList,fr->f_twin,fcd,
-                                 ekind,M,wcycle,upd,FALSE,etrtVELOCITY2,cr,nrnb,constr,&top->idef);
-               }
-
-                /* Above, initialize just copies ekinh into ekin,
-                 * it doesn't copy position (for VV),
-                 * and entire integrator for MD.
-                 */
-
-                if (ir->eI==eiVVAK)
-                {
-                    copy_rvecn(state->x,cbuf,0,state->natoms);
-                }
-
-                update_coords(fplog,step,ir,mdatoms,state,f,fr->bTwinRange && bNStList,fr->f_twin,fcd,
-                              ekind,M,wcycle,upd,bInitStep,etrtPOSITION,cr,nrnb,constr,&top->idef);
-                wallcycle_stop(wcycle,ewcUPDATE);
-
-                update_constraints(fplog,step,&dvdl,ir,ekind,mdatoms,state,graph,f,
-                                   &top->idef,shake_vir,force_vir,
-                                   cr,nrnb,wcycle,upd,constr,
-                                   bInitStep,FALSE,bCalcEnerPres,state->veta);
-
-                if (ir->eI==eiVVAK)
-                {
-                    /* erase F_EKIN and F_TEMP here? */
-                    /* just compute the kinetic energy at the half step to perform a trotter step */
-                    compute_globals(fplog,gstat,cr,ir,fr,ekind,state,state_global,mdatoms,nrnb,vcm,
-                                    wcycle,enerd,force_vir,shake_vir,total_vir,pres,mu_tot,
-                                    constr,NULL,FALSE,lastbox,
-                                    top_global,&pcurr,top_global->natoms,&bSumEkinhOld,
-                                    cglo_flags | CGLO_TEMPERATURE | CGLO_CONSTRAINT
-                        );
-                    wallcycle_start(wcycle,ewcUPDATE);
-                    trotter_update(ir,step,ekind,enerd,state,total_vir,mdatoms,&MassQ, trotter_seq,ettTSEQ4);
-                    /* now we know the scaling, we can compute the positions again again */
-                    copy_rvecn(cbuf,state->x,0,state->natoms);
-
-                    update_coords(fplog,step,ir,mdatoms,state,f,fr->bTwinRange && bNStList,fr->f_twin,fcd,
-                                  ekind,M,wcycle,upd,bInitStep,etrtPOSITION,cr,nrnb,constr,&top->idef);
-                    wallcycle_stop(wcycle,ewcUPDATE);
-
-                    /* do we need an extra constraint here? just need to copy out of state->v to upd->xp? */
-                    /* are the small terms in the shake_vir here due
-                     * to numerical errors, or are they important
-                     * physically? I'm thinking they are just errors, but not completely sure.
-                     * For now, will call without actually constraining, constr=NULL*/
-                    update_constraints(fplog,step,&dvdl,ir,ekind,mdatoms,state,graph,f,
-                                       &top->idef,tmp_vir,force_vir,
-                                       cr,nrnb,wcycle,upd,NULL,
-                                       bInitStep,FALSE,bCalcEnerPres,state->veta);
-                }
-                if (!bOK && !bFFscan)
-                {
-                    gmx_fatal(FARGS,"Constraint error: Shake, Lincs or Settle could not solve the constrains");
-                }
-
-                if (fr->bSepDVDL && fplog && do_log)
-                {
-                    fprintf(fplog,sepdvdlformat,"Constraint",0.0,dvdl);
-                }
-                enerd->term[F_DHDL_CON] += dvdl;
-            }
-            else if (graph)
-            {
-                /* Need to unshift here */
-                unshift_self(graph,state->box,state->x);
-            }
-
-            GMX_BARRIER(cr->mpi_comm_mygroup);
-            GMX_MPE_LOG(ev_update_finish);
-
-            if (vsite != NULL)
-            {
-                wallcycle_start(wcycle,ewcVSITECONSTR);
-                if (graph != NULL)
-                {
-                    shift_self(graph,state->box,state->x);
-                }
-                construct_vsites(fplog,vsite,state->x,nrnb,ir->delta_t,state->v,
-                                 top->idef.iparams,top->idef.il,
-                                 fr->ePBC,fr->bMolPBC,graph,cr,state->box);
-
-                if (graph != NULL)
-                {
-                    unshift_self(graph,state->box,state->x);
-                }
-                wallcycle_stop(wcycle,ewcVSITECONSTR);
-            }
-
-            /* ############## IF NOT VV, Calculate globals HERE, also iterate constraints ############ */
-            if (ir->nstlist == -1 && bFirstIterate)
-            {
-                gs.sig[eglsNABNSB] = nlh.nabnsb;
-            }
-            compute_globals(fplog,gstat,cr,ir,fr,ekind,state,state_global,mdatoms,nrnb,vcm,
-                            wcycle,enerd,force_vir,shake_vir,total_vir,pres,mu_tot,
-                            constr,
-                            bFirstIterate ? &gs : NULL,(step % gs.nstms == 0),
-                            lastbox,
-                            top_global,&pcurr,top_global->natoms,&bSumEkinhOld,
-                            cglo_flags
-                            | (!EI_VV(ir->eI) ? CGLO_ENERGY : 0)
-                            | (!EI_VV(ir->eI) ? CGLO_TEMPERATURE : 0)
-                            | (!EI_VV(ir->eI) || bRerunMD ? CGLO_PRESSURE : 0)
-                            | (bIterations && iterate.bIterate ? CGLO_ITERATE : 0)
-                            | (bFirstIterate ? CGLO_FIRSTITERATE : 0)
-                            | CGLO_CONSTRAINT
-                );
-            if (ir->nstlist == -1 && bFirstIterate)
-            {
-                nlh.nabnsb = gs.set[eglsNABNSB];
-                gs.set[eglsNABNSB] = 0;
-            }
-            /* bIterate is set to keep it from eliminating the old ekin kinetic energy terms */
-            /* #############  END CALC EKIN AND PRESSURE ################# */
-
-            /* Note: this is OK, but there are some numerical precision issues with using the convergence of
-               the virial that should probably be addressed eventually. state->veta has better properies,
-               but what we actually need entering the new cycle is the new shake_vir value. Ideally, we could
-               generate the new shake_vir, but test the veta value for convergence.  This will take some thought. */
-
-            if (bIterations &&
-                done_iterating(cr,fplog,step,&iterate,bFirstIterate,
-                               trace(shake_vir),&tracevir))
-            {
-                break;
-            }
-            bFirstIterate = FALSE;
-        }
-
-        update_box(fplog,step,ir,mdatoms,state,graph,f,
-                   ir->nstlist==-1 ? &nlh.scale_tot : NULL,pcoupl_mu,nrnb,wcycle,upd,bInitStep,FALSE);
-
-        /* ################# END UPDATE STEP 2 ################# */
-        /* #### We now have r(t+dt) and v(t+dt/2)  ############# */
-
-        /* The coordinates (x) were unshifted in update */
-/*        if (bFFscan && (shellfc==NULL || bConverged))
-        {
-            if (print_forcefield(fplog,enerd->term,mdatoms->homenr,
-                                 f,NULL,xcopy,
-                                 &(top_global->mols),mdatoms->massT,pres))
-            {
-                if (gmx_parallel_env_initialized())
-                {
-                    gmx_finalize();
-                }
-                fprintf(stderr,"\n");
-                exit(0);
-            }
-        }*/
-        if (!bGStat)
-        {
-            /* We will not sum ekinh_old,
-             * so signal that we still have to do it.
-             */
-            bSumEkinhOld = TRUE;
-        }
-
-/*        if (bTCR)
-        {*/
-            /* Only do GCT when the relaxation of shells (minimization) has converged,
-             * otherwise we might be coupling to bogus energies.
-             * In parallel we must always do this, because the other sims might
-             * update the FF.
-             */
-
-            /* Since this is called with the new coordinates state->x, I assume
-             * we want the new box state->box too. / EL 20040121
-             */
-/*            do_coupling(fplog,oenv,nfile,fnm,tcr,t,step,enerd->term,fr,
-                        ir,MASTER(cr),
-                        mdatoms,&(top->idef),mu_aver,
-                        top_global->mols.nr,cr,
-                        state->box,total_vir,pres,
-                        mu_tot,state->x,f,bConverged);
-            debug_gmx();
-        }*/
-
-        /* #########  BEGIN PREPARING EDR OUTPUT  ###########  */
-
-        sum_dhdl(enerd,state->lambda,ir);
-        /* use the directly determined last velocity, not actually the averaged half steps */
-        if (bTrotter && ir->eI==eiVV)
-        {
-            enerd->term[F_EKIN] = last_ekin;
-        }
-        enerd->term[F_ETOT] = enerd->term[F_EPOT] + enerd->term[F_EKIN];
-
-        switch (ir->etc)
-        {
-        case etcNO:
-            break;
-        case etcBERENDSEN:
-            break;
-        case etcNOSEHOOVER:
-            if (IR_NVT_TROTTER(ir)) {
-                enerd->term[F_ECONSERVED] = enerd->term[F_ETOT] + last_conserved;
-            } else {
-                enerd->term[F_ECONSERVED] = enerd->term[F_ETOT] +
-                    NPT_energy(ir,state,&MassQ);
-            }
-            break;
-        case etcVRESCALE:
-            enerd->term[F_ECONSERVED] =
-                enerd->term[F_ETOT] + vrescale_energy(&(ir->opts),
-                                                      state->therm_integral);
-            break;
-        default:
-            break;
-        }
-
-        /* Check for excessively large energies */
-/*        if (bIonize)
-        {
-#ifdef GMX_DOUBLE
-            real etot_max = 1e200;
-#else
-            real etot_max = 1e30;
-#endif
-            if (fabs(enerd->term[F_ETOT]) > etot_max)
-            {
-                fprintf(stderr,"Energy too large (%g), giving up\n",
-                        enerd->term[F_ETOT]);
-            }
-        }*/
-        /* #########  END PREPARING EDR OUTPUT  ###########  */
-
-        /* Time for performance */
-        if (((step % stepout) == 0) || bLastStep)
-        {
-            runtime_upd_proc(runtime);
-        }
-
-        /* Output stuff */
-        if (MASTER(cr))
-        {
-            gmx_bool do_dr,do_or;
-
-            if (!(bStartingFromCpt && (EI_VV(ir->eI))))
-            {
-                if (bNstEner)
-                {
-                    upd_mdebin(mdebin,bDoDHDL,TRUE,
-                               t,mdatoms->tmass,enerd,state,lastbox,
-                               shake_vir,force_vir,total_vir,pres,
-                               ekind,mu_tot,constr);
-                }
-                else
-                {
-                    upd_mdebin_step(mdebin);
-                }
-
-                do_dr  = do_per_step(step,ir->nstdisreout);
-                do_or  = do_per_step(step,ir->nstorireout);
-
-                print_ebin(outf->fp_ene,do_ene,do_dr,do_or,do_log?fplog:NULL,
-                           step,t,
-                           eprNORMAL,bCompact,mdebin,fcd,groups,&(ir->opts));
-            }
-            if (ir->ePull != epullNO)
-            {
-                pull_print_output(ir->pull,step,t);
-            }
-
-            if (do_per_step(step,ir->nstlog))
-            {
-                if(fflush(fplog) != 0)
-                {
-                    gmx_fatal(FARGS,"Cannot flush logfile - maybe you are out of quota?");
-                }
-            }
-        }
-
-
-        /* Remaining runtime */
-        if (MULTIMASTER(cr) && (do_verbose || gmx_got_usr_signal() ))
-        {
-            if (shellfc)
-            {
-                fprintf(stderr,"\n");
-            }
-            print_time(stderr,runtime,step,ir,cr);
-        }
-
-               /* Set new positions for the group to embed */
-               if(!bLastStep){
-                       if(step_rel<=it_xy)
-                       {
-                               fac[0]+=xy_step;
-                               fac[1]+=xy_step;
-                       } else if (step_rel<=(it_xy+it_z))
-                       {
-                               fac[2]+=z_step;
-                       }
-                       resize(ins_at,r_ins,state_global->x,pos_ins,fac);
-               }
-
-        /* Replica exchange */
-/*        bExchanged = FALSE;
-        if ((repl_ex_nst > 0) && (step > 0) && !bLastStep &&
-            do_per_step(step,repl_ex_nst))
-        {
-            bExchanged = replica_exchange(fplog,cr,repl_ex,
-                                          state_global,enerd->term,
-                                          state,step,t);
-        }
-        if (bExchanged && PAR(cr))
-        {
-            if (DOMAINDECOMP(cr))
-            {
-                dd_partition_system(fplog,step,cr,TRUE,1,
-                                    state_global,top_global,ir,
-                                    state,&f,mdatoms,top,fr,
-                                    vsite,shellfc,constr,
-                                    nrnb,wcycle,FALSE);
-            }
-            else
-            {
-                bcast_state(cr,state,FALSE);
-            }
-        }*/
-
-        bFirstStep = FALSE;
-        bInitStep = FALSE;
-        bStartingFromCpt = FALSE;
-
-        /* #######  SET VARIABLES FOR NEXT ITERATION IF THEY STILL NEED IT ###### */
-       /* With all integrators, except VV, we need to retain the pressure
-         * at the current step for coupling at the next step.
-         */
-        if ((state->flags & (1<<estPRES_PREV)) &&
-            (bGStatEveryStep ||
-             (ir->nstpcouple > 0 && step % ir->nstpcouple == 0)))
-        {
-            /* Store the pressure in t_state for pressure coupling
-             * at the next MD step.
-             */
-            copy_mat(pres,state->pres_prev);
-        }
-
-        /* #######  END SET VARIABLES FOR NEXT ITERATION ###### */
-
-        if (bRerunMD)
-        {
-            /* read next frame from input trajectory */
-            bNotLastFrame = read_next_frame(oenv,status,&rerun_fr);
-        }
-
-        if (!bRerunMD || !rerun_fr.bStep)
-        {
-            /* increase the MD step number */
-            step++;
-            step_rel++;
-        }
-
-        cycles = wallcycle_stop(wcycle,ewcSTEP);
-        if (DOMAINDECOMP(cr) && wcycle)
-        {
-            dd_cycles_add(cr->dd,cycles,ddCyclStep);
-        }
-
-        if (step_rel == wcycle_get_reset_counters(wcycle) ||
-            gs.set[eglsRESETCOUNTERS] != 0)
-        {
-            /* Reset all the counters related to performance over the run */
-            reset_all_counters(fplog,cr,step,&step_rel,ir,wcycle,nrnb,runtime);
-            wcycle_set_reset_counters(wcycle,-1);
-            bResetCountersHalfMaxH = FALSE;
-            gs.set[eglsRESETCOUNTERS] = 0;
-        }
-    }
-    /* End of main MD loop */
-    debug_gmx();
-    write_sto_conf_mtop(ftp2fn(efSTO,nfile,fnm),
-                                        *top_global->name,top_global,
-                                        state_global->x,state_global->v,
-                                        ir->ePBC,state->box);
-
-    /* Stop the time */
-    runtime_end(runtime);
-
-    if (bRerunMD)
-    {
-        close_trj(status);
-    }
-
-    if (!(cr->duty & DUTY_PME))
-    {
-        /* Tell the PME only node to finish */
-        gmx_pme_finish(cr);
-    }
-
-    if (MASTER(cr))
-    {
-        if (ir->nstcalcenergy > 0 && !bRerunMD)
-        {
-            print_ebin(outf->fp_ene,FALSE,FALSE,FALSE,fplog,step,t,
-                       eprAVER,FALSE,mdebin,fcd,groups,&(ir->opts));
-        }
-    }
-
-    done_mdoutf(outf);
-
-    debug_gmx();
-
-    if (ir->nstlist == -1 && nlh.nns > 0 && fplog)
-    {
-        fprintf(fplog,"Average neighborlist lifetime: %.1f steps, std.dev.: %.1f steps\n",nlh.s1/nlh.nns,sqrt(nlh.s2/nlh.nns - sqr(nlh.s1/nlh.nns)));
-        fprintf(fplog,"Average number of atoms that crossed the half buffer length: %.1f\n\n",nlh.ab/nlh.nns);
-    }
-
-    if (shellfc && fplog)
-    {
-        fprintf(fplog,"Fraction of iterations that converged:           %.2f %%\n",
-                (nconverged*100.0)/step_rel);
-        fprintf(fplog,"Average number of force evaluations per MD step: %.2f\n\n",
-                tcount/step_rel);
-    }
-
-/*    if (repl_ex_nst > 0 && MASTER(cr))
-    {
-        print_replica_exchange_statistics(fplog,repl_ex);
-    }*/
-
-    runtime->nsteps_done = step_rel;
-
-    return 0;
-}
-
-
-int mdrunner_membed(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,
-             int nstepout,int resetstep,int nmultisim,int repl_ex_nst,int repl_ex_seed,
-             real pforce,real cpt_period,real max_hours,
-             const char *deviceOptions,
-             unsigned long Flags,
-             real xy_fac, real xy_max, real z_fac, real z_max,
-             int it_xy, int it_z, real probe_rad, int low_up_rm,
-             int pieces, gmx_bool bALLOW_ASYMMETRY, int maxwarn)
-{
-    double     nodetime=0,realtime;
-    t_inputrec *inputrec;
-    t_state    *state=NULL;
-    matrix     box;
-    gmx_ddbox_t ddbox;
-    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=1,nthreads_requested=1;
-
-
-       char                    *ins;
-       int                     rm_bonded_at,fr_id,fr_i=0,tmp_id,warn=0;
-       int                     ng,j,max_lip_rm,ins_grp_id,ins_nat,mem_nat,ntype,lip_rm,tpr_version;
-       real                    xy_step=0,z_step=0;
-       real                    prot_area;
-       rvec                    *r_ins=NULL,fac;
-       t_block                 *ins_at,*rest_at;
-       pos_ins_t               *pos_ins;
-       mem_t                   *mem_p;
-       rm_t                    *rm_p;
-       gmx_groups_t            *groups;
-       gmx_bool                        bExcl=FALSE;
-       t_atoms                 atoms;
-       t_pbc                   *pbc;
-       char                    **piecename=NULL;
-
-    /* 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 (bVerbose && SIMMASTER(cr))
-    {
-        fprintf(stderr,"Getting Loaded...\n");
-    }
-
-    if (Flags & MD_APPENDFILES)
-    {
-        fplog = NULL;
-    }
-
-    snew(state,1);
-    if (MASTER(cr))
-    {
-        /* Read (nearly) all data required for the simulation */
-        read_tpx_state(ftp2fn(efTPX,nfile,fnm),inputrec,state,NULL,mtop);
-
-        /* NOW the threads will be started: */
-#ifdef GMX_THREADS
-#endif
-    }
-    /* END OF CAUTION: cr is now reliable */
-
-    if (PAR(cr))
-    {
-        /* now broadcast everything to the non-master nodes/threads: */
-        init_parallel(fplog, cr, inputrec, mtop);
-    }
-    /* now make sure the state is initialized and propagated */
-    set_state_entries(state,inputrec,cr->nnodes);
-
-    if (can_use_allvsall(inputrec,mtop,TRUE,cr,fplog))
-    {
-        /* All-vs-all loops do not work with domain decomposition */
-        Flags |= MD_PARTDEC;
-    }
-
-    if (!EEL_PME(inputrec->coulombtype) || (Flags & MD_PARTDEC))
-    {
-        cr->npmenodes = 0;
-    }
-
-       snew(ins_at,1);
-       snew(pos_ins,1);
-       if(MASTER(cr))
-       {
-               tpr_version = get_tpr_version(ftp2fn(efTPX,nfile,fnm));
-               if (tpr_version<58)
-                       gmx_fatal(FARGS,"Version of *.tpr file to old (%d). Rerun grompp with gromacs VERSION 4.0.3 or newer.\n",tpr_version);
-
-               if( inputrec->eI != eiMD )
-                       gmx_input("Change integrator to md in mdp file.");
-
-               if(PAR(cr))
-                       gmx_input("Sorry, parallel g_membed is not yet fully functrional.");
-
-               groups=&(mtop->groups);
-
-               atoms=gmx_mtop_global_atoms(mtop);
-               snew(mem_p,1);
-               fprintf(stderr,"\nSelect a group to embed in the membrane:\n");
-               get_index(&atoms,ftp2fn_null(efNDX,nfile,fnm),1,&(ins_at->nr),&(ins_at->index),&ins);
-               ins_grp_id = search_string(ins,groups->ngrpname,(groups->grpname));
-               fprintf(stderr,"\nSelect a group to embed %s into (e.g. the membrane):\n",ins);
-               get_index(&atoms,ftp2fn_null(efNDX,nfile,fnm),1,&(mem_p->mem_at.nr),&(mem_p->mem_at.index),&(mem_p->name));
-
-               pos_ins->pieces=pieces;
-               snew(pos_ins->nidx,pieces);
-               snew(pos_ins->subindex,pieces);
-               snew(piecename,pieces); 
-               if (pieces>1)
-               {
-                       fprintf(stderr,"\nSelect pieces to embed:\n");
-                       get_index(&atoms,ftp2fn_null(efNDX,nfile,fnm),pieces,pos_ins->nidx,pos_ins->subindex,piecename);
-               }
-               else
-               {       
-                       /*use whole embedded group*/
-                       snew(pos_ins->nidx,1);
-                       snew(pos_ins->subindex,1);
-                       pos_ins->nidx[0]=ins_at->nr;
-                       pos_ins->subindex[0]=ins_at->index;
-               }
-
-               if(probe_rad<0.2199999)
-               {
-                       warn++;
-                       fprintf(stderr,"\nWarning %d:\nA probe radius (-rad) smaller than 0.2 can result in overlap between waters "
-                                       "and the group to embed, which will result in Lincs errors etc.\nIf you are sure, you can increase maxwarn.\n\n",warn);
-               }
-
-               if(xy_fac<0.09999999)
-               {
-                       warn++;
-                       fprintf(stderr,"\nWarning %d:\nThe initial size of %s is probably too smal.\n"
-                                       "If you are sure, you can increase maxwarn.\n\n",warn,ins);
-               }
-
-               if(it_xy<1000)
-               {
-                       warn++;
-                       fprintf(stderr,"\nWarning %d;\nThe number of steps used to grow the xy-coordinates of %s (%d) is probably too small.\n"
-                                       "Increase -nxy or, if you are sure, you can increase maxwarn.\n\n",warn,ins,it_xy);
-               }
-
-               if( (it_z<100) && ( z_fac<0.99999999 || z_fac>1.0000001) )
-                {
-                        warn++;
-                        fprintf(stderr,"\nWarning %d;\nThe number of steps used to grow the z-coordinate of %s (%d) is probably too small.\n"
-                                       "Increase -nz or, if you are sure, you can increase maxwarn.\n\n",warn,ins,it_z);
-                }
-
-               if(it_xy+it_z>inputrec->nsteps)
-               {
-                       warn++;
-                       fprintf(stderr,"\nWarning %d:\nThe number of growth steps (-nxy + -nz) is larger than the number of steps in the tpr.\n"
-                                       "If you are sure, you can increase maxwarn.\n\n",warn);
-               }
-
-               fr_id=-1;
-               if( inputrec->opts.ngfrz==1)
-                       gmx_fatal(FARGS,"You did not specify \"%s\" as a freezegroup.",ins);
-               for(i=0;i<inputrec->opts.ngfrz;i++)
-               {
-                       tmp_id = mtop->groups.grps[egcFREEZE].nm_ind[i];
-                       if(ins_grp_id==tmp_id)
-                       {
-                               fr_id=tmp_id;
-                               fr_i=i;
-                       }
-               }
-               if (fr_id == -1 )
-                       gmx_fatal(FARGS,"\"%s\" not as freezegroup defined in the mdp-file.",ins);
-
-               for(i=0;i<DIM;i++)
-                       if( inputrec->opts.nFreeze[fr_i][i] != 1)
-                               gmx_fatal(FARGS,"freeze dimensions for %s are not Y Y Y\n",ins);
-
-               ng = groups->grps[egcENER].nr;
-               if (ng == 1)
-                       gmx_input("No energy groups defined. This is necessary for energy exclusion in the freeze group");
-
-               for(i=0;i<ng;i++)
-               {
-                       for(j=0;j<ng;j++)
-                       {
-                               if (inputrec->opts.egp_flags[ng*i+j] == EGP_EXCL)
-                               {
-                                       bExcl = TRUE;
-                                       if ( (groups->grps[egcENER].nm_ind[i] != ins_grp_id) || (groups->grps[egcENER].nm_ind[j] != ins_grp_id) )
-                                               gmx_fatal(FARGS,"Energy exclusions \"%s\" and  \"%s\" do not match the group to embed \"%s\"",
-                                                               *groups->grpname[groups->grps[egcENER].nm_ind[i]],
-                                                               *groups->grpname[groups->grps[egcENER].nm_ind[j]],ins);
-                               }
-                       }
-               }
-               if (!bExcl)
-                       gmx_input("No energy exclusion groups defined. This is necessary for energy exclusion in the freeze group");
-
-               /* Set all atoms in box*/
-               /*set_inbox(state->natoms,state->x);*/
-
-               /* Guess the area the protein will occupy in the membrane plane  Calculate area per lipid*/
-               snew(rest_at,1);
-               ins_nat = init_ins_at(ins_at,rest_at,state,pos_ins,groups,ins_grp_id,xy_max);
-               /* Check moleculetypes in insertion group */
-               check_types(ins_at,rest_at,mtop);
-
-               mem_nat = init_mem_at(mem_p,mtop,state->x,state->box,pos_ins);
-
-               prot_area = est_prot_area(pos_ins,state->x,ins_at,mem_p);
-               if ( (prot_area>7.5) && ( (state->box[XX][XX]*state->box[YY][YY]-state->box[XX][YY]*state->box[YY][XX])<50) )
-               {
-                       warn++;
-                       fprintf(stderr,"\nWarning %d:\nThe xy-area is very small compared to the area of the protein.\n"
-                                       "This might cause pressure problems during the growth phase. Just try with\n"
-                                       "current setup (-maxwarn + 1), but if pressure problems occur, lower the\n"
-                                       "compressibility in the mdp-file or use no pressure coupling at all.\n\n",warn);
-               }
-               if(warn>maxwarn)
-                                       gmx_fatal(FARGS,"Too many warnings.\n");
-
-               printf("The estimated area of the protein in the membrane is %.3f nm^2\n",prot_area);
-               printf("\nThere are %d lipids in the membrane part that overlaps the protein.\nThe area per lipid is %.4f nm^2.\n",mem_p->nmol,mem_p->lip_area);
-
-               /* Maximum number of lipids to be removed*/
-               max_lip_rm=(int)(2*prot_area/mem_p->lip_area);
-               printf("Maximum number of lipids that will be removed is %d.\n",max_lip_rm);
-
-               printf("\nWill resize the protein by a factor of %.3f in the xy plane and %.3f in the z direction.\n"
-                               "This resizing will be done with respect to the geometrical center of all protein atoms\n"
-                               "that span the membrane region, i.e. z between %.3f and %.3f\n\n",xy_fac,z_fac,mem_p->zmin,mem_p->zmax);
-
-               /* resize the protein by xy and by z if necessary*/
-               snew(r_ins,ins_at->nr);
-               init_resize(ins_at,r_ins,pos_ins,mem_p,state->x,bALLOW_ASYMMETRY);
-               fac[0]=fac[1]=xy_fac;
-               fac[2]=z_fac;
-
-               xy_step =(xy_max-xy_fac)/(double)(it_xy);
-               z_step  =(z_max-z_fac)/(double)(it_z-1);
-
-               resize(ins_at,r_ins,state->x,pos_ins,fac);
-
-               /* remove overlapping lipids and water from the membrane box*/
-               /*mark molecules to be removed*/
-               snew(pbc,1);
-               set_pbc(pbc,inputrec->ePBC,state->box);
-
-               snew(rm_p,1);
-               lip_rm = gen_rm_list(rm_p,ins_at,rest_at,pbc,mtop,state->x, r_ins, mem_p,pos_ins,probe_rad,low_up_rm,bALLOW_ASYMMETRY);
-        lip_rm -= low_up_rm;
-
-               if(fplog)
-                       for(i=0;i<rm_p->nr;i++)
-                               fprintf(fplog,"rm mol %d\n",rm_p->mol[i]);
-
-               for(i=0;i<mtop->nmolblock;i++)
-               {
-                       ntype=0;
-                       for(j=0;j<rm_p->nr;j++)
-                               if(rm_p->block[j]==i)
-                                       ntype++;
-                       printf("Will remove %d %s molecules\n",ntype,*(mtop->moltype[mtop->molblock[i].type].name));
-               }
-
-               if(lip_rm>max_lip_rm)
-               {
-                       warn++;
-                       fprintf(stderr,"\nWarning %d:\nTrying to remove a larger lipid area than the estimated protein area\n"
-                                       "Try making the -xyinit resize factor smaller. If you are sure about this increase maxwarn.\n\n",warn);
-               }
-
-               /*remove all lipids and waters overlapping and update all important structures*/
-               rm_group(inputrec,groups,mtop,rm_p,state,ins_at,pos_ins);
-
-               rm_bonded_at = rm_bonded(ins_at,mtop);
-               if (rm_bonded_at != ins_at->nr)
-               {
-                       fprintf(stderr,"Warning: The number of atoms for which the bonded interactions are removed is %d, "
-                                       "while %d atoms are embedded. Make sure that the atoms to be embedded are not in the same"
-                                       "molecule type as atoms that are not to be embedded.\n",rm_bonded_at,ins_at->nr);
-               }
-
-               if(warn>maxwarn)
-                       gmx_fatal(FARGS,"Too many warnings.\nIf you are sure these warnings are harmless, you can increase -maxwarn");
-
-               if (MASTER(cr))
-               {
-                       if (ftp2bSet(efTOP,nfile,fnm))
-                               top_update(opt2fn("-p",nfile,fnm),ins,rm_p,mtop);
-               }
-
-               sfree(pbc);
-               sfree(rest_at);
-       }
-
-#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.
-         */
-/*        deform_init_init_step_tpx = inputrec->init_step;*/
-/*        copy_mat(box,deform_init_box_tpx);*/
-    }
-
-    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));
-
-            if (bReadRNG)
-            {
-                Flags |= MD_READ_RNG;
-            }
-            if (bReadEkin)
-            {
-                Flags |= MD_READ_EKIN;
-            }
-        }
-    }
-
-    if ((MASTER(cr) || (Flags & MD_SEPPOT)) && (Flags & MD_APPENDFILES))
-    {
-        gmx_log_open(ftp2fn(efLOG,nfile,fnm),cr,!(Flags & MD_SEPPOT),
-                             Flags,&fplog);
-    }
-
-    if (SIMMASTER(cr))
-    {
-        copy_mat(state->box,box);
-    }
-
-    if (PAR(cr))
-    {
-        gmx_bcast(sizeof(box),box,cr);
-    }
-
-    if (bVerbose && SIMMASTER(cr))
-    {
-        fprintf(stderr,"Loaded with Money\n\n");
-    }
-
-    if (PAR(cr) && !((Flags & MD_PARTDEC) || EI_TPI(inputrec->eI)))
-    {
-        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 = cr->nnodes;
-        npme_minor = 1;
-
-        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);
-    }
-
-    wcycle = wallcycle_init(fplog,resetstep,cr);
-    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))
-            {
-                if (!MASTER(cr))
-                {
-                    snew(state,1);
-                }
-                bcast_state(cr,state,TRUE);
-            }
-        }
-
-        /* Dihedral Restraints */
-        if (gmx_mtop_ftype_count(mtop,F_DIHRES) > 0)
-        {
-            init_dihres(fplog,mtop,inputrec,fcd);
-        }
-
-        /* Initiate forcerecord */
-        fr = mk_forcerec();
-        init_forcerec(fplog,oenv,fr,fcd,inputrec,mtop,cr,box,FALSE,
-                      opt2fn("-table",nfile,fnm),
-                      opt2fn("-tablep",nfile,fnm),
-                      opt2fn("-tableb",nfile,fnm),FALSE,pforce);
-
-        /* version for PCA_NOT_READ_NODE (see md.c) */
-        /*init_forcerec(fplog,fr,fcd,inputrec,mtop,cr,box,FALSE,
-          "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);
-
-        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);
-            }
-        }
-
-        /* Initiate PPPM if necessary */
-        if (fr->eeltype == eelPPPM)
-        {
-            if (mdatoms->nChargePerturbed)
-            {
-                gmx_fatal(FARGS,"Free energy with %s is not implemented",
-                          eel_names[fr->eeltype]);
-            }
-            status = gmx_pppm_init(fplog,cr,oenv,FALSE,TRUE,box,
-                                   getenv("GMXGHAT"),inputrec, (Flags & MD_REPRODUCIBLE));
-            if (status != 0)
-            {
-                gmx_fatal(FARGS,"Error %d initializing PPPM",status);
-            }
-        }
-
-        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);
-    }
-
-    /* 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));
-            if (status != 0)
-            {
-                gmx_fatal(FARGS,"Error %d initializing PME",status);
-            }
-        }
-    }
-
-
-/*    if (integrator[inputrec->eI].func == do_md
-#ifdef GMX_OPENMM
-        ||
-        integrator[inputrec->eI].func == do_md_openmm
-#endif
-        )
-    {*/
-        /* 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,
-                      EI_DYNAMICS(inputrec->eI) && MASTER(cr),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...) */
-        do_md_membed(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_seed,
-                                      cpt_period,max_hours,
-                                      deviceOptions,
-                                      Flags,
-                                      &runtime,
-                                      fac, r_ins, pos_ins, ins_at,
-                                      xy_step, z_step, it_xy, it_z);
-
-        if (inputrec->ePull != epullNO)
-        {
-            finish_pull(fplog,inputrec->pull);
-        }
-    }
-    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 (MASTER(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,
-               EI_DYNAMICS(inputrec->eI) && !MULTISIM(cr));
-
-    /* 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);
-    }
-
-    if (pieces>1)
-    {
-       sfree(piecename);
-    }
-
-    rc=(int)gmx_get_stop_condition();
-
-    return rc;
-}
-
 int gmx_membed(int argc,char *argv[])
 {
        const char *desc[] = {
@@ -4324,83 +91,24 @@ int gmx_membed(int argc,char *argv[])
                        " - It is recommended to perform a short equilibration run after the embedding",
                        "(see Wolf et al, J Comp Chem 31 (2010) 2169-2174, to re-equilibrate the membrane. Clearly",
                        "protein equilibration might require longer.\n",
+                       " - It is now also possible to use the g_membed functionality with mdrun. You should than pass",
+                       "a data file containing the command line options of g_membed following the -membed option, for",
+                       "example mdrun -s into_mem.tpr -membed membed.dat.",
                        "\n"
        };
-       t_commrec    *cr;
        t_filenm fnm[] = {
                        { efTPX, "-f",      "into_mem", ffREAD },
                        { efNDX, "-n",      "index",    ffOPTRD },
                        { efTOP, "-p",      "topol",    ffOPTRW },
                        { efTRN, "-o",      NULL,       ffWRITE },
                        { efXTC, "-x",      NULL,       ffOPTWR },
-                       { efCPT, "-cpi",    NULL,       ffOPTRD },
-                       { efCPT, "-cpo",    NULL,       ffOPTWR },
                        { efSTO, "-c",      "membedded",  ffWRITE },
                        { efEDR, "-e",      "ener",     ffWRITE },
-                       { efLOG, "-g",      "md",       ffWRITE },
-                       { efEDI, "-ei",     "sam",      ffOPTRD },
-                       { efTRX, "-rerun",  "rerun",    ffOPTRD },
-                       { efXVG, "-table",  "table",    ffOPTRD },
-                       { efXVG, "-tablep", "tablep",   ffOPTRD },
-                       { efXVG, "-tableb", "table",    ffOPTRD },
-                       { efXVG, "-dhdl",   "dhdl",     ffOPTWR },
-                       { efXVG, "-field",  "field",    ffOPTWR },
-                       { efXVG, "-table",  "table",    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 },
-                       { efEDO, "-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 },
-                       { efMTX, "-mtx",    "nm",       ffOPTWR },
-                       { efNDX, "-dn",     "dipole",   ffOPTWR }
+                        { efDAT, "-dat",    "membed",   ffWRITE }
        };
 #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 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  nstepout=100;
-       int  nthreads=0; /* set to determine # of threads automatically */
-       int  resetstep=-1;
-
-       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 };
-       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,bAddPart=TRUE;
-       gmx_bool bResetCountersHalfWay=FALSE;
-       output_env_t oenv=NULL;
-       const char *deviceOptions = "";
-
        real xy_fac = 0.5;
        real xy_max = 1.0;
        real z_fac = 1.0;
@@ -4411,8 +119,11 @@ int gmx_membed(int argc,char *argv[])
        int low_up_rm = 0;
        int maxwarn=0;
        int pieces=1;
-    gmx_bool bALLOW_ASYMMETRY=FALSE;
-
+        gmx_bool bALLOW_ASYMMETRY=FALSE;
+        gmx_bool bStart=FALSE;
+        int nstepout=100;
+        gmx_bool bVerbose=FALSE;
+        char *mdrun_path=NULL;
 
 /* arguments relevant to OPENMM only*/
 #ifdef GMX_OPENMM
@@ -4420,248 +131,87 @@ int gmx_membed(int argc,char *argv[])
 #endif
 
        t_pargs pa[] = {
-                       { "-xyinit",   FALSE, etREAL,  {&xy_fac},       "Resize factor for the protein in the xy dimension before starting embedding" },
-                       { "-xyend",   FALSE, etREAL,  {&xy_max},                "Final resize factor in the xy dimension" },
-                       { "-zinit",    FALSE, etREAL,  {&z_fac},                "Resize factor for the protein in the z dimension before starting embedding" },
-                       { "-zend",    FALSE, etREAL,  {&z_max},                 "Final resize faction in the z dimension" },
-                       { "-nxy",     FALSE,  etINT,  {&it_xy},         "Number of iteration for the xy dimension" },
-                       { "-nz",      FALSE,  etINT,  {&it_z},          "Number of iterations for the z dimension" },
-                       { "-rad",     FALSE, etREAL,  {&probe_rad},     "Probe radius to check for overlap between the group to embed and the membrane"},
-                       { "-pieces",  FALSE,  etINT,  {&pieces},        "Perform piecewise resize. Select parts of the group to insert and resize these with respect to their own geometrical center." },
-            { "-asymmetry",FALSE, etBOOL,{&bALLOW_ASYMMETRY}, "Allow asymmetric insertion, i.e. the number of lipids removed from the upper and lower leaflet will not be checked." },
-            { "-ndiff" ,  FALSE, etINT, {&low_up_rm},       "Number of lipids that will additionally be removed from the lower (negative number) or upper (positive number) membrane leaflet." },
-                       { "-maxwarn", FALSE, etINT, {&maxwarn},                 "Maximum number of warning allowed" },
-  { "-pd",      FALSE, etBOOL,{&bPartDec},
-    "HIDDENUse particle decompostion" },
-  { "-dd",      FALSE, etRVEC,{&realddxyz},
-    "HIDDENDomain decomposition grid, 0 is optimize" },
-  { "-nt",      FALSE, etINT, {&nthreads},
-    "HIDDENNumber of threads to start (0 is guess)" },
-  { "-npme",    FALSE, etINT, {&npme},
-    "HIDDENNumber of separate nodes to be used for PME, -1 is guess" },
-  { "-ddorder", FALSE, etENUM, {ddno_opt},
-    "HIDDENDD node order" },
-  { "-ddcheck", FALSE, etBOOL, {&bDDBondCheck},
-    "HIDDENCheck for all bonded interactions with DD" },
-  { "-ddbondcomm", FALSE, etBOOL, {&bDDBondComm},
-    "HIDDENUse special bonded atom communication when -rdd > cut-off" },
-  { "-rdd",     FALSE, etREAL, {&rdd},
-    "HIDDENThe maximum distance for bonded interactions with DD (nm), 0 is determine from initial coordinates" },
-  { "-rcon",    FALSE, etREAL, {&rconstr},
-    "HIDDENMaximum distance for P-LINCS (nm), 0 is estimate" },
-  { "-dlb",     FALSE, etENUM, {dddlb_opt},
-    "HIDDENDynamic load balancing (with DD)" },
-  { "-dds",     FALSE, etREAL, {&dlb_scale},
-    "HIDDENMinimum 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},
-    "HIDDENGlobal communication frequency" },
-  { "-compact", FALSE, etBOOL,{&bCompact},
-    "Write a compact log file" },
-  { "-seppot",  FALSE, etBOOL, {&bSepPot},
-    "HIDDENWrite separate V and dVdl terms for each interaction type and node to the log file(s)" },
-  { "-pforce",  FALSE, etREAL, {&pforce},
-    "HIDDENPrint all forces larger than this (kJ/mol nm)" },
-  { "-reprod",  FALSE, etBOOL,{&bReproducible},
-    "HIDDENTry to avoid optimizations that affect binary reproducibility" },
-  { "-multi",   FALSE, etINT,{&nmultisim},
-    "HIDDENDo multiple simulations in parallel" },
-  { "-replex",  FALSE, etINT, {&repl_ex_nst},
-    "HIDDENAttempt replica exchange every # steps" },
-  { "-reseed",  FALSE, etINT, {&repl_ex_seed},
-    "HIDDENSeed for replica exchange, -1 is generate a seed" },
-  { "-rerunvsite", FALSE, etBOOL, {&bRerunVSite},
-    "HIDDENRecalculate virtual site coordinates with -rerun" },
-  { "-ionize",  FALSE, etBOOL,{&bIonize},
-    "HIDDENDo a simulation including the effect of an X-Ray bombardment on your system" },
-  { "-confout", TRUE, etBOOL, {&bConfout},
-    "HIDDENWrite the last configuration with -c 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 -maxh" },
-  { "-v",       FALSE, etBOOL,{&bVerbose},
-    "Be loud and noisy" },
-  { "-maxh",   FALSE, etREAL, {&max_hours},
-    "HIDDENTerminate after 0.99 times this time (hours)" },
-  { "-cpt",     FALSE, etREAL, {&cpt_period},
-    "HIDDENCheckpoint interval (minutes)" },
-  { "-append",  FALSE, etBOOL, {&bAppendFiles},
-    "HIDDENAppend to previous output files when continuing from checkpoint" },
-  { "-addpart",  FALSE, etBOOL, {&bAddPart},
-    "HIDDENAdd the simulation part number to all output files when continuing from checkpoint" },
+                       { "-xyinit",   FALSE, etREAL,  {&xy_fac},       
+                               "Resize factor for the protein in the xy dimension before starting embedding" },
+                       { "-xyend",   FALSE, etREAL,  {&xy_max},
+                               "Final resize factor in the xy dimension" },
+                       { "-zinit",    FALSE, etREAL,  {&z_fac},
+                               "Resize factor for the protein in the z dimension before starting embedding" },
+                       { "-zend",    FALSE, etREAL,  {&z_max},
+                               "Final resize faction in the z dimension" },
+                       { "-nxy",     FALSE,  etINT,  {&it_xy},
+                               "Number of iteration for the xy dimension" },
+                       { "-nz",      FALSE,  etINT,  {&it_z},
+                               "Number of iterations for the z dimension" },
+                       { "-rad",     FALSE, etREAL,  {&probe_rad},
+                               "Probe radius to check for overlap between the group to embed and the membrane"},
+                       { "-pieces",  FALSE,  etINT,  {&pieces},
+                               "Perform piecewise resize. Select parts of the group to insert and resize these with respect to their own geometrical center." },
+                       { "-asymmetry",FALSE, etBOOL,{&bALLOW_ASYMMETRY}, 
+                               "Allow asymmetric insertion, i.e. the number of lipids removed from the upper and lower leaflet will not be checked." },
+                       { "-ndiff" ,  FALSE, etINT, {&low_up_rm},
+                               "Number of lipids that will additionally be removed from the lower (negative number) or upper (positive number) membrane leaflet." },
+                       { "-maxwarn", FALSE, etINT, {&maxwarn},         
+                               "Maximum number of warning allowed" },
+                        { "-start",   FALSE, etBOOL, {&bStart},
+                                "Call mdrun with membed options" },
+                       { "-stepout", FALSE, etINT, {&nstepout},
+                               "HIDDENFrequency of writing the remaining runtime" },
+                       { "-v",       FALSE, etBOOL,{&bVerbose},
+                               "Be loud and noisy" },
+                       { "-mdrun_path", FALSE, etSTR, {&mdrun_path},
+                               "Path to the mdrun executable compiled with this g_membed version" }
        };
-       gmx_edsam_t  ed;
-       unsigned long Flags, PCA_Flags;
-       ivec     ddxyz;
-       int      dd_node_order;
-       gmx_bool     HaveCheckpoint;
-       FILE     *fplog,*fptest;
-       int      sim_part,sim_part_fn;
-       const char *part_suffix=".part";
-       char     suffix[STRLEN];
-       int      rc;
-
-
-       cr = init_par(&argc,&argv);
-
-       PCA_Flags = (PCA_KEEP_ARGS | PCA_NOEXIT_ON_ARGS | 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;
-
-#ifdef GMX_THREADS
-       /* now determine the number of threads automatically. The threads are
-   only started at mdrunner_threads, though. */
-       if (nthreads<1)
-       {
-               nthreads=tMPI_Get_recommended_nthreads();
-       }
-#else
-       nthreads=1;
-#endif
 
+        FILE *data_out;
+        output_env_t oenv;
+        char buf[256],buf2[64];
 
-       if (repl_ex_nst != 0 && nmultisim < 2)
-               gmx_fatal(FARGS,"Need at least two replicas for replica exchange (option -multi)");
 
-       if (nmultisim > 1) {
-#ifndef GMX_THREADS
-               init_multisystem(cr,nmultisim,NFILE,fnm,TRUE);
-#else
-               gmx_fatal(FARGS,"mdrun -multi is not supported with the thread library.Please compile GROMACS with MPI support");
-#endif
-       }
-
-       /* Check if there is ANY checkpoint file available */
-       sim_part    = 1;
-       sim_part_fn = sim_part;
-       if (opt2bSet("-cpi",NFILE,fnm))
-       {
-               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;
-               }
-       }
-       else
-       {
-               bAppendFiles = FALSE;
-       }
+        parse_common_args(&argc,argv,0, NFILE,fnm,asize(pa),pa,
+                    asize(desc),desc,0,NULL, &oenv);
 
-       if (!bAppendFiles)
-       {
-               sim_part_fn = sim_part;
-       }
+        data_out = ffopen(opt2fn("-dat",NFILE,fnm),"w");
+        fprintf(data_out,"nxy = %d\nnz = %d\nxyinit = %f\nxyend = %f\nzinit = %f\nzend = %f\n"
+                       "rad = %f\npieces = %d\nasymmetry = %s\nndiff = %d\nmaxwarn = %d\n",
+                       it_xy,it_z,xy_fac,xy_max,z_fac,z_max,probe_rad,pieces,
+                       bALLOW_ASYMMETRY ? "yes" : "no",low_up_rm,maxwarn);
+        fclose(data_out);
 
-       if (bAddPart && sim_part_fn > 1)
+        sprintf(buf,"%s -s %s -membed %s -o %s -c %s -e %s -nt 1 -cpt -1",
+                   (mdrun_path==NULL) ? "mdrun" : mdrun_path,
+                   opt2fn("-f",NFILE,fnm),opt2fn("-dat",NFILE,fnm),opt2fn("-o",NFILE,fnm),
+                   opt2fn("-c",NFILE,fnm),opt2fn("-e",NFILE,fnm));
+        if (opt2bSet("-n",NFILE,fnm))
        {
-               /* This is a continuation run, rename trajectory 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);
-               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 | (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 | (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)
+               sprintf(buf2," -mn %s",opt2fn("-n",NFILE,fnm));
+               strcat(buf,buf2);
+        }
+       if (opt2bSet("-x",NFILE,fnm))
        {
-               gmx_log_open(ftp2fn(efLOG,NFILE,fnm),cr,!bSepPot,Flags,&fplog);
-               CopyRight(fplog,argv[0]);
-               please_cite(fplog,"Hess2008b");
-               please_cite(fplog,"Spoel2005a");
-               please_cite(fplog,"Lindahl2001a");
-               please_cite(fplog,"Berendsen95a");
+               sprintf(buf2," -x %s",opt2fn("-x",NFILE,fnm));
+                strcat(buf,buf2);
        }
-       else
+        if (opt2bSet("-p",NFILE,fnm))
+        {
+                sprintf(buf2," -mp %s",opt2fn("-p",NFILE,fnm));
+                strcat(buf,buf2);
+        }
+       if (bVerbose)
        {
-               fplog = NULL;
-       }
-
-       ddxyz[XX] = (int)(realddxyz[XX] + 0.5);
-       ddxyz[YY] = (int)(realddxyz[YY] + 0.5);
-       ddxyz[ZZ] = (int)(realddxyz[ZZ] + 0.5);
-
-       /* even if nthreads = 1, we still call this one */
-
-       rc = mdrunner_membed(fplog, cr, NFILE, fnm, oenv, bVerbose, bCompact,
-                       nstglobalcomm,
-                       ddxyz, dd_node_order, rdd, rconstr, dddlb_opt[0], dlb_scale,
-                       ddcsx, ddcsy, ddcsz, nstepout, resetstep, nmultisim, repl_ex_nst,
-                       repl_ex_seed, pforce, cpt_period, max_hours, deviceOptions, Flags,
-                       xy_fac,xy_max,z_fac,z_max,
-                       it_xy,it_z,probe_rad,low_up_rm,
-                       pieces,bALLOW_ASYMMETRY,maxwarn);
-
-       if (gmx_parallel_env_initialized())
-               gmx_finalize();
-
-       if (MULTIMASTER(cr)) {
-               thanx(stderr);
+               sprintf(buf2," -v -stepout %d",nstepout);
+               strcat(buf,buf2);
        }
 
-       /* Log file has to be closed in mdrunner if we are appending to it
-   (fplog not set here) */
-       fprintf(stderr,"Please cite:\nWolf et al, J Comp Chem 31 (2010) 2169-2174.\n");
+        printf("%s\n",buf);
+        if (bStart)
+        {
+                system(buf);
+        } else {
+                printf("You can membed your protein now by:\n%s\n",buf);
+        }
 
-       if (MASTER(cr) && !bAppendFiles)
-       {
-               gmx_log_close(fplog);
-       }
+        fprintf(stderr,"Please cite:\nWolf et al, J Comp Chem 31 (2010) 2169-2174.\n");
 
-       return rc;
+       return 0;
 }
index e46f6f40776781ff84199db56b4581e81cebe912..3665f390557c168fe22383a744ae6cd0831d0c04 100644 (file)
@@ -508,7 +508,7 @@ void printmol(t_corr *curr,const char *fn,
     for(j=0; (j<curr->nrestart); j++) {
       real xx,yy,dx,dy;
       
-      while(gmx_stats_get_point(curr->lsq[j][i],&xx,&yy,&dx,&dy) == estatsOK)
+      while(gmx_stats_get_point(curr->lsq[j][i],&xx,&yy,&dx,&dy,0) == estatsOK)
           gmx_stats_add_point(lsq1,xx,yy,dx,dy);
     }
     gmx_stats_get_ab(lsq1,elsqWEIGHT_NONE,&a,&b,NULL,NULL,NULL,NULL);
index d2baf690a6317ded07125f293864c7a86a0a7544..c0396989d6c7eda030075d16e0acaaa66fe15ff8 100644 (file)
@@ -1080,7 +1080,8 @@ int gmx_pme_error(int argc,char *argv[])
     cr = init_par(&argc,&argv);
     
 #ifdef GMX_MPI
-    MPI_Barrier(MPI_COMM_WORLD);
+    if (PAR(cr))
+        MPI_Barrier(MPI_COMM_WORLD);
 #endif
 
     if (MASTER(cr))
index 7f7dbeb3c6675984bc0935d41ec3d536c9178c19..0d59616405dbe769e9f5a0f40a7ae68447bc3c49 100644 (file)
@@ -122,8 +122,9 @@ int gmx_saltbr(int argc,char *argv[])
   const char *desc[] = {
     "g_saltbr plots the distance between all combination of charged groups",
     "as a function of time. The groups are combined in different ways.",
-    "A minimum distance can be given, (eg. the cut-off), then groups",
-    "that are never closer than that distance will not be plotted.[BR]",
+    "A truncation/cut-off distance can be supplied with -t, ",
+    "such that only groups interacting within this distance will be plotted in the ",
+    "output.[BR]",
     "Output will be in a number of fixed filenames, min-min.xvg, plus-min.xvg",
     "and plus-plus.xvg, or files for every individual ion-pair if the [TT]-sep[tt]",
     "option is selected. In this case files are named as [TT]sb-ResnameResnr-Atomnr[tt].",
index 4361af1b73a63c154051ae8355c2194e80be9623..8b65a3a4f9462a7e151598eb43b68411c708137a 100644 (file)
 #include <statutil.h>
 #include <xvgr.h>
 #include <string2.h>
-#include <trajana.h>
 #include "gmx_ana.h"
 #include "gmx_fatal.h"
 
+#include "gromacs/trajana/trajana.h"
 
 typedef struct
 {
index 12d747cdd8129702b8b57b3372c9a84ad007819e..ed6e9bb407b59468b18ada313746108f29b50ab7 100644 (file)
@@ -1140,7 +1140,11 @@ static void make_benchmark_tprs(
  * not on mdrun command line options! */
 static gmx_bool tpr_triggers_file(const char *opt)
 {
-    if ( (0 == strcmp(opt, "-pf"))
+    if ( (0 == strcmp(opt, "-ro"))
+      || (0 == strcmp(opt, "-ra"))
+      || (0 == strcmp(opt, "-rt"))
+      || (0 == strcmp(opt, "-rs"))
+      || (0 == strcmp(opt, "-pf"))
       || (0 == strcmp(opt, "-px")) )
         return TRUE;
     else
@@ -2047,6 +2051,10 @@ int gmx_tune_pme(int argc,char *argv[])
       { 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 },
       /* Output files that are deleted after each benchmark run */
@@ -2067,6 +2075,10 @@ int gmx_tune_pme(int argc,char *argv[])
       { efXVG, "-brunav", "benchrnav",ffOPTWR },
       { efXVG, "-bpx",    "benchpx",  ffOPTWR },
       { efXVG, "-bpf",    "benchpf",  ffOPTWR },
+      { efXVG, "-bro",    "benchrot", ffOPTWR },
+      { efLOG, "-bra",    "benchrota",ffOPTWR },
+      { efLOG, "-brs",    "benchrots",ffOPTWR },
+      { efLOG, "-brt",    "benchrott",ffOPTWR },
       { efMTX, "-bmtx",   "benchn",   ffOPTWR },
       { efNDX, "-bdn",    "bench",    ffOPTWR }
     };