Merge release-4-6 into master
authorRoland Schulz <roland@utk.edu>
Sun, 25 Nov 2012 16:18:20 +0000 (11:18 -0500)
committerRoland Schulz <roland@utk.edu>
Sun, 25 Nov 2012 16:18:20 +0000 (11:18 -0500)
Conflicts:
CMakeLists.txt
cmake/gmxCFlags.cmake
src/gromacs/legacyheaders/rdgroup.h: deleted
src/kernel/CMakeLists.txt: ignored. Instead renamed main.c to main.cpp
            and added main.cpp to programs/*/CMakeLists.txt
src/mdlib/CMakeLists.txt: applied to src/gromacs/mdlib/CMakeLists.txt
src/tools/g_anadock.c: master changes applied to gmx_anadock.c
src/tools/make_edi.c: master changes applied to gmx_make_edi.c

For 5.0 we always compile with C++ and thus all main functions should be
always compiled with C++. Thus we shouldn't have a main.c which is compiled
with C++ but instead the main function should always be in a cpp file.
Because tools are currenlty anyhow changed to g_ana (Change-Id: Ifcd166dbd)
I don't rename all tools main files to .cpp.

Change-Id: I083968bcbaca8020364f19a69d9a5b74f00b1eac

269 files changed:
1  2 
CMakeLists.txt
cmake/gmxCFlags.cmake
share/template/CMakeLists.txt
src/contrib/testxml.c
src/gromacs/gmxlib/nonbonded/CMakeLists.txt
src/gromacs/gmxlib/nonbonded/nb_free_energy.c
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel_ElecRFCut_VdwCSTab_GeomW4W4_c.c
src/gromacs/gmxlib/nonbonded/nb_kernel_c/nb_kernel_template_c.pre
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/kernelutil_x86_sse2_single.h
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecCSTab_VdwCSTab_GeomP1P1_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecCSTab_VdwCSTab_GeomW3P1_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecCSTab_VdwCSTab_GeomW3W3_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecCSTab_VdwCSTab_GeomW4P1_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecCSTab_VdwCSTab_GeomW4W4_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecCSTab_VdwLJ_GeomP1P1_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecCSTab_VdwLJ_GeomW3P1_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecCSTab_VdwLJ_GeomW3W3_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecCSTab_VdwLJ_GeomW4P1_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecCSTab_VdwLJ_GeomW4W4_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecCSTab_VdwNone_GeomP1P1_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecCSTab_VdwNone_GeomW3P1_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecCSTab_VdwNone_GeomW3W3_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecCSTab_VdwNone_GeomW4P1_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecCSTab_VdwNone_GeomW4W4_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecCoul_VdwCSTab_GeomP1P1_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecCoul_VdwCSTab_GeomW3P1_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecCoul_VdwCSTab_GeomW3W3_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecCoul_VdwCSTab_GeomW4P1_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecCoul_VdwCSTab_GeomW4W4_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecCoul_VdwLJ_GeomP1P1_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecCoul_VdwLJ_GeomW3P1_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecCoul_VdwLJ_GeomW3W3_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecCoul_VdwLJ_GeomW4P1_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecCoul_VdwLJ_GeomW4W4_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecCoul_VdwNone_GeomP1P1_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecCoul_VdwNone_GeomW3P1_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecCoul_VdwNone_GeomW3W3_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecCoul_VdwNone_GeomW4P1_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecCoul_VdwNone_GeomW4W4_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecEwSh_VdwLJSh_GeomP1P1_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecEwSh_VdwLJSh_GeomW3P1_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecEwSh_VdwLJSh_GeomW3W3_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecEwSh_VdwLJSh_GeomW4P1_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecEwSh_VdwLJSh_GeomW4W4_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecEwSh_VdwNone_GeomP1P1_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecEwSh_VdwNone_GeomW3P1_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecEwSh_VdwNone_GeomW3W3_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecEwSh_VdwNone_GeomW4P1_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecEwSh_VdwNone_GeomW4W4_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecEwSw_VdwLJSw_GeomP1P1_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecEwSw_VdwLJSw_GeomW3P1_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecEwSw_VdwLJSw_GeomW3W3_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecEwSw_VdwLJSw_GeomW4P1_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecEwSw_VdwLJSw_GeomW4W4_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecEwSw_VdwNone_GeomP1P1_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecEwSw_VdwNone_GeomW3P1_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecEwSw_VdwNone_GeomW3W3_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecEwSw_VdwNone_GeomW4P1_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecEwSw_VdwNone_GeomW4W4_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecEw_VdwCSTab_GeomP1P1_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecEw_VdwCSTab_GeomW3P1_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecEw_VdwCSTab_GeomW3W3_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecEw_VdwCSTab_GeomW4P1_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecEw_VdwCSTab_GeomW4W4_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecEw_VdwLJ_GeomP1P1_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecEw_VdwLJ_GeomW3P1_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecEw_VdwLJ_GeomW3W3_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecEw_VdwLJ_GeomW4P1_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecEw_VdwLJ_GeomW4W4_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecEw_VdwNone_GeomP1P1_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecEw_VdwNone_GeomW3P1_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecEw_VdwNone_GeomW3W3_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecEw_VdwNone_GeomW4P1_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecEw_VdwNone_GeomW4W4_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecGB_VdwCSTab_GeomP1P1_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecGB_VdwLJ_GeomP1P1_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecGB_VdwNone_GeomP1P1_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecNone_VdwCSTab_GeomP1P1_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecNone_VdwLJSh_GeomP1P1_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecNone_VdwLJSw_GeomP1P1_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecNone_VdwLJ_GeomP1P1_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecRFCut_VdwCSTab_GeomP1P1_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecRFCut_VdwCSTab_GeomW3P1_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecRFCut_VdwCSTab_GeomW3W3_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecRFCut_VdwCSTab_GeomW4P1_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecRFCut_VdwCSTab_GeomW4W4_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecRFCut_VdwLJSh_GeomP1P1_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecRFCut_VdwLJSh_GeomW3P1_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecRFCut_VdwLJSh_GeomW3W3_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecRFCut_VdwLJSh_GeomW4P1_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecRFCut_VdwLJSh_GeomW4W4_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecRFCut_VdwLJSw_GeomP1P1_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecRFCut_VdwLJSw_GeomW3P1_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecRFCut_VdwLJSw_GeomW3W3_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecRFCut_VdwLJSw_GeomW4P1_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecRFCut_VdwLJSw_GeomW4W4_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecRFCut_VdwNone_GeomP1P1_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecRFCut_VdwNone_GeomW3P1_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecRFCut_VdwNone_GeomW3W3_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecRFCut_VdwNone_GeomW4P1_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecRFCut_VdwNone_GeomW4W4_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecRF_VdwCSTab_GeomP1P1_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecRF_VdwCSTab_GeomW3P1_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecRF_VdwCSTab_GeomW3W3_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecRF_VdwCSTab_GeomW4P1_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecRF_VdwCSTab_GeomW4W4_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecRF_VdwLJ_GeomP1P1_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecRF_VdwLJ_GeomW3P1_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecRF_VdwLJ_GeomW3W3_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecRF_VdwLJ_GeomW4P1_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecRF_VdwLJ_GeomW4W4_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecRF_VdwNone_GeomP1P1_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecRF_VdwNone_GeomW3P1_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecRF_VdwNone_GeomW3W3_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecRF_VdwNone_GeomW4P1_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_ElecRF_VdwNone_GeomW4W4_sse2_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse2_single/nb_kernel_template_sse2_single.pre
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/kernelutil_x86_sse4_1_single.h
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/make_nb_kernel_sse4_1_single.py
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecCSTab_VdwCSTab_GeomP1P1_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecCSTab_VdwCSTab_GeomW3P1_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecCSTab_VdwCSTab_GeomW3W3_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecCSTab_VdwCSTab_GeomW4P1_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecCSTab_VdwCSTab_GeomW4W4_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecCSTab_VdwLJ_GeomP1P1_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecCSTab_VdwLJ_GeomW3P1_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecCSTab_VdwLJ_GeomW3W3_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecCSTab_VdwLJ_GeomW4P1_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecCSTab_VdwLJ_GeomW4W4_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecCSTab_VdwNone_GeomP1P1_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecCSTab_VdwNone_GeomW3P1_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecCSTab_VdwNone_GeomW3W3_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecCSTab_VdwNone_GeomW4P1_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecCSTab_VdwNone_GeomW4W4_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecCoul_VdwCSTab_GeomP1P1_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecCoul_VdwCSTab_GeomW3P1_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecCoul_VdwCSTab_GeomW3W3_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecCoul_VdwCSTab_GeomW4P1_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecCoul_VdwCSTab_GeomW4W4_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecCoul_VdwLJ_GeomP1P1_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecCoul_VdwLJ_GeomW3P1_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecCoul_VdwLJ_GeomW3W3_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecCoul_VdwLJ_GeomW4P1_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecCoul_VdwLJ_GeomW4W4_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecCoul_VdwNone_GeomP1P1_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecCoul_VdwNone_GeomW3P1_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecCoul_VdwNone_GeomW3W3_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecCoul_VdwNone_GeomW4P1_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecCoul_VdwNone_GeomW4W4_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecEwSh_VdwLJSh_GeomP1P1_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecEwSh_VdwLJSh_GeomW3P1_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecEwSh_VdwLJSh_GeomW3W3_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecEwSh_VdwLJSh_GeomW4P1_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecEwSh_VdwLJSh_GeomW4W4_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecEwSh_VdwNone_GeomP1P1_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecEwSh_VdwNone_GeomW3P1_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecEwSh_VdwNone_GeomW3W3_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecEwSh_VdwNone_GeomW4P1_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecEwSh_VdwNone_GeomW4W4_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecEwSw_VdwLJSw_GeomP1P1_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecEwSw_VdwLJSw_GeomW3P1_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecEwSw_VdwLJSw_GeomW3W3_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecEwSw_VdwLJSw_GeomW4P1_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecEwSw_VdwLJSw_GeomW4W4_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecEwSw_VdwNone_GeomP1P1_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecEwSw_VdwNone_GeomW3P1_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecEwSw_VdwNone_GeomW3W3_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecEwSw_VdwNone_GeomW4P1_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecEwSw_VdwNone_GeomW4W4_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecEw_VdwCSTab_GeomP1P1_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecEw_VdwCSTab_GeomW3P1_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecEw_VdwCSTab_GeomW3W3_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecEw_VdwCSTab_GeomW4P1_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecEw_VdwCSTab_GeomW4W4_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecEw_VdwLJ_GeomP1P1_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecEw_VdwLJ_GeomW3P1_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecEw_VdwLJ_GeomW3W3_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecEw_VdwLJ_GeomW4P1_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecEw_VdwLJ_GeomW4W4_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecEw_VdwNone_GeomP1P1_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecEw_VdwNone_GeomW3P1_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecEw_VdwNone_GeomW3W3_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecEw_VdwNone_GeomW4P1_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecEw_VdwNone_GeomW4W4_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecGB_VdwCSTab_GeomP1P1_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecGB_VdwLJ_GeomP1P1_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecGB_VdwNone_GeomP1P1_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecNone_VdwCSTab_GeomP1P1_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecNone_VdwLJSh_GeomP1P1_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecNone_VdwLJSw_GeomP1P1_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecNone_VdwLJ_GeomP1P1_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecRFCut_VdwCSTab_GeomP1P1_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecRFCut_VdwCSTab_GeomW3P1_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecRFCut_VdwCSTab_GeomW3W3_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecRFCut_VdwCSTab_GeomW4P1_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecRFCut_VdwCSTab_GeomW4W4_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecRFCut_VdwLJSh_GeomP1P1_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecRFCut_VdwLJSh_GeomW3P1_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecRFCut_VdwLJSh_GeomW3W3_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecRFCut_VdwLJSh_GeomW4P1_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecRFCut_VdwLJSh_GeomW4W4_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecRFCut_VdwLJSw_GeomP1P1_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecRFCut_VdwLJSw_GeomW3P1_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecRFCut_VdwLJSw_GeomW3W3_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecRFCut_VdwLJSw_GeomW4P1_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecRFCut_VdwLJSw_GeomW4W4_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecRFCut_VdwNone_GeomP1P1_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecRFCut_VdwNone_GeomW3P1_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecRFCut_VdwNone_GeomW3W3_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecRFCut_VdwNone_GeomW4P1_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecRFCut_VdwNone_GeomW4W4_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecRF_VdwCSTab_GeomP1P1_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecRF_VdwCSTab_GeomW3P1_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecRF_VdwCSTab_GeomW3W3_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecRF_VdwCSTab_GeomW4P1_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecRF_VdwCSTab_GeomW4W4_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecRF_VdwLJ_GeomP1P1_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecRF_VdwLJ_GeomW3P1_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecRF_VdwLJ_GeomW3W3_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecRF_VdwLJ_GeomW4P1_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecRF_VdwLJ_GeomW4W4_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecRF_VdwNone_GeomP1P1_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecRF_VdwNone_GeomW3P1_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecRF_VdwNone_GeomW3W3_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecRF_VdwNone_GeomW4P1_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_ElecRF_VdwNone_GeomW4W4_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_sse4_1_single.c
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_sse4_1_single.h
src/gromacs/gmxlib/nonbonded/nb_kernel_sse4_1_single/nb_kernel_template_sse4_1_single.pre
src/gromacs/gmxlib/nonbonded/nonbonded.c
src/gromacs/gmxpreprocess/readpull.c
src/gromacs/legacyheaders/confio.h
src/gromacs/legacyheaders/gmx_ana.h
src/gromacs/legacyheaders/gmx_x86_sse4_1.h
src/gromacs/legacyheaders/maths.h
src/gromacs/legacyheaders/md_support.h
src/gromacs/legacyheaders/toputil.h
src/gromacs/mdlib/CMakeLists.txt
src/gromacs/mdlib/force.c
src/gromacs/mdlib/forcerec.c
src/gromacs/mdlib/iteratedconstraints.c
src/gromacs/mdlib/pull.c
src/gromacs/mdlib/pullutil.c
src/gromacs/mdlib/sim_util.c
src/programs/g_protonate/CMakeLists.txt
src/programs/g_protonate/g_protonate.c
src/programs/g_x2top/CMakeLists.txt
src/programs/g_x2top/g_x2top.c
src/programs/gmxcheck/CMakeLists.txt
src/programs/gmxcheck/gmxcheck.c
src/programs/gmxcheck/tpbcmp.c
src/programs/gmxdump/CMakeLists.txt
src/programs/gmxdump/gmxdump.c
src/programs/grompp/CMakeLists.txt
src/programs/grompp/grompp.c
src/programs/main.cpp
src/programs/mdrun/CMakeLists.txt
src/programs/mdrun/md.c
src/programs/mdrun/mdrun.c
src/programs/pdb2gmx/CMakeLists.txt
src/programs/pdb2gmx/pdb2gmx.c
src/programs/tpbconv/CMakeLists.txt
src/programs/tpbconv/tpbconv.c
src/tools/CMakeLists.txt
src/tools/gmx_anadock.c
src/tools/gmx_make_edi.c
src/tools/gmx_msd.c
src/tools/gmx_tune_pme.c
src/tools/gmx_wham.cpp

diff --cc CMakeLists.txt
index 08bd1c8f229b2292a3dae84faade95e4a20be3fa,9cd938cb7eaf07254e8a0595a31933ed3c35342d..9dfbd26e6fd19e0023dc2a3e61eaad62f2308364
@@@ -107,6 -104,18 +107,7 @@@ if(CMAKE_HOST_UNIX
  endif()
  
  ########################################################################
 -# User input options - enable C++ - before any CXX flags are changed   #
 -########################################################################
 -option(GMX_GPU  "Enable GPU acceleration" ON)
 -option(GMX_OPENMM "Accelerated execution on GPUs through the OpenMM library (rerun cmake after changing to see relevant options)" OFF)
 -option(GMX_FORCE_CXX "Enable C++ compilation even if not necessary" OFF)
 -mark_as_advanced(GMX_FORCE_CXX)
 -if(GMX_GPU OR GMX_OPENMM OR GMX_FORCE_CXX)
 -    enable_language(CXX)
 -endif()
+ set(CMAKE_PREFIX_PATH "" CACHE STRING "Extra locations to search for external libraries and tools (give directory without lib, bin, or include)")
 -
 -########################################################################
  # Fix stupid flags on Windows
  ########################################################################
  SET(SHARED_LIBS_DEFAULT ON) 
@@@ -206,27 -209,28 +207,26 @@@ option(GMX_CYCLE_SUBCOUNTERS "Enable cy
  mark_as_advanced(GMX_CYCLE_SUBCOUNTERS)
  
  ######################################################################
- # compiler tests
- # these need ot be done early (before further tests).
+ # Compiler tests
+ # These need to be done early (before further tests).
  #####################################################################
  
- # cmake/Check{C,CXX}CompilerFlag.cmake are lifted from CMake git next
- # branch (proposed for v2.8.9) to be able to detect invalid options
- # with the Intel Compilers.
- # Remove these files from the source tree when a CMake version that
- # includes the features in question becomes required.
+ # The cmake/Check{C,CXX}CompilerFlag.cmake files in the GROMACS distribution
+ # are used with permission from CMake v2.8.9 so that GROMACS can detect
+ # invalid options with the Intel Compilers.
+ # These files should be removed from the source tree when a CMake version that
+ # includes the features in question becomes required for building GROMACS.
  include(CheckCCompilerFlag)
 -if(CMAKE_CXX_COMPILER_LOADED)
 -    include(CheckCXXCompilerFlag)
 -endif()
 +include(CheckCXXCompilerFlag)
  
  # OpenMP check must come before other CFLAGS!
  if(GMX_OPENMP)
      find_package(OpenMP)
      if(OPENMP_FOUND)
-         #- only set linker flag, if user didn't set them manual
-         #- cmake on windows doesn't support linker flags passed to target_link_libraries
-         #  (cmake treats /openmp as \openmp library file) and no openmp linker flags are needed
+         # CMake on Windows doesn't support linker flags passed to target_link_libraries
+         # (i.e. it treats /openmp as \openmp library file). Also, no OpenMP linker flags are needed.
          if(NOT (WIN32 AND NOT CYGWIN))
 -            if(CMAKE_COMPILER_IS_GNUCC AND GMX_PREFER_STATIC_OPENMP)
 +            if(CMAKE_COMPILER_IS_GNUCC AND GMX_PREFER_STATIC_OPENMP AND NOT APPLE)
                  set(OpenMP_LINKER_FLAGS "-Wl,-static -lgomp -lrt -Wl,-Bdynamic -lpthread")
                  set(OpenMP_SHARED_LINKER_FLAGS "")
              else()
index 77657961cf1c5db1939efc6f00bdb1ad140c5663,e84af63ccde7a0560a60d72fd2594752a305d86c..8c0de1ffb069b2a59656e6f0c03f7dafaf7f4dbc
@@@ -13,12 -13,12 +13,12 @@@ ENDMACRO(GMX_TEST_CFLAG VARIABLE FLAGS 
  # Test C++ flags FLAGS, and set VARIABLE to true if the work. Also add the
  # flags to CXXFLAGSVAR.
  MACRO(GMX_TEST_CXXFLAG VARIABLE FLAGS CXXFLAGSVAR)
 -    IF(NOT DEFINED ${VARIABLE} AND CMAKE_CXX_COMPILER_LOADED)
 +    IF(NOT DEFINED ${VARIABLE})
          CHECK_CXX_COMPILER_FLAG("${FLAGS}" ${VARIABLE})
-         IF (${VARIABLE})
-             SET (${CXXFLAGSVAR} "${FLAGS} ${${CXXFLAGSVAR}}")
-         ENDIF (${VARIABLE}) 
 -    ENDIF(NOT DEFINED ${VARIABLE} AND CMAKE_CXX_COMPILER_LOADED)
 +    ENDIF(NOT DEFINED ${VARIABLE})
+     IF (${VARIABLE})
+         SET (${CXXFLAGSVAR} "${FLAGS} ${${CXXFLAGSVAR}}")
+     ENDIF (${VARIABLE})
  ENDMACRO(GMX_TEST_CXXFLAG VARIABLE FLAGS CXXFLAGSVAR)
  
  
@@@ -56,11 -56,10 +56,11 @@@ MACRO(gmx_c_flags
      # g++
      if(CMAKE_COMPILER_IS_GNUCXX)
          if(NOT GMX_OPENMP)
-             GMX_TEST_CFLAG(CXXFLAGS_PRAGMA "-Wno-unknown-pragmas" GMXC_CXXFLAGS)
+             GMX_TEST_CXXFLAG(CXXFLAGS_PRAGMA "-Wno-unknown-pragmas" GMXC_CXXFLAGS)
          endif()
-         GMX_TEST_CXXFLAG(CXXFLAGS_WARN "-Wall -Wno-unused-function -Wno-unused-parameter" GMXC_CXXFLAGS)
-         GMX_TEST_CXXFLAG(CXXFLAGS_WARN "-Wnon-virtual-dtor" GMXC_CXXFLAGS)
-         GMX_TEST_CXXFLAG(CXXFLAGS_WARN "-Wextra -Wno-missing-field-initializers" GMXC_CXXFLAGS)
+         GMX_TEST_CXXFLAG(CXXFLAGS_WARN "-Wall -Wno-unused -Wunused-value" GMXC_CXXFLAGS)
 -        GMX_TEST_CXXFLAG(CXXFLAGS_WARN_EXTRA "-Wextra -Wno-missing-field-initializers -Wno-sign-compare" GMXC_CXXFLAGS)
++        GMX_TEST_CXXFLAG(CXXFLAGS_WARN_EFFCXX "-Wnon-virtual-dtor" GMXC_CXXFLAGS)
++        GMX_TEST_CXXFLAG(CXXFLAGS_WARN_EXTRA "-Wextra -Wno-missing-field-initializers" GMXC_CXXFLAGS)
        # new in gcc 4.5
          GMX_TEST_CXXFLAG(CXXFLAGS_EXCESS_PREC "-fexcess-precision=fast" GMXC_CXXFLAGS_RELEASE)
          GMX_TEST_CXXFLAG(CXXFLAGS_COPT "-fomit-frame-pointer -funroll-all-loops"
          GMX_TEST_CFLAG(CFLAGS_LANG "-qlanglvl=extc99" GMXC_CFLAGS)
      endif()
      if (CMAKE_CXX_COMPILER_ID MATCHES "XL")
-         GMX_TEST_CXXFLAG(CFLAGS_OPT "-qarch=auto -qtune=auto" GMXC_CXXFLAGS)
+         GMX_TEST_CXXFLAG(CXXFLAGS_OPT "-qarch=auto -qtune=auto" GMXC_CXXFLAGS)
      endif()
  
 -    #msvc
 +    # msvc
      if (MSVC)
          # disable warnings for: 
 -        #      inconsistent dll linkage
 -        GMX_TEST_CFLAG(CFLAGS_WARN "/wd4273" GMXC_CFLAGS)
 -        GMX_TEST_CXXFLAG(CXXFLAGS_WARN "/wd4273" GMXC_CXXFLAGS)
 +        #      forcing value to bool
 +        #      "this" in initializer list
 +        #      deprecated (posix, secure) functions
 +        GMX_TEST_CFLAG(CFLAGS_WARN "/wd4800 /wd4355 /wd4996" GMXC_CFLAGS)
-         GMX_TEST_CFLAG(CXXFLAGS_WARN "/wd4800 /wd4355 /wd4996" GMXC_CXXFLAGS)
++        GMX_TEST_CXXFLAG(CXXFLAGS_WARN "/wd4800 /wd4355 /wd4996" GMXC_CXXFLAGS)
 +    endif()
 +
 +    if (CMAKE_C_COMPILER_ID MATCHES "Clang")
 +        if(NOT GMX_OPENMP)
 +            GMX_TEST_CFLAG(CFLAGS_PRAGMA "-Wno-unknown-pragmas" GMXC_CFLAGS)
 +        endif()
 +        GMX_TEST_CFLAG(CFLAGS_WARN "-Wall -Wno-unused" GMXC_CFLAGS)
      endif()
  
 +    if (CMAKE_C_COMPILER_ID MATCHES "Clang")
 +        if(NOT GMX_OPENMP)
 +            GMX_TEST_CFLAG(CXXFLAGS_PRAGMA "-Wno-unknown-pragmas" GMXC_CXXFLAGS)
 +        endif()
 +        GMX_TEST_CXXFLAG(CXXFLAGS_WARN "-Wall -Wno-unused-function" GMXC_CXXFLAGS)
 +    endif()
 +      
      if (CMAKE_C_COMPILER_ID MATCHES "Clang")
          if(NOT GMX_OPENMP)
              GMX_TEST_CFLAG(CFLAGS_PRAGMA "-Wno-unknown-pragmas" GMXC_CFLAGS)
Simple merge
index bea44f4dd3b02c62c3df90b4c5d512b4363dfdf0,0000000000000000000000000000000000000000..e1d1bdbdcb4e72da78116483c2d72b97aa4fc187
mode 100644,000000..100644
--- /dev/null
@@@ -1,79 -1,0 +1,79 @@@
- int main(int argc,char *argv[])
 +/*
 + * 
 + *                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
 + */
 +#include "macros.h"
 +#include "smalloc.h"
 +#include "xmlio.h"
 +#include "statutil.h"
 +#include "tpxio.h"
 +
++int cmain(int argc,char *argv[])
 +{
 +  int        step,natoms;
 +  real       t,lambda;
 +  t_inputrec ir;
 +  t_topology top;
 +  matrix     box;
 +  rvec       *x,*v,*f;
 +  t_filenm fnm[] = {
 +    { efTPX, NULL, NULL, ffREAD  },
 +    { efXML, "-r", NULL, ffREAD  },
 +    { efXML, "-o", NULL, ffWRITE }
 +  };  
 +#define NFILE asize(fnm)
 +
 +  CopyRight(stderr,argv[0]);
 +  parse_common_args(&argc,argv,0,NFILE,fnm,0,NULL,0,NULL,0,NULL);
 +  
 +  init_top(&top);
 +  if (opt2bSet("-r",NFILE,fnm))
 +    read_xml(opt2fn("-r",NFILE,fnm),&step,&t,&lambda,&ir,
 +           box,&natoms,&x,&v,&f,&top);
 +  else {
 +    t_tpxheader tpx;
 +    
 +    read_tpxheader(ftp2fn(efTPX,NFILE,fnm),&tpx,FALSE);
 +    snew(x,tpx.natoms);
 +    snew(v,tpx.natoms);
 +    f = NULL;
 +    read_tpx(ftp2fn(efTPX,NFILE,fnm),&step,&t,&lambda,&ir,
 +           box,&natoms,x,v,f,&top);
 +  }
 +  /*write_xml(opt2fn("-o",NFILE,fnm),step,t,lambda,&ir,box,natoms,x,v,f,&top);*/
 +  
 +  return 0;
 +}
 +
 +
 +
index 0000000000000000000000000000000000000000,3db14fb769fab38305e19a946011b4b185c53fd8..3db14fb769fab38305e19a946011b4b185c53fd8
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,d16e608f0292e75c2ff69f315fe0d1880807d4f6..d16e608f0292e75c2ff69f315fe0d1880807d4f6
mode 000000,100755..100755
--- /dev/null
index 0000000000000000000000000000000000000000,71f74f45654feb569e80827fb15fb62dd96ab236..71f74f45654feb569e80827fb15fb62dd96ab236
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,89ee5c19b0ced0be366433ed582c02bd33002e27..89ee5c19b0ced0be366433ed582c02bd33002e27
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,a337ae2f77828081323f6ed54cd03b8af307ab7a..a337ae2f77828081323f6ed54cd03b8af307ab7a
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,424291fd0ed571166faec2faae5163da08a584d9..424291fd0ed571166faec2faae5163da08a584d9
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,0e1755e564d7ac7c7274a68ca0b8f6609fb1a7a4..0e1755e564d7ac7c7274a68ca0b8f6609fb1a7a4
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,4f80354d9156d5f60e112b8e1e4185bee90fc57e..4f80354d9156d5f60e112b8e1e4185bee90fc57e
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,2478fb16bb032dea0cda4eb8d894d1e833649458..2478fb16bb032dea0cda4eb8d894d1e833649458
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,499a65956bbf384f6ef576275e5d1c08356bec51..499a65956bbf384f6ef576275e5d1c08356bec51
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,adc8bb219241fba0413157313bbdaff1b25f9717..adc8bb219241fba0413157313bbdaff1b25f9717
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,211579c83efa9dc2d7085b4a1e8a7e0a9f634c96..211579c83efa9dc2d7085b4a1e8a7e0a9f634c96
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,db773fcaa7c08ef0dda4d0a99742cfe20d024862..db773fcaa7c08ef0dda4d0a99742cfe20d024862
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,6deaef13a177da3ea2d6a94972ea46880fd097da..6deaef13a177da3ea2d6a94972ea46880fd097da
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,a8054157a141e46495c2eb4a01803bc5e1dd0622..a8054157a141e46495c2eb4a01803bc5e1dd0622
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,1733db7272416237ca075d8158dad3eafd2b7f2f..1733db7272416237ca075d8158dad3eafd2b7f2f
mode 000000,100644..100644
--- /dev/null
Simple merge
index 2b2372545fada9d30c36ccc98f3cf1208dd477ce,0000000000000000000000000000000000000000..cb6e57b1acac94c1cebbf517d4b60abaf887dab9
mode 100644,000000..100644
--- /dev/null
@@@ -1,111 -1,0 +1,107 @@@
- void init_t_atoms(t_atoms *atoms, int natoms, gmx_bool bPdbinfo);
- /* allocate memory for the arrays, set nr to natoms and nres to 0
-  * set pdbinfo to NULL or allocate memory for it */  
 +/*
 + * 
 + *                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 _confio_h
 +#define _confio_h
 +
 +
 +#include "typedefs.h"
 +
 +/* For reading coordinate files it is assumed that enough memory
 + * has been allocated beforehand.
 + */
 +#ifdef __cplusplus
 +extern "C" {
 +#endif
 +  
 +int read_g96_conf(FILE *fp,const char *infile,t_trxframe *fr, char *line);
 +/* read a Gromos96 coordinate or trajectory file,                       *
 + * returns the number of atoms                                          *
 + * sets what's in the frame in info                                     *  
 + * read from fp, infile is only needed for error messages               *   
 + * nwanted is the number of wanted coordinates,                         *
 + * set this to -1 if you want to know the number of atoms in the file   *
 + * title, atoms, x, v can all be NULL, in which case they won't be read *
 + * line holds the previous line for trajectory reading                  */
 +
 +void write_g96_conf(FILE *out,t_trxframe *fr,int nindex,const atom_id *index);
 +/* write a Gromos96 coordinate file or trajectory frame *
 + * index can be NULL                                    */
 +
 +gmx_bool gro_next_x_or_v(FILE *status,t_trxframe *fr);
 +int gro_first_x_or_v(FILE *status,t_trxframe *fr);
 +/* read first/next x and/or v frame from gro file */
 +
 +void write_hconf_indexed_p(FILE *out,const char *title,t_atoms *atoms,
 +                           int nx,const atom_id index[],int ndec,
 +                           rvec *x,rvec *v,matrix box);
 +
 +void write_hconf_p(FILE *out,const char *title,t_atoms *atoms, int ndec,
 +                        rvec *x,rvec *v,matrix box); 
 +/* Write a Gromos file with precision ndec: number of decimal places in x,
 + * v has one place more. */ 
 +
 +void write_sto_conf_indexed(const char *outfile,const char *title,
 +                          t_atoms *atoms, 
 +                          rvec x[],rvec *v,int ePBC,matrix box,
 +                          atom_id nindex,atom_id index[]);
 +/* like write_sto_conf, but indexed */ 
 +
 +void write_sto_conf(const char *outfile,const char *title,
 +                         t_atoms *atoms, 
 +                         rvec x[],rvec *v,int ePBC,matrix box);
 +/* write atoms, x, v (if .gro and not NULL) and box (if not NULL) 
 + * to an STO (.gro or .pdb) file */ 
 +
 +void write_sto_conf_mtop(const char *outfile,const char *title,
 +                              gmx_mtop_t *mtop,
 +                              rvec x[],rvec *v,int ePBC,matrix box);
 +/* As write_sto_conf, but uses a gmx_mtop_t struct */
 +
 +void get_stx_coordnum (const char *infile,int *natoms);
 +/* read the number of atoms from an STX file */
 +
 +void read_stx_conf(const char *infile,char *title,
 +                        t_atoms *atoms, 
 +                        rvec x[],rvec *v,int *ePBC,matrix box);
 +/* Read atoms, x, v and box from an STX file.
 + * If ePBC!=NULL return the type of pbc in *ePBC or -1 if unknown.
 + */
 +
 +#ifdef __cplusplus
 +}
 +#endif
 +
 +#endif        /* _confio_h */
Simple merge
index bbc2b811eac189ef06dc7cc4517e532e23cb0bf0,0000000000000000000000000000000000000000..3ade75f1e52dc2466cf397bc66f6a9f9f334b13f
mode 100644,000000..100644
--- /dev/null
@@@ -1,163 -1,0 +1,161 @@@
- int           gmx_nint(real a);
- real    sign(real x,real y);
 +/* -*- 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:
 + * Gromacs Runs On Most of All Computer Systems
 + */
 +
 +#ifndef _maths_h
 +#define _maths_h
 +
 +#include <math.h>
 +#include "types/simple.h"
 +#include "typedefs.h"
 +
 +#ifdef __cplusplus
 +extern "C" {
 +#endif
 +
 +#ifndef M_PI
 +#define       M_PI            3.14159265358979323846
 +#endif
 +
 +#ifndef M_PI_2
 +#define       M_PI_2          1.57079632679489661923
 +#endif
 +
 +#ifndef M_2PI
 +#define       M_2PI           6.28318530717958647692
 +#endif
 +    
 +#ifndef M_SQRT2
 +#define M_SQRT2 sqrt(2.0)
 +#endif
 +
 +#ifndef M_1_PI
 +#define M_1_PI      0.31830988618379067154
 +#endif
 +
 +int           gmx_nint(real a);
 +real    sign(real x,real y);
 +
 +real    cuberoot (real a);
 +double  gmx_erfd(double x);
 +double  gmx_erfcd(double x);
 +float   gmx_erff(float x);
 +float   gmx_erfcf(float x);
 +#ifdef GMX_DOUBLE
 +#define gmx_erf(x)   gmx_erfd(x)
 +#define gmx_erfc(x)  gmx_erfcd(x)
 +#else
 +#define gmx_erf(x)   gmx_erff(x)
 +#define gmx_erfc(x)  gmx_erfcf(x)
 +#endif
 +
 +gmx_bool gmx_isfinite(real x);
 +
 +/*! \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( fabs(f1-f2) <= tol*0.5*(fabs(f1)+fabs(f2)) )
 +    {
 +        return 1;
 +    }
 +    else
 +    {
 +        return 0;
 +    }
 +}
 +
 +
 +
 +/** 
 + * 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);
 +}
 +
 +
 +static real
 +gmx_log2(real x)
 +{
 +  const real iclog2 = 1.0/log( 2.0 );
 +
 +    return log( x ) * iclog2;
 +}
 +
 +/*! /brief Multiply two large ints
 + *
 + *  Returns true when overflow did not occur.
 + */
 +gmx_bool
 +check_int_multiply_for_overflow(gmx_large_int_t a,
 +                                gmx_large_int_t b,
 +                                gmx_large_int_t *result);
 +
 +#ifdef __cplusplus
 +}
 +#endif
 +
 +#endif        /* _maths_h */
Simple merge
index 35f6d271d756b6319c303701b54242f609e895f7,0000000000000000000000000000000000000000..96c331230b7af7e712fb69ed7442df2d746cb32f
mode 100644,000000..100644
--- /dev/null
@@@ -1,14 -1,0 +1,14 @@@
- file(GLOB MDLIB_SOURCES *.c *.cpp nbnxn_kernels/*.c)
 +
++file(GLOB MDLIB_SOURCES nbnxn_kernels/*.c *.c *.cpp)
 +if(GMX_FFT_FFTPACK)
 +list(APPEND MDLIB_SOURCES ${CMAKE_SOURCE_DIR}/src/external/fftpack/fftpack.c)
 +endif()
 +set(MDLIB_SOURCES ${MDLIB_SOURCES} PARENT_SCOPE)
 +if (BUILD_TESTING)
 +    add_subdirectory(tests)
 +endif (BUILD_TESTING)
 +
 +if(GMX_GPU)
 +    add_subdirectory(nbnxn_cuda)
 +    set(GMX_GPU_LIBRARIES ${GMX_GPU_LIBRARIES} nbnxn_cuda PARENT_SCOPE)
 +endif()
index cdcc6e9f2dd6e776d457ffccc6a9e4ce607e9979,0000000000000000000000000000000000000000..73e278c36fbce445d8463e8e81fa6430b0209770
mode 100644,000000..100644
--- /dev/null
@@@ -1,923 -1,0 +1,926 @@@
-     if (flags & GMX_FORCE_NONBONDED)
 +/* -*- 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 <math.h>
 +#include <string.h>
 +#include <assert.h>
 +#include "sysstuff.h"
 +#include "typedefs.h"
 +#include "macros.h"
 +#include "smalloc.h"
 +#include "macros.h"
 +#include "physics.h"
 +#include "force.h"
 +#include "nonbonded.h"
 +#include "names.h"
 +#include "network.h"
 +#include "pbc.h"
 +#include "ns.h"
 +#include "nrnb.h"
 +#include "bondf.h"
 +#include "mshift.h"
 +#include "txtdump.h"
 +#include "coulomb.h"
 +#include "pme.h"
 +#include "mdrun.h"
 +#include "domdec.h"
 +#include "partdec.h"
 +#include "qmmm.h"
 +#include "gmx_omp_nthreads.h"
 +
 +
 +void ns(FILE *fp,
 +        t_forcerec *fr,
 +        rvec       x[],
 +        matrix     box,
 +        gmx_groups_t *groups,
 +        t_grpopts  *opts,
 +        gmx_localtop_t *top,
 +        t_mdatoms  *md,
 +        t_commrec  *cr,
 +        t_nrnb     *nrnb,
 +        real       *lambda,
 +        real       *dvdlambda,
 +        gmx_grppairener_t *grppener,
 +        gmx_bool       bFillGrid,
 +        gmx_bool       bDoLongRangeNS)
 +{
 +  char   *ptr;
 +  int    nsearch;
 +
 +
 +  if (!fr->ns.nblist_initialized)
 +  {
 +      init_neighbor_list(fp, fr, md->homenr);
 +  }
 +
 +  if (fr->bTwinRange)
 +    fr->nlr=0;
 +
 +    nsearch = search_neighbours(fp,fr,x,box,top,groups,cr,nrnb,md,
 +                                lambda,dvdlambda,grppener,
 +                                bFillGrid,bDoLongRangeNS,TRUE);
 +  if (debug)
 +    fprintf(debug,"nsearch = %d\n",nsearch);
 +
 +  /* Check whether we have to do dynamic load balancing */
 +  /*if ((nsb->nstDlb > 0) && (mod(step,nsb->nstDlb) == 0))
 +    count_nb(cr,nsb,&(top->blocks[ebCGS]),nns,fr->nlr,
 +    &(top->idef),opts->ngener);
 +  */
 +  if (fr->ns.dump_nl > 0)
 +    dump_nblist(fp,cr,fr,fr->ns.dump_nl);
 +}
 +
 +static void reduce_thread_forces(int n,rvec *f,
 +                                 tensor vir,
 +                                 real *Vcorr,
 +                                 int efpt_ind,real *dvdl,
 +                                 int nthreads,f_thread_t *f_t)
 +{
 +    int t,i;
 +
 +    /* This reduction can run over any number of threads */
 +#pragma omp parallel for num_threads(gmx_omp_nthreads_get(emntBonded)) private(t) schedule(static)
 +    for(i=0; i<n; i++)
 +    {
 +        for(t=1; t<nthreads; t++)
 +        {
 +            rvec_inc(f[i],f_t[t].f[i]);
 +        }
 +    }
 +    for(t=1; t<nthreads; t++)
 +    {
 +        *Vcorr += f_t[t].Vcorr;
 +        *dvdl  += f_t[t].dvdl[efpt_ind];
 +        m_add(vir,f_t[t].vir,vir);
 +    }
 +}
 +
 +void do_force_lowlevel(FILE       *fplog,   gmx_large_int_t step,
 +                       t_forcerec *fr,      t_inputrec *ir,
 +                       t_idef     *idef,    t_commrec  *cr,
 +                       t_nrnb     *nrnb,    gmx_wallcycle_t wcycle,
 +                       t_mdatoms  *md,
 +                       t_grpopts  *opts,
 +                       rvec       x[],      history_t  *hist,
 +                       rvec       f[],
 +                       rvec       f_longrange[],
 +                       gmx_enerdata_t *enerd,
 +                       t_fcdata   *fcd,
 +                       gmx_mtop_t     *mtop,
 +                       gmx_localtop_t *top,
 +                       gmx_genborn_t *born,
 +                       t_atomtypes *atype,
 +                       gmx_bool       bBornRadii,
 +                       matrix     box,
 +                       t_lambda   *fepvals,
 +                       real       *lambda,
 +                       t_graph    *graph,
 +                       t_blocka   *excl,
 +                       rvec       mu_tot[],
 +                       int        flags,
 +                       float      *cycles_pme)
 +{
 +    int     i,j,status;
 +    int     donb_flags;
 +    gmx_bool    bDoEpot,bSepDVDL,bSB;
 +    int     pme_flags;
 +    matrix  boxs;
 +    rvec    box_size;
 +    real    Vsr,Vlr,Vcorr=0;
 +    t_pbc   pbc;
 +    real    dvdgb;
 +    char    buf[22];
 +    gmx_enerdata_t ed_lam;
 +    double  clam_i,vlam_i;
 +    real    dvdl_dum[efptNR], dvdl, dvdl_nb[efptNR], lam_i[efptNR];
 +    real    dvdlsum;
 +
 +#ifdef GMX_MPI
 +    double  t0=0.0,t1,t2,t3; /* time measurement for coarse load balancing */
 +#endif
 +
 +#define PRINT_SEPDVDL(s,v,dvdlambda) if (bSepDVDL) fprintf(fplog,sepdvdlformat,s,v,dvdlambda);
 +
 +
 +    set_pbc(&pbc,fr->ePBC,box);
 +
 +    /* reset free energy components */
 +    for (i=0;i<efptNR;i++)
 +    {
 +        dvdl_nb[i]  = 0;
 +        dvdl_dum[i] = 0;
 +    }
 +
 +    /* Reset box */
 +    for(i=0; (i<DIM); i++)
 +    {
 +        box_size[i]=box[i][i];
 +    }
 +
 +    bSepDVDL=(fr->bSepDVDL && do_per_step(step,ir->nstlog));
 +    debug_gmx();
 +
 +    /* do QMMM first if requested */
 +    if(fr->bQMMM)
 +    {
 +        enerd->term[F_EQM] = calculate_QMMM(cr,x,f,fr,md);
 +    }
 +
 +    if (bSepDVDL)
 +    {
 +        fprintf(fplog,"Step %s: non-bonded V and dVdl for node %d:\n",
 +                gmx_step_str(step,buf),cr->nodeid);
 +    }
 +
 +    /* Call the short range functions all in one go. */
 +
 +#ifdef GMX_MPI
 +    /*#define TAKETIME ((cr->npmenodes) && (fr->timesteps < 12))*/
 +#define TAKETIME FALSE
 +    if (TAKETIME)
 +    {
 +        MPI_Barrier(cr->mpi_comm_mygroup);
 +        t0=MPI_Wtime();
 +    }
 +#endif
 +
 +    if (ir->nwall)
 +    {
 +        /* foreign lambda component for walls */
 +        dvdl = do_walls(ir,fr,box,md,x,f,lambda[efptVDW],
 +                        enerd->grpp.ener[egLJSR],nrnb);
 +        PRINT_SEPDVDL("Walls",0.0,dvdl);
 +        enerd->dvdl_lin[efptVDW] += dvdl;
 +    }
 +
 +      /* If doing GB, reset dvda and calculate the Born radii */
 +      if (ir->implicit_solvent)
 +      {
 +        wallcycle_sub_start(wcycle, ewcsNONBONDED);
 +
 +              for(i=0;i<born->nr;i++)
 +              {
 +                      fr->dvda[i]=0;
 +              }
 +
 +              if(bBornRadii)
 +              {
 +                      calc_gb_rad(cr,fr,ir,top,atype,x,&(fr->gblist),born,md,nrnb);
 +              }
 +
 +        wallcycle_sub_stop(wcycle, ewcsNONBONDED);
 +      }
 +
 +    where();
++    /* We only do non-bonded calculation with group scheme here, the verlet
++     * calls are done from do_force_cutsVERLET(). */
++    if (fr->cutoff_scheme == ecutsGROUP && (flags & GMX_FORCE_NONBONDED))
 +    {
 +        donb_flags = 0;
 +        /* Add short-range interactions */
 +        donb_flags |= GMX_NONBONDED_DO_SR;
 +
 +        if (flags & GMX_FORCE_FORCES)
 +        {
 +            donb_flags |= GMX_NONBONDED_DO_FORCE;
 +        }
 +        if (flags & GMX_FORCE_ENERGY)
 +        {
 +            donb_flags |= GMX_NONBONDED_DO_POTENTIAL;
 +        }
 +        if (flags & GMX_FORCE_DO_LR)
 +        {
 +            donb_flags |= GMX_NONBONDED_DO_LR;
 +        }
 +
 +        wallcycle_sub_start(wcycle, ewcsNONBONDED);
 +        do_nonbonded(cr,fr,x,f,f_longrange,md,excl,
 +                    &enerd->grpp,box_size,nrnb,
 +                    lambda,dvdl_nb,-1,-1,donb_flags);
 +        wallcycle_sub_stop(wcycle, ewcsNONBONDED);
 +    }
 +
 +    /* If we do foreign lambda and we have soft-core interactions
 +     * we have to recalculate the (non-linear) energies contributions.
 +     */
 +    if (fepvals->n_lambda > 0 && (flags & GMX_FORCE_DHDL) && fepvals->sc_alpha != 0)
 +    {
 +        wallcycle_sub_start(wcycle, ewcsNONBONDED);
 +        init_enerdata(mtop->groups.grps[egcENER].nr,fepvals->n_lambda,&ed_lam);
 +
 +        for(i=0; i<enerd->n_lambda; i++)
 +        {
 +            for (j=0;j<efptNR;j++)
 +            {
 +                lam_i[j] = (i==0 ? lambda[j] : fepvals->all_lambda[j][i-1]);
 +            }
 +            reset_enerdata(&ir->opts,fr,TRUE,&ed_lam,FALSE);
 +            do_nonbonded(cr,fr,x,f,f_longrange,md,excl,
 +                         &(ed_lam.grpp), box_size,nrnb,
 +                         lam_i,dvdl_dum,-1,-1,
 +                         GMX_NONBONDED_DO_FOREIGNLAMBDA | GMX_NONBONDED_DO_SR);
 +            sum_epot(&ir->opts,&ed_lam);
 +            enerd->enerpart_lambda[i] += ed_lam.term[F_EPOT];
 +        }
 +        destroy_enerdata(&ed_lam);
 +        wallcycle_sub_stop(wcycle, ewcsNONBONDED);
 +    }
 +    where();
 +
 +      /* If we are doing GB, calculate bonded forces and apply corrections
 +       * to the solvation forces */
 +    /* MRS: Eventually, many need to include free energy contribution here! */
 +      if (ir->implicit_solvent)
 +    {
++        wallcycle_sub_start(wcycle, ewcsBONDED);
 +              calc_gb_forces(cr,md,born,top,atype,x,f,fr,idef,
 +                       ir->gb_algorithm,ir->sa_algorithm,nrnb,bBornRadii,&pbc,graph,enerd);
 +        wallcycle_sub_stop(wcycle, ewcsBONDED);
 +    }
 +
 +#ifdef GMX_MPI
 +    if (TAKETIME)
 +    {
 +        t1=MPI_Wtime();
 +        fr->t_fnbf += t1-t0;
 +    }
 +#endif
 +
 +    if (fepvals->sc_alpha!=0)
 +    {
 +        enerd->dvdl_nonlin[efptVDW] += dvdl_nb[efptVDW];
 +    }
 +    else
 +    {
 +        enerd->dvdl_lin[efptVDW] += dvdl_nb[efptVDW];
 +    }
 +
 +    if (fepvals->sc_alpha!=0)
 +
 +        /* even though coulomb part is linear, we already added it, beacuse we
 +           need to go through the vdw calculation anyway */
 +    {
 +        enerd->dvdl_nonlin[efptCOUL] += dvdl_nb[efptCOUL];
 +    }
 +    else
 +    {
 +        enerd->dvdl_lin[efptCOUL] += dvdl_nb[efptCOUL];
 +    }
 +
 +    Vsr = 0;
 +    if (bSepDVDL)
 +    {
 +        for(i=0; i<enerd->grpp.nener; i++)
 +        {
 +            Vsr +=
 +                (fr->bBHAM ?
 +                 enerd->grpp.ener[egBHAMSR][i] :
 +                 enerd->grpp.ener[egLJSR][i])
 +                + enerd->grpp.ener[egCOULSR][i] + enerd->grpp.ener[egGB][i];
 +        }
 +        dvdlsum = dvdl_nb[efptVDW] + dvdl_nb[efptCOUL];
 +        PRINT_SEPDVDL("VdW and Coulomb SR particle-p.",Vsr,dvdlsum);
 +    }
 +    debug_gmx();
 +
 +
 +    if (debug)
 +    {
 +        pr_rvecs(debug,0,"fshift after SR",fr->fshift,SHIFTS);
 +    }
 +
 +    /* Shift the coordinates. Must be done before bonded forces and PPPM,
 +     * but is also necessary for SHAKE and update, therefore it can NOT
 +     * go when no bonded forces have to be evaluated.
 +     */
 +
 +    /* Here sometimes we would not need to shift with NBFonly,
 +     * but we do so anyhow for consistency of the returned coordinates.
 +     */
 +    if (graph)
 +    {
 +        shift_self(graph,box,x);
 +        if (TRICLINIC(box))
 +        {
 +            inc_nrnb(nrnb,eNR_SHIFTX,2*graph->nnodes);
 +        }
 +        else
 +        {
 +            inc_nrnb(nrnb,eNR_SHIFTX,graph->nnodes);
 +        }
 +    }
 +    /* Check whether we need to do bondeds or correct for exclusions */
 +    if (fr->bMolPBC &&
 +        ((flags & GMX_FORCE_BONDED)
 +         || EEL_RF(fr->eeltype) || EEL_FULL(fr->eeltype)))
 +    {
 +        /* Since all atoms are in the rectangular or triclinic unit-cell,
 +         * only single box vector shifts (2 in x) are required.
 +         */
 +        set_pbc_dd(&pbc,fr->ePBC,cr->dd,TRUE,box);
 +    }
 +    debug_gmx();
 +
 +    if (flags & GMX_FORCE_BONDED)
 +    {
 +        wallcycle_sub_start(wcycle, ewcsBONDED);
 +        calc_bonds(fplog,cr->ms,
 +                   idef,x,hist,f,fr,&pbc,graph,enerd,nrnb,lambda,md,fcd,
 +                   DOMAINDECOMP(cr) ? cr->dd->gatindex : NULL, atype, born,
 +                   flags,
 +                   fr->bSepDVDL && do_per_step(step,ir->nstlog),step);
 +
 +        /* Check if we have to determine energy differences
 +         * at foreign lambda's.
 +         */
 +        if (fepvals->n_lambda > 0 && (flags & GMX_FORCE_DHDL) &&
 +            idef->ilsort != ilsortNO_FE)
 +        {
 +            if (idef->ilsort != ilsortFE_SORTED)
 +            {
 +                gmx_incons("The bonded interactions are not sorted for free energy");
 +            }
 +            init_enerdata(mtop->groups.grps[egcENER].nr,fepvals->n_lambda,&ed_lam);
 +
 +            for(i=0; i<enerd->n_lambda; i++)
 +            {
 +                reset_enerdata(&ir->opts,fr,TRUE,&ed_lam,FALSE);
 +                for (j=0;j<efptNR;j++)
 +                {
 +                    lam_i[j] = (i==0 ? lambda[j] : fepvals->all_lambda[j][i-1]);
 +                }
 +                calc_bonds_lambda(fplog,idef,x,fr,&pbc,graph,&ed_lam,nrnb,lam_i,md,
 +                                  fcd,DOMAINDECOMP(cr) ? cr->dd->gatindex : NULL);
 +                sum_epot(&ir->opts,&ed_lam);
 +                enerd->enerpart_lambda[i] += ed_lam.term[F_EPOT];
 +            }
 +            destroy_enerdata(&ed_lam);
 +        }
 +        debug_gmx();
 +
 +        wallcycle_sub_stop(wcycle, ewcsBONDED);
 +    }
 +
 +    where();
 +
 +    *cycles_pme = 0;
 +    if (EEL_FULL(fr->eeltype))
 +    {
 +        bSB = (ir->nwall == 2);
 +        if (bSB)
 +        {
 +            copy_mat(box,boxs);
 +            svmul(ir->wall_ewald_zfac,boxs[ZZ],boxs[ZZ]);
 +            box_size[ZZ] *= ir->wall_ewald_zfac;
 +        }
 +
 +        clear_mat(fr->vir_el_recip);
 +
 +        if (fr->bEwald)
 +        {
 +            Vcorr = 0;
 +            dvdl  = 0;
 +
 +            /* With the Verlet scheme exclusion forces are calculated
 +             * in the non-bonded kernel.
 +             */
 +            /* The TPI molecule does not have exclusions with the rest
 +             * of the system and no intra-molecular PME grid contributions
 +             * will be calculated in gmx_pme_calc_energy.
 +             */
 +            if ((ir->cutoff_scheme == ecutsGROUP && fr->n_tpi == 0) ||
 +                ir->ewald_geometry != eewg3D ||
 +                ir->epsilon_surface != 0)
 +            {
 +                int nthreads,t;
 +
 +                wallcycle_sub_start(wcycle, ewcsEWALD_CORRECTION);
 +
 +                if (fr->n_tpi > 0)
 +                {
 +                    gmx_fatal(FARGS,"TPI with PME currently only works in a 3D geometry with tin-foil boundary conditions");
 +                }
 +
 +                nthreads = gmx_omp_nthreads_get(emntBonded);
 +#pragma omp parallel for num_threads(nthreads) schedule(static)
 +                for(t=0; t<nthreads; t++)
 +                {
 +                    int s,e,i;
 +                    rvec *fnv;
 +                    tensor *vir;
 +                    real *Vcorrt,*dvdlt;
 +                    if (t == 0)
 +                    {
 +                        fnv    = fr->f_novirsum;
 +                        vir    = &fr->vir_el_recip;
 +                        Vcorrt = &Vcorr;
 +                        dvdlt  = &dvdl;
 +                    }
 +                    else
 +                    {
 +                        fnv    = fr->f_t[t].f;
 +                        vir    = &fr->f_t[t].vir;
 +                        Vcorrt = &fr->f_t[t].Vcorr;
 +                        dvdlt  = &fr->f_t[t].dvdl[efptCOUL];
 +                        for(i=0; i<fr->natoms_force; i++)
 +                        {
 +                            clear_rvec(fnv[i]);
 +                        }
 +                        clear_mat(*vir);
 +                    }
 +                    *dvdlt = 0;
 +                    *Vcorrt =
 +                        ewald_LRcorrection(fplog,
 +                                           fr->excl_load[t],fr->excl_load[t+1],
 +                                           cr,t,fr,
 +                                           md->chargeA,
 +                                           md->nChargePerturbed ? md->chargeB : NULL,
 +                                           ir->cutoff_scheme != ecutsVERLET,
 +                                           excl,x,bSB ? boxs : box,mu_tot,
 +                                           ir->ewald_geometry,
 +                                           ir->epsilon_surface,
 +                                           fnv,*vir,
 +                                           lambda[efptCOUL],dvdlt);
 +                }
 +                if (nthreads > 1)
 +                {
 +                    reduce_thread_forces(fr->natoms_force,fr->f_novirsum,
 +                                         fr->vir_el_recip,
 +                                         &Vcorr,efptCOUL,&dvdl,
 +                                         nthreads,fr->f_t);
 +                }
 +
 +                wallcycle_sub_stop(wcycle, ewcsEWALD_CORRECTION);
 +            }
 +
 +            if (fr->n_tpi == 0)
 +            {
 +                Vcorr += ewald_charge_correction(cr,fr,lambda[efptCOUL],box,
 +                                                 &dvdl,fr->vir_el_recip);
 +            }
 +
 +            PRINT_SEPDVDL("Ewald excl./charge/dip. corr.",Vcorr,dvdl);
 +            enerd->dvdl_lin[efptCOUL] += dvdl;
 +        }
 +
 +        status = 0;
 +        Vlr  = 0;
 +        dvdl = 0;
 +        switch (fr->eeltype)
 +        {
 +        case eelPME:
 +        case eelPMESWITCH:
 +        case eelPMEUSER:
 +        case eelPMEUSERSWITCH:
 +        case eelP3M_AD:
 +            if (cr->duty & DUTY_PME)
 +            {
 +                assert(fr->n_tpi >= 0);
 +                if (fr->n_tpi == 0 || (flags & GMX_FORCE_STATECHANGED))
 +                {
 +                    pme_flags = GMX_PME_SPREAD_Q | GMX_PME_SOLVE;
 +                    if (flags & GMX_FORCE_FORCES)
 +                    {
 +                        pme_flags |= GMX_PME_CALC_F;
 +                    }
 +                    if (flags & (GMX_FORCE_VIRIAL | GMX_FORCE_ENERGY))
 +                    {
 +                        pme_flags |= GMX_PME_CALC_ENER_VIR;
 +                    }
 +                    if (fr->n_tpi > 0)
 +                    {
 +                        /* We don't calculate f, but we do want the potential */
 +                        pme_flags |= GMX_PME_CALC_POT;
 +                    }
 +                    wallcycle_start(wcycle,ewcPMEMESH);
 +                    status = gmx_pme_do(fr->pmedata,
 +                                        md->start,md->homenr - fr->n_tpi,
 +                                        x,fr->f_novirsum,
 +                                        md->chargeA,md->chargeB,
 +                                        bSB ? boxs : box,cr,
 +                                        DOMAINDECOMP(cr) ? dd_pme_maxshift_x(cr->dd) : 0,
 +                                        DOMAINDECOMP(cr) ? dd_pme_maxshift_y(cr->dd) : 0,
 +                                        nrnb,wcycle,
 +                                        fr->vir_el_recip,fr->ewaldcoeff,
 +                                        &Vlr,lambda[efptCOUL],&dvdl,
 +                                        pme_flags);
 +                    *cycles_pme = wallcycle_stop(wcycle,ewcPMEMESH);
 +
 +                    /* We should try to do as little computation after
 +                     * this as possible, because parallel PME synchronizes
 +                     * the nodes, so we want all load imbalance of the rest
 +                     * of the force calculation to be before the PME call.
 +                     * DD load balancing is done on the whole time of
 +                     * the force call (without PME).
 +                     */
 +                }
 +                if (fr->n_tpi > 0)
 +                {
 +                    /* Determine the PME grid energy of the test molecule
 +                     * with the PME grid potential of the other charges.
 +                     */
 +                    gmx_pme_calc_energy(fr->pmedata,fr->n_tpi,
 +                                        x + md->homenr - fr->n_tpi,
 +                                        md->chargeA + md->homenr - fr->n_tpi,
 +                                        &Vlr);
 +                }
 +                PRINT_SEPDVDL("PME mesh",Vlr,dvdl);
 +            }
 +            break;
 +        case eelEWALD:
 +            Vlr = do_ewald(fplog,FALSE,ir,x,fr->f_novirsum,
 +                           md->chargeA,md->chargeB,
 +                           box_size,cr,md->homenr,
 +                           fr->vir_el_recip,fr->ewaldcoeff,
 +                           lambda[efptCOUL],&dvdl,fr->ewald_table);
 +            PRINT_SEPDVDL("Ewald long-range",Vlr,dvdl);
 +            break;
 +        default:
 +            gmx_fatal(FARGS,"No such electrostatics method implemented %s",
 +                      eel_names[fr->eeltype]);
 +        }
 +        if (status != 0)
 +        {
 +            gmx_fatal(FARGS,"Error %d in long range electrostatics routine %s",
 +                      status,EELTYPE(fr->eeltype));
 +              }
 +        /* Note that with separate PME nodes we get the real energies later */
 +        enerd->dvdl_lin[efptCOUL] += dvdl;
 +        enerd->term[F_COUL_RECIP] = Vlr + Vcorr;
 +        if (debug)
 +        {
 +            fprintf(debug,"Vlr = %g, Vcorr = %g, Vlr_corr = %g\n",
 +                    Vlr,Vcorr,enerd->term[F_COUL_RECIP]);
 +            pr_rvecs(debug,0,"vir_el_recip after corr",fr->vir_el_recip,DIM);
 +            pr_rvecs(debug,0,"fshift after LR Corrections",fr->fshift,SHIFTS);
 +        }
 +    }
 +    else
 +    {
 +        if (EEL_RF(fr->eeltype))
 +        {
 +            /* With the Verlet scheme exclusion forces are calculated
 +             * in the non-bonded kernel.
 +             */
 +            if (ir->cutoff_scheme != ecutsVERLET && fr->eeltype != eelRF_NEC)
 +            {
 +                dvdl = 0;
 +                enerd->term[F_RF_EXCL] =
 +                    RF_excl_correction(fplog,fr,graph,md,excl,x,f,
 +                                       fr->fshift,&pbc,lambda[efptCOUL],&dvdl);
 +            }
 +
 +            enerd->dvdl_lin[efptCOUL] += dvdl;
 +            PRINT_SEPDVDL("RF exclusion correction",
 +                          enerd->term[F_RF_EXCL],dvdl);
 +        }
 +    }
 +    where();
 +    debug_gmx();
 +
 +    if (debug)
 +    {
 +        print_nrnb(debug,nrnb);
 +    }
 +    debug_gmx();
 +
 +#ifdef GMX_MPI
 +    if (TAKETIME)
 +    {
 +        t2=MPI_Wtime();
 +        MPI_Barrier(cr->mpi_comm_mygroup);
 +        t3=MPI_Wtime();
 +        fr->t_wait += t3-t2;
 +        if (fr->timesteps == 11)
 +        {
 +            fprintf(stderr,"* PP load balancing info: node %d, step %s, rel wait time=%3.0f%% , load string value: %7.2f\n",
 +                    cr->nodeid, gmx_step_str(fr->timesteps,buf),
 +                    100*fr->t_wait/(fr->t_wait+fr->t_fnbf),
 +                    (fr->t_fnbf+fr->t_wait)/fr->t_fnbf);
 +        }
 +        fr->timesteps++;
 +    }
 +#endif
 +
 +    if (debug)
 +    {
 +        pr_rvecs(debug,0,"fshift after bondeds",fr->fshift,SHIFTS);
 +    }
 +
 +}
 +
 +void init_enerdata(int ngener,int n_lambda,gmx_enerdata_t *enerd)
 +{
 +    int i,n2;
 +
 +    for(i=0; i<F_NRE; i++)
 +    {
 +        enerd->term[i] = 0;
 +    }
 +
 +
 +    for(i=0; i<efptNR; i++) {
 +        enerd->dvdl_lin[i]  = 0;
 +        enerd->dvdl_nonlin[i]  = 0;
 +    }
 +
 +    n2=ngener*ngener;
 +    if (debug)
 +    {
 +        fprintf(debug,"Creating %d sized group matrix for energies\n",n2);
 +    }
 +    enerd->grpp.nener = n2;
 +    for(i=0; (i<egNR); i++)
 +    {
 +        snew(enerd->grpp.ener[i],n2);
 +    }
 +
 +    if (n_lambda)
 +    {
 +        enerd->n_lambda = 1 + n_lambda;
 +        snew(enerd->enerpart_lambda,enerd->n_lambda);
 +    }
 +    else
 +    {
 +        enerd->n_lambda = 0;
 +    }
 +}
 +
 +void destroy_enerdata(gmx_enerdata_t *enerd)
 +{
 +    int i;
 +
 +    for(i=0; (i<egNR); i++)
 +    {
 +        sfree(enerd->grpp.ener[i]);
 +    }
 +
 +    if (enerd->n_lambda)
 +    {
 +        sfree(enerd->enerpart_lambda);
 +    }
 +}
 +
 +static real sum_v(int n,real v[])
 +{
 +  real t;
 +  int  i;
 +
 +  t = 0.0;
 +  for(i=0; (i<n); i++)
 +    t = t + v[i];
 +
 +  return t;
 +}
 +
 +void sum_epot(t_grpopts *opts,gmx_enerdata_t *enerd)
 +{
 +  gmx_grppairener_t *grpp;
 +  real *epot;
 +  int i;
 +
 +  grpp = &enerd->grpp;
 +  epot = enerd->term;
 +
 +  /* Accumulate energies */
 +  epot[F_COUL_SR]  = sum_v(grpp->nener,grpp->ener[egCOULSR]);
 +  epot[F_LJ]       = sum_v(grpp->nener,grpp->ener[egLJSR]);
 +  epot[F_LJ14]     = sum_v(grpp->nener,grpp->ener[egLJ14]);
 +  epot[F_COUL14]   = sum_v(grpp->nener,grpp->ener[egCOUL14]);
 +  epot[F_COUL_LR]  = sum_v(grpp->nener,grpp->ener[egCOULLR]);
 +  epot[F_LJ_LR]    = sum_v(grpp->nener,grpp->ener[egLJLR]);
 +  /* We have already added 1-2,1-3, and 1-4 terms to F_GBPOL */
 +  epot[F_GBPOL]   += sum_v(grpp->nener,grpp->ener[egGB]);
 +
 +/* lattice part of LR doesnt belong to any group
 + * and has been added earlier
 + */
 +  epot[F_BHAM]     = sum_v(grpp->nener,grpp->ener[egBHAMSR]);
 +  epot[F_BHAM_LR]  = sum_v(grpp->nener,grpp->ener[egBHAMLR]);
 +
 +  epot[F_EPOT] = 0;
 +  for(i=0; (i<F_EPOT); i++)
 +  {
 +      if (i != F_DISRESVIOL && i != F_ORIRESDEV)
 +      {
 +          epot[F_EPOT] += epot[i];
 +      }
 +  }
 +}
 +
 +void sum_dhdl(gmx_enerdata_t *enerd, real *lambda, t_lambda *fepvals)
 +{
 +    int i,j,index;
 +    double dlam;
 +
 +    enerd->dvdl_lin[efptVDW] += enerd->term[F_DVDL_VDW];  /* include dispersion correction */
 +    enerd->term[F_DVDL] = 0.0;
 +    for (i=0;i<efptNR;i++)
 +    {
 +        if (fepvals->separate_dvdl[i])
 +        {
 +            /* could this be done more readably/compactly? */
 +            switch (i) {
 +            case (efptCOUL):
 +                index = F_DVDL_COUL;
 +                break;
 +            case (efptVDW):
 +                index = F_DVDL_VDW;
 +                break;
 +            case (efptBONDED):
 +                index = F_DVDL_BONDED;
 +                break;
 +            case (efptRESTRAINT):
 +                index = F_DVDL_RESTRAINT;
 +                break;
 +            case (efptMASS):
 +                index = F_DKDL;
 +                break;
 +            default:
 +                index = F_DVDL;
 +                break;
 +            }
 +            enerd->term[index] = enerd->dvdl_lin[i] + enerd->dvdl_nonlin[i];
 +            if (debug)
 +            {
 +                fprintf(debug,"dvdl-%s[%2d]: %f: non-linear %f + linear %f\n",
 +                        efpt_names[i],i,enerd->term[index],enerd->dvdl_nonlin[i],enerd->dvdl_lin[i]);
 +            }
 +        }
 +        else
 +        {
 +            enerd->term[F_DVDL] += enerd->dvdl_lin[i] + enerd->dvdl_nonlin[i];
 +            if (debug)
 +            {
 +                fprintf(debug,"dvd-%sl[%2d]: %f: non-linear %f + linear %f\n",
 +                        efpt_names[0],i,enerd->term[F_DVDL],enerd->dvdl_nonlin[i],enerd->dvdl_lin[i]);
 +            }
 +        }
 +    }
 +
 +    /* Notes on the foreign lambda free energy difference evaluation:
 +     * Adding the potential and ekin terms that depend linearly on lambda
 +     * as delta lam * dvdl to the energy differences is exact.
 +     * For the constraints this is not exact, but we have no other option
 +     * without literally changing the lengths and reevaluating the energies at each step.
 +     * (try to remedy this post 4.6 - MRS)
 +     * For the non-bonded LR term we assume that the soft-core (if present)
 +     * no longer affects the energy beyond the short-range cut-off,
 +     * which is a very good approximation (except for exotic settings).
 +     * (investigate how to overcome this post 4.6 - MRS)
 +     */
 +
 +    for(i=0; i<fepvals->n_lambda; i++)
 +    {                                         /* note we are iterating over fepvals here!
 +                                                 For the current lam, dlam = 0 automatically,
 +                                                 so we don't need to add anything to the
 +                                                 enerd->enerpart_lambda[0] */
 +
 +        /* we don't need to worry about dvdl contributions to the current lambda, because
 +           it's automatically zero */
 +
 +        /* first kinetic energy term */
 +        dlam = (fepvals->all_lambda[efptMASS][i] - lambda[efptMASS]);
 +
 +        enerd->enerpart_lambda[i+1] += enerd->term[F_DKDL]*dlam;
 +
 +        for (j=0;j<efptNR;j++)
 +        {
 +            if (j==efptMASS) {continue;} /* no other mass term to worry about */
 +
 +            dlam = (fepvals->all_lambda[j][i]-lambda[j]);
 +            enerd->enerpart_lambda[i+1] += dlam*enerd->dvdl_lin[j];
 +            if (debug)
 +            {
 +                fprintf(debug,"enerdiff lam %g: (%15s), non-linear %f linear %f*%f\n",
 +                        fepvals->all_lambda[j][i],efpt_names[j],
 +                        (enerd->enerpart_lambda[i+1] - enerd->enerpart_lambda[0]),
 +                        dlam,enerd->dvdl_lin[j]);
 +            }
 +        }
 +    }
 +}
 +
 +void reset_enerdata(t_grpopts *opts,
 +                    t_forcerec *fr,gmx_bool bNS,
 +                    gmx_enerdata_t *enerd,
 +                    gmx_bool bMaster)
 +{
 +    gmx_bool bKeepLR;
 +    int  i,j;
 +
 +    /* First reset all energy components, except for the long range terms
 +     * on the master at non neighbor search steps, since the long range
 +     * terms have already been summed at the last neighbor search step.
 +     */
 +    bKeepLR = (fr->bTwinRange && !bNS);
 +    for(i=0; (i<egNR); i++) {
 +        if (!(bKeepLR && bMaster && (i == egCOULLR || i == egLJLR))) {
 +            for(j=0; (j<enerd->grpp.nener); j++)
 +                enerd->grpp.ener[i][j] = 0.0;
 +        }
 +    }
 +    for (i=0;i<efptNR;i++)
 +    {
 +        enerd->dvdl_lin[i]    = 0.0;
 +        enerd->dvdl_nonlin[i] = 0.0;
 +    }
 +
 +    /* Normal potential energy components */
 +    for(i=0; (i<=F_EPOT); i++) {
 +        enerd->term[i] = 0.0;
 +    }
 +    /* Initialize the dVdlambda term with the long range contribution */
 +    /* Initialize the dvdl term with the long range contribution */
 +    enerd->term[F_DVDL]            = 0.0;
 +    enerd->term[F_DVDL_COUL]       = 0.0;
 +    enerd->term[F_DVDL_VDW]        = 0.0;
 +    enerd->term[F_DVDL_BONDED]     = 0.0;
 +    enerd->term[F_DVDL_RESTRAINT]  = 0.0;
 +    enerd->term[F_DKDL]            = 0.0;
 +    if (enerd->n_lambda > 0)
 +    {
 +        for(i=0; i<enerd->n_lambda; i++)
 +        {
 +            enerd->enerpart_lambda[i] = 0.0;
 +        }
 +    }
 +}
index 6690a5bf62be762ca9ec66309ede056bbb9f0715,0000000000000000000000000000000000000000..ebfcc53cd84331b3fcf3338b5f90b0996e9472c2
mode 100644,000000..100644
--- /dev/null
@@@ -1,2692 -1,0 +1,2693 @@@
 +/* -*- 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 <math.h>
 +#include <string.h>
 +#include <assert.h>
 +#include "sysstuff.h"
 +#include "typedefs.h"
 +#include "vec.h"
 +#include "maths.h"
 +#include "macros.h"
 +#include "smalloc.h"
 +#include "macros.h"
 +#include "gmx_fatal.h"
 +#include "gmx_fatal_collective.h"
 +#include "physics.h"
 +#include "force.h"
 +#include "tables.h"
 +#include "nonbonded.h"
 +#include "invblock.h"
 +#include "names.h"
 +#include "network.h"
 +#include "pbc.h"
 +#include "ns.h"
 +#include "mshift.h"
 +#include "txtdump.h"
 +#include "coulomb.h"
 +#include "md_support.h"
++#include "md_logging.h"
 +#include "domdec.h"
 +#include "partdec.h"
 +#include "qmmm.h"
 +#include "copyrite.h"
 +#include "mtop_util.h"
 +#include "nbnxn_search.h"
 +#include "nbnxn_atomdata.h"
 +#include "nbnxn_consts.h"
 +#include "statutil.h"
 +#include "gmx_omp_nthreads.h"
 +
 +#ifdef _MSC_VER
 +/* MSVC definition for __cpuid() */
 +#include <intrin.h>
 +#endif
 +
 +#include "types/nbnxn_cuda_types_ext.h"
 +#include "gpu_utils.h"
 +#include "nbnxn_cuda_data_mgmt.h"
 +#include "pmalloc_cuda.h"
 +
 +t_forcerec *mk_forcerec(void)
 +{
 +  t_forcerec *fr;
 +  
 +  snew(fr,1);
 +  
 +  return fr;
 +}
 +
 +#ifdef DEBUG
 +static void pr_nbfp(FILE *fp,real *nbfp,gmx_bool bBHAM,int atnr)
 +{
 +  int i,j;
 +  
 +  for(i=0; (i<atnr); i++) {
 +    for(j=0; (j<atnr); j++) {
 +      fprintf(fp,"%2d - %2d",i,j);
 +      if (bBHAM)
 +      fprintf(fp,"  a=%10g, b=%10g, c=%10g\n",BHAMA(nbfp,atnr,i,j),
 +              BHAMB(nbfp,atnr,i,j),BHAMC(nbfp,atnr,i,j)/6.0);
 +      else
 +      fprintf(fp,"  c6=%10g, c12=%10g\n",C6(nbfp,atnr,i,j)/6.0,
 +            C12(nbfp,atnr,i,j)/12.0);
 +    }
 +  }
 +}
 +#endif
 +
 +static real *mk_nbfp(const gmx_ffparams_t *idef,gmx_bool bBHAM)
 +{
 +  real *nbfp;
 +  int  i,j,k,atnr;
 +  
 +  atnr=idef->atnr;
 +  if (bBHAM) {
 +    snew(nbfp,3*atnr*atnr);
 +    for(i=k=0; (i<atnr); i++) {
 +      for(j=0; (j<atnr); j++,k++) {
 +          BHAMA(nbfp,atnr,i,j) = idef->iparams[k].bham.a;
 +          BHAMB(nbfp,atnr,i,j) = idef->iparams[k].bham.b;
 +          /* nbfp now includes the 6.0 derivative prefactor */
 +          BHAMC(nbfp,atnr,i,j) = idef->iparams[k].bham.c*6.0;
 +      }
 +    }
 +  }
 +  else {
 +    snew(nbfp,2*atnr*atnr);
 +    for(i=k=0; (i<atnr); i++) {
 +      for(j=0; (j<atnr); j++,k++) {
 +          /* nbfp now includes the 6.0/12.0 derivative prefactors */
 +          C6(nbfp,atnr,i,j)   = idef->iparams[k].lj.c6*6.0;
 +          C12(nbfp,atnr,i,j)  = idef->iparams[k].lj.c12*12.0;
 +      }
 +    }
 +  }
 +
 +  return nbfp;
 +}
 +
 +/* This routine sets fr->solvent_opt to the most common solvent in the 
 + * system, e.g. esolSPC or esolTIP4P. It will also mark each charge group in 
 + * the fr->solvent_type array with the correct type (or esolNO).
 + *
 + * Charge groups that fulfill the conditions but are not identical to the
 + * most common one will be marked as esolNO in the solvent_type array. 
 + *
 + * TIP3p is identical to SPC for these purposes, so we call it
 + * SPC in the arrays (Apologies to Bill Jorgensen ;-)
 + * 
 + * NOTE: QM particle should not
 + * become an optimized solvent. Not even if there is only one charge
 + * group in the Qm 
 + */
 +
 +typedef struct 
 +{
 +    int    model;          
 +    int    count;
 +    int    vdwtype[4];
 +    real   charge[4];
 +} solvent_parameters_t;
 +
 +static void
 +check_solvent_cg(const gmx_moltype_t   *molt,
 +                 int                   cg0,
 +                 int                   nmol,
 +                 const unsigned char   *qm_grpnr,
 +                 const t_grps          *qm_grps,
 +                 t_forcerec *          fr,
 +                 int                   *n_solvent_parameters,
 +                 solvent_parameters_t  **solvent_parameters_p,
 +                 int                   cginfo,
 +                 int                   *cg_sp)
 +{
 +    const t_blocka *  excl;
 +    t_atom            *atom;
 +    int               j,k;
 +    int               j0,j1,nj;
 +    gmx_bool              perturbed;
 +    gmx_bool              has_vdw[4];
 +    gmx_bool              match;
 +    real              tmp_charge[4];
 +    int               tmp_vdwtype[4];
 +    int               tjA;
 +    gmx_bool              qm;
 +    solvent_parameters_t *solvent_parameters;
 +
 +    /* We use a list with parameters for each solvent type. 
 +     * Every time we discover a new molecule that fulfills the basic 
 +     * conditions for a solvent we compare with the previous entries
 +     * in these lists. If the parameters are the same we just increment
 +     * the counter for that type, and otherwise we create a new type
 +     * based on the current molecule.
 +     *
 +     * Once we've finished going through all molecules we check which
 +     * solvent is most common, and mark all those molecules while we
 +     * clear the flag on all others.
 +     */   
 +
 +    solvent_parameters = *solvent_parameters_p;
 +
 +    /* Mark the cg first as non optimized */
 +    *cg_sp = -1;
 +    
 +    /* Check if this cg has no exclusions with atoms in other charge groups
 +     * and all atoms inside the charge group excluded.
 +     * We only have 3 or 4 atom solvent loops.
 +     */
 +    if (GET_CGINFO_EXCL_INTER(cginfo) ||
 +        !GET_CGINFO_EXCL_INTRA(cginfo))
 +    {
 +        return;
 +    }
 +
 +    /* Get the indices of the first atom in this charge group */
 +    j0     = molt->cgs.index[cg0];
 +    j1     = molt->cgs.index[cg0+1];
 +    
 +    /* Number of atoms in our molecule */
 +    nj     = j1 - j0;
 +
 +    if (debug) {
 +        fprintf(debug,
 +                "Moltype '%s': there are %d atoms in this charge group\n",
 +                *molt->name,nj);
 +    }
 +    
 +    /* Check if it could be an SPC (3 atoms) or TIP4p (4) water,
 +     * otherwise skip it.
 +     */
 +    if (nj<3 || nj>4)
 +    {
 +        return;
 +    }
 +    
 +    /* Check if we are doing QM on this group */
 +    qm = FALSE; 
 +    if (qm_grpnr != NULL)
 +    {
 +        for(j=j0 ; j<j1 && !qm; j++)
 +        {
 +            qm = (qm_grpnr[j] < qm_grps->nr - 1);
 +        }
 +    }
 +    /* Cannot use solvent optimization with QM */
 +    if (qm)
 +    {
 +        return;
 +    }
 +    
 +    atom = molt->atoms.atom;
 +
 +    /* Still looks like a solvent, time to check parameters */
 +    
 +    /* If it is perturbed (free energy) we can't use the solvent loops,
 +     * so then we just skip to the next molecule.
 +     */   
 +    perturbed = FALSE; 
 +    
 +    for(j=j0; j<j1 && !perturbed; j++)
 +    {
 +        perturbed = PERTURBED(atom[j]);
 +    }
 +    
 +    if (perturbed)
 +    {
 +        return;
 +    }
 +    
 +    /* Now it's only a question if the VdW and charge parameters 
 +     * are OK. Before doing the check we compare and see if they are 
 +     * identical to a possible previous solvent type.
 +     * First we assign the current types and charges.    
 +     */
 +    for(j=0; j<nj; j++)
 +    {
 +        tmp_vdwtype[j] = atom[j0+j].type;
 +        tmp_charge[j]  = atom[j0+j].q;
 +    } 
 +    
 +    /* Does it match any previous solvent type? */
 +    for(k=0 ; k<*n_solvent_parameters; k++)
 +    {
 +        match = TRUE;
 +        
 +        
 +        /* We can only match SPC with 3 atoms and TIP4p with 4 atoms */
 +        if( (solvent_parameters[k].model==esolSPC   && nj!=3)  ||
 +            (solvent_parameters[k].model==esolTIP4P && nj!=4) )
 +            match = FALSE;
 +        
 +        /* Check that types & charges match for all atoms in molecule */
 +        for(j=0 ; j<nj && match==TRUE; j++)
 +        {                     
 +            if (tmp_vdwtype[j] != solvent_parameters[k].vdwtype[j])
 +            {
 +                match = FALSE;
 +            }
 +            if(tmp_charge[j] != solvent_parameters[k].charge[j])
 +            {
 +                match = FALSE;
 +            }
 +        }
 +        if (match == TRUE)
 +        {
 +            /* Congratulations! We have a matched solvent.
 +             * Flag it with this type for later processing.
 +             */
 +            *cg_sp = k;
 +            solvent_parameters[k].count += nmol;
 +
 +            /* We are done with this charge group */
 +            return;
 +        }
 +    }
 +    
 +    /* If we get here, we have a tentative new solvent type.
 +     * Before we add it we must check that it fulfills the requirements
 +     * of the solvent optimized loops. First determine which atoms have
 +     * VdW interactions.   
 +     */
 +    for(j=0; j<nj; j++) 
 +    {
 +        has_vdw[j] = FALSE;
 +        tjA        = tmp_vdwtype[j];
 +        
 +        /* Go through all other tpes and see if any have non-zero
 +         * VdW parameters when combined with this one.
 +         */   
 +        for(k=0; k<fr->ntype && (has_vdw[j]==FALSE); k++)
 +        {
 +            /* We already checked that the atoms weren't perturbed,
 +             * so we only need to check state A now.
 +             */ 
 +            if (fr->bBHAM) 
 +            {
 +                has_vdw[j] = (has_vdw[j] || 
 +                              (BHAMA(fr->nbfp,fr->ntype,tjA,k) != 0.0) ||
 +                              (BHAMB(fr->nbfp,fr->ntype,tjA,k) != 0.0) ||
 +                              (BHAMC(fr->nbfp,fr->ntype,tjA,k) != 0.0));
 +            }
 +            else
 +            {
 +                /* Standard LJ */
 +                has_vdw[j] = (has_vdw[j] || 
 +                              (C6(fr->nbfp,fr->ntype,tjA,k)  != 0.0) ||
 +                              (C12(fr->nbfp,fr->ntype,tjA,k) != 0.0));
 +            }
 +        }
 +    }
 +    
 +    /* Now we know all we need to make the final check and assignment. */
 +    if (nj == 3)
 +    {
 +        /* So, is it an SPC?
 +         * For this we require thatn all atoms have charge, 
 +         * the charges on atom 2 & 3 should be the same, and only
 +         * atom 1 might have VdW.
 +         */
 +        if (has_vdw[1] == FALSE &&
 +            has_vdw[2] == FALSE &&
 +            tmp_charge[0]  != 0 &&
 +            tmp_charge[1]  != 0 &&
 +            tmp_charge[2]  == tmp_charge[1])
 +        {
 +            srenew(solvent_parameters,*n_solvent_parameters+1);
 +            solvent_parameters[*n_solvent_parameters].model = esolSPC;
 +            solvent_parameters[*n_solvent_parameters].count = nmol;
 +            for(k=0;k<3;k++)
 +            {
 +                solvent_parameters[*n_solvent_parameters].vdwtype[k] = tmp_vdwtype[k];
 +                solvent_parameters[*n_solvent_parameters].charge[k]  = tmp_charge[k];
 +            }
 +
 +            *cg_sp = *n_solvent_parameters;
 +            (*n_solvent_parameters)++;
 +        }
 +    }
 +    else if (nj==4)
 +    {
 +        /* Or could it be a TIP4P?
 +         * For this we require thatn atoms 2,3,4 have charge, but not atom 1. 
 +         * Only atom 1 mght have VdW.
 +         */
 +        if(has_vdw[1] == FALSE &&
 +           has_vdw[2] == FALSE &&
 +           has_vdw[3] == FALSE &&
 +           tmp_charge[0]  == 0 &&
 +           tmp_charge[1]  != 0 &&
 +           tmp_charge[2]  == tmp_charge[1] &&
 +           tmp_charge[3]  != 0)
 +        {
 +            srenew(solvent_parameters,*n_solvent_parameters+1);
 +            solvent_parameters[*n_solvent_parameters].model = esolTIP4P;
 +            solvent_parameters[*n_solvent_parameters].count = nmol;
 +            for(k=0;k<4;k++)
 +            {
 +                solvent_parameters[*n_solvent_parameters].vdwtype[k] = tmp_vdwtype[k];
 +                solvent_parameters[*n_solvent_parameters].charge[k]  = tmp_charge[k];
 +            }
 +            
 +            *cg_sp = *n_solvent_parameters;
 +            (*n_solvent_parameters)++;
 +        }
 +    }
 +
 +    *solvent_parameters_p = solvent_parameters;
 +}
 +
 +static void
 +check_solvent(FILE *                fp,
 +              const gmx_mtop_t *    mtop,
 +              t_forcerec *          fr,
 +              cginfo_mb_t           *cginfo_mb)
 +{
 +    const t_block *   cgs;
 +    const t_block *   mols;
 +    const gmx_moltype_t *molt;
 +    int               mb,mol,cg_mol,at_offset,cg_offset,am,cgm,i,nmol_ch,nmol;
 +    int               n_solvent_parameters;
 +    solvent_parameters_t *solvent_parameters;
 +    int               **cg_sp;
 +    int               bestsp,bestsol;
 +
 +    if (debug)
 +    {
 +        fprintf(debug,"Going to determine what solvent types we have.\n");
 +    }
 +
 +    mols = &mtop->mols;
 +
 +    n_solvent_parameters = 0;
 +    solvent_parameters = NULL;
 +    /* Allocate temporary array for solvent type */
 +    snew(cg_sp,mtop->nmolblock);
 +
 +    cg_offset = 0;
 +    at_offset = 0;
 +    for(mb=0; mb<mtop->nmolblock; mb++)
 +    {
 +        molt = &mtop->moltype[mtop->molblock[mb].type];
 +        cgs  = &molt->cgs;
 +        /* Here we have to loop over all individual molecules
 +         * because we need to check for QMMM particles.
 +         */
 +        snew(cg_sp[mb],cginfo_mb[mb].cg_mod);
 +        nmol_ch = cginfo_mb[mb].cg_mod/cgs->nr;
 +        nmol    = mtop->molblock[mb].nmol/nmol_ch;
 +        for(mol=0; mol<nmol_ch; mol++)
 +        {
 +            cgm = mol*cgs->nr;
 +            am  = mol*cgs->index[cgs->nr];
 +            for(cg_mol=0; cg_mol<cgs->nr; cg_mol++)
 +            {
 +                check_solvent_cg(molt,cg_mol,nmol,
 +                                 mtop->groups.grpnr[egcQMMM] ?
 +                                 mtop->groups.grpnr[egcQMMM]+at_offset+am : 0,
 +                                 &mtop->groups.grps[egcQMMM],
 +                                 fr,
 +                                 &n_solvent_parameters,&solvent_parameters,
 +                                 cginfo_mb[mb].cginfo[cgm+cg_mol],
 +                                 &cg_sp[mb][cgm+cg_mol]);
 +            }
 +        }
 +        cg_offset += cgs->nr;
 +        at_offset += cgs->index[cgs->nr];
 +    }
 +
 +    /* Puh! We finished going through all charge groups.
 +     * Now find the most common solvent model.
 +     */   
 +    
 +    /* Most common solvent this far */
 +    bestsp = -2;
 +    for(i=0;i<n_solvent_parameters;i++)
 +    {
 +        if (bestsp == -2 ||
 +            solvent_parameters[i].count > solvent_parameters[bestsp].count)
 +        {
 +            bestsp = i;
 +        }
 +    }
 +    
 +    if (bestsp >= 0)
 +    {
 +        bestsol = solvent_parameters[bestsp].model;
 +    }
 +    else
 +    {
 +        bestsol = esolNO;
 +    }
 +    
 +#ifdef DISABLE_WATER_NLIST
 +      bestsol = esolNO;
 +#endif
 +
 +    fr->nWatMol = 0;
 +    for(mb=0; mb<mtop->nmolblock; mb++)
 +    {
 +        cgs = &mtop->moltype[mtop->molblock[mb].type].cgs;
 +        nmol = (mtop->molblock[mb].nmol*cgs->nr)/cginfo_mb[mb].cg_mod;
 +        for(i=0; i<cginfo_mb[mb].cg_mod; i++)
 +        {
 +            if (cg_sp[mb][i] == bestsp)
 +            {
 +                SET_CGINFO_SOLOPT(cginfo_mb[mb].cginfo[i],bestsol);
 +                fr->nWatMol += nmol;
 +            }
 +            else
 +            {
 +                SET_CGINFO_SOLOPT(cginfo_mb[mb].cginfo[i],esolNO);
 +            }
 +        }
 +        sfree(cg_sp[mb]);
 +    }
 +    sfree(cg_sp);
 +    
 +    if (bestsol != esolNO && fp!=NULL)
 +    {
 +        fprintf(fp,"\nEnabling %s-like water optimization for %d molecules.\n\n",
 +                esol_names[bestsol],
 +                solvent_parameters[bestsp].count);
 +    }
 +
 +    sfree(solvent_parameters);
 +    fr->solvent_opt = bestsol;
 +}
 +
 +enum { acNONE=0, acCONSTRAINT, acSETTLE };
 +
 +static cginfo_mb_t *init_cginfo_mb(FILE *fplog,const gmx_mtop_t *mtop,
 +                                   t_forcerec *fr,gmx_bool bNoSolvOpt,
 +                                   gmx_bool *bExcl_IntraCGAll_InterCGNone)
 +{
 +    const t_block *cgs;
 +    const t_blocka *excl;
 +    const gmx_moltype_t *molt;
 +    const gmx_molblock_t *molb;
 +    cginfo_mb_t *cginfo_mb;
 +    gmx_bool *type_VDW;
 +    int  *cginfo;
 +    int  cg_offset,a_offset,cgm,am;
 +    int  mb,m,ncg_tot,cg,a0,a1,gid,ai,j,aj,excl_nalloc;
 +    int  *a_con;
 +    int  ftype;
 +    int  ia;
 +    gmx_bool bId,*bExcl,bExclIntraAll,bExclInter,bHaveVDW,bHaveQ;
 +
 +    ncg_tot = ncg_mtop(mtop);
 +    snew(cginfo_mb,mtop->nmolblock);
 +
 +    snew(type_VDW,fr->ntype);
 +    for(ai=0; ai<fr->ntype; ai++)
 +    {
 +        type_VDW[ai] = FALSE;
 +        for(j=0; j<fr->ntype; j++)
 +        {
 +            type_VDW[ai] = type_VDW[ai] ||
 +                fr->bBHAM ||
 +                C6(fr->nbfp,fr->ntype,ai,j) != 0 ||
 +                C12(fr->nbfp,fr->ntype,ai,j) != 0;
 +        }
 +    }
 +
 +    *bExcl_IntraCGAll_InterCGNone = TRUE;
 +
 +    excl_nalloc = 10;
 +    snew(bExcl,excl_nalloc);
 +    cg_offset = 0;
 +    a_offset  = 0;
 +    for(mb=0; mb<mtop->nmolblock; mb++)
 +    {
 +        molb = &mtop->molblock[mb];
 +        molt = &mtop->moltype[molb->type];
 +        cgs  = &molt->cgs;
 +        excl = &molt->excls;
 +
 +        /* Check if the cginfo is identical for all molecules in this block.
 +         * If so, we only need an array of the size of one molecule.
 +         * Otherwise we make an array of #mol times #cgs per molecule.
 +         */
 +        bId = TRUE;
 +        am = 0;
 +        for(m=0; m<molb->nmol; m++)
 +        {
 +            am = m*cgs->index[cgs->nr];
 +            for(cg=0; cg<cgs->nr; cg++)
 +            {
 +                a0 = cgs->index[cg];
 +                a1 = cgs->index[cg+1];
 +                if (ggrpnr(&mtop->groups,egcENER,a_offset+am+a0) !=
 +                    ggrpnr(&mtop->groups,egcENER,a_offset   +a0))
 +                {
 +                    bId = FALSE;
 +                }
 +                if (mtop->groups.grpnr[egcQMMM] != NULL)
 +                {
 +                    for(ai=a0; ai<a1; ai++)
 +                    {
 +                        if (mtop->groups.grpnr[egcQMMM][a_offset+am+ai] !=
 +                            mtop->groups.grpnr[egcQMMM][a_offset   +ai])
 +                        {
 +                            bId = FALSE;
 +                        }
 +                    }
 +                }
 +            }
 +        }
 +
 +        cginfo_mb[mb].cg_start = cg_offset;
 +        cginfo_mb[mb].cg_end   = cg_offset + molb->nmol*cgs->nr;
 +        cginfo_mb[mb].cg_mod   = (bId ? 1 : molb->nmol)*cgs->nr;
 +        snew(cginfo_mb[mb].cginfo,cginfo_mb[mb].cg_mod);
 +        cginfo = cginfo_mb[mb].cginfo;
 +
 +        /* Set constraints flags for constrained atoms */
 +        snew(a_con,molt->atoms.nr);
 +        for(ftype=0; ftype<F_NRE; ftype++)
 +        {
 +            if (interaction_function[ftype].flags & IF_CONSTRAINT)
 +            {
 +                int nral;
 +
 +                nral = NRAL(ftype);
 +                for(ia=0; ia<molt->ilist[ftype].nr; ia+=1+nral)
 +                {
 +                    int a;
 +
 +                    for(a=0; a<nral; a++)
 +                    {
 +                        a_con[molt->ilist[ftype].iatoms[ia+1+a]] =
 +                            (ftype == F_SETTLE ? acSETTLE : acCONSTRAINT);
 +                    }
 +                }
 +            }
 +        }
 +
 +        for(m=0; m<(bId ? 1 : molb->nmol); m++)
 +        {
 +            cgm = m*cgs->nr;
 +            am  = m*cgs->index[cgs->nr];
 +            for(cg=0; cg<cgs->nr; cg++)
 +            {
 +                a0 = cgs->index[cg];
 +                a1 = cgs->index[cg+1];
 +
 +                /* Store the energy group in cginfo */
 +                gid = ggrpnr(&mtop->groups,egcENER,a_offset+am+a0);
 +                SET_CGINFO_GID(cginfo[cgm+cg],gid);
 +                
 +                /* Check the intra/inter charge group exclusions */
 +                if (a1-a0 > excl_nalloc) {
 +                    excl_nalloc = a1 - a0;
 +                    srenew(bExcl,excl_nalloc);
 +                }
 +                /* bExclIntraAll: all intra cg interactions excluded
 +                 * bExclInter:    any inter cg interactions excluded
 +                 */
 +                bExclIntraAll = TRUE;
 +                bExclInter    = FALSE;
 +                bHaveVDW      = FALSE;
 +                bHaveQ        = FALSE;
 +                for(ai=a0; ai<a1; ai++)
 +                {
 +                    /* Check VDW and electrostatic interactions */
 +                    bHaveVDW = bHaveVDW || (type_VDW[molt->atoms.atom[ai].type] ||
 +                                            type_VDW[molt->atoms.atom[ai].typeB]);
 +                    bHaveQ  = bHaveQ    || (molt->atoms.atom[ai].q != 0 ||
 +                                            molt->atoms.atom[ai].qB != 0);
 +
 +                    /* Clear the exclusion list for atom ai */
 +                    for(aj=a0; aj<a1; aj++)
 +                    {
 +                        bExcl[aj-a0] = FALSE;
 +                    }
 +                    /* Loop over all the exclusions of atom ai */
 +                    for(j=excl->index[ai]; j<excl->index[ai+1]; j++)
 +                    {
 +                        aj = excl->a[j];
 +                        if (aj < a0 || aj >= a1)
 +                        {
 +                            bExclInter = TRUE;
 +                        }
 +                        else
 +                        {
 +                            bExcl[aj-a0] = TRUE;
 +                        }
 +                    }
 +                    /* Check if ai excludes a0 to a1 */
 +                    for(aj=a0; aj<a1; aj++)
 +                    {
 +                        if (!bExcl[aj-a0])
 +                        {
 +                            bExclIntraAll = FALSE;
 +                        }
 +                    }
 +
 +                    switch (a_con[ai])
 +                    {
 +                    case acCONSTRAINT:
 +                        SET_CGINFO_CONSTR(cginfo[cgm+cg]);
 +                        break;
 +                    case acSETTLE:
 +                        SET_CGINFO_SETTLE(cginfo[cgm+cg]);
 +                        break;
 +                    default:
 +                        break;
 +                    }
 +                }
 +                if (bExclIntraAll)
 +                {
 +                    SET_CGINFO_EXCL_INTRA(cginfo[cgm+cg]);
 +                }
 +                if (bExclInter)
 +                {
 +                    SET_CGINFO_EXCL_INTER(cginfo[cgm+cg]);
 +                }
 +                if (a1 - a0 > MAX_CHARGEGROUP_SIZE)
 +                {
 +                    /* The size in cginfo is currently only read with DD */
 +                    gmx_fatal(FARGS,"A charge group has size %d which is larger than the limit of %d atoms",a1-a0,MAX_CHARGEGROUP_SIZE);
 +                }
 +                if (bHaveVDW)
 +                {
 +                    SET_CGINFO_HAS_VDW(cginfo[cgm+cg]);
 +                }
 +                if (bHaveQ)
 +                {
 +                    SET_CGINFO_HAS_Q(cginfo[cgm+cg]);
 +                }
 +                /* Store the charge group size */
 +                SET_CGINFO_NATOMS(cginfo[cgm+cg],a1-a0);
 +
 +                if (!bExclIntraAll || bExclInter)
 +                {
 +                    *bExcl_IntraCGAll_InterCGNone = FALSE;
 +                }
 +            }
 +        }
 +
 +        sfree(a_con);
 +
 +        cg_offset += molb->nmol*cgs->nr;
 +        a_offset  += molb->nmol*cgs->index[cgs->nr];
 +    }
 +    sfree(bExcl);
 +    
 +    /* the solvent optimizer is called after the QM is initialized,
 +     * because we don't want to have the QM subsystemto become an
 +     * optimized solvent
 +     */
 +
 +    check_solvent(fplog,mtop,fr,cginfo_mb);
 +    
 +    if (getenv("GMX_NO_SOLV_OPT"))
 +    {
 +        if (fplog)
 +        {
 +            fprintf(fplog,"Found environment variable GMX_NO_SOLV_OPT.\n"
 +                    "Disabling all solvent optimization\n");
 +        }
 +        fr->solvent_opt = esolNO;
 +    }
 +    if (bNoSolvOpt)
 +    {
 +        fr->solvent_opt = esolNO;
 +    }
 +    if (!fr->solvent_opt)
 +    {
 +        for(mb=0; mb<mtop->nmolblock; mb++)
 +        {
 +            for(cg=0; cg<cginfo_mb[mb].cg_mod; cg++)
 +            {
 +                SET_CGINFO_SOLOPT(cginfo_mb[mb].cginfo[cg],esolNO);
 +            }
 +        }
 +    }
 +    
 +    return cginfo_mb;
 +}
 +
 +static int *cginfo_expand(int nmb,cginfo_mb_t *cgi_mb)
 +{
 +    int ncg,mb,cg;
 +    int *cginfo;
 +
 +    ncg = cgi_mb[nmb-1].cg_end;
 +    snew(cginfo,ncg);
 +    mb = 0;
 +    for(cg=0; cg<ncg; cg++)
 +    {
 +        while (cg >= cgi_mb[mb].cg_end)
 +        {
 +            mb++;
 +        }
 +        cginfo[cg] =
 +            cgi_mb[mb].cginfo[(cg - cgi_mb[mb].cg_start) % cgi_mb[mb].cg_mod];
 +    }
 +
 +    return cginfo;
 +}
 +
 +static void set_chargesum(FILE *log,t_forcerec *fr,const gmx_mtop_t *mtop)
 +{
 +    double qsum,q2sum,q;
 +    int    mb,nmol,i;
 +    const t_atoms *atoms;
 +    
 +    qsum  = 0;
 +    q2sum = 0;
 +    for(mb=0; mb<mtop->nmolblock; mb++)
 +    {
 +        nmol  = mtop->molblock[mb].nmol;
 +        atoms = &mtop->moltype[mtop->molblock[mb].type].atoms;
 +        for(i=0; i<atoms->nr; i++)
 +        {
 +            q = atoms->atom[i].q;
 +            qsum  += nmol*q;
 +            q2sum += nmol*q*q;
 +        }
 +    }
 +    fr->qsum[0]  = qsum;
 +    fr->q2sum[0] = q2sum;
 +    if (fr->efep != efepNO)
 +    {
 +        qsum  = 0;
 +        q2sum = 0;
 +        for(mb=0; mb<mtop->nmolblock; mb++)
 +        {
 +            nmol  = mtop->molblock[mb].nmol;
 +            atoms = &mtop->moltype[mtop->molblock[mb].type].atoms;
 +            for(i=0; i<atoms->nr; i++)
 +            {
 +                q = atoms->atom[i].qB;
 +                qsum  += nmol*q;
 +                q2sum += nmol*q*q;
 +            }
 +            fr->qsum[1]  = qsum;
 +            fr->q2sum[1] = q2sum;
 +        }
 +    }
 +    else
 +    {
 +        fr->qsum[1]  = fr->qsum[0];
 +        fr->q2sum[1] = fr->q2sum[0];
 +    }
 +    if (log) {
 +        if (fr->efep == efepNO)
 +            fprintf(log,"System total charge: %.3f\n",fr->qsum[0]);
 +        else
 +            fprintf(log,"System total charge, top. A: %.3f top. B: %.3f\n",
 +                    fr->qsum[0],fr->qsum[1]);
 +    }
 +}
 +
 +void update_forcerec(FILE *log,t_forcerec *fr,matrix box)
 +{
 +    if (fr->eeltype == eelGRF)
 +    {
 +        calc_rffac(NULL,fr->eeltype,fr->epsilon_r,fr->epsilon_rf,
 +                   fr->rcoulomb,fr->temp,fr->zsquare,box,
 +                   &fr->kappa,&fr->k_rf,&fr->c_rf);
 +    }
 +}
 +
 +void set_avcsixtwelve(FILE *fplog,t_forcerec *fr,const gmx_mtop_t *mtop)
 +{
 +    const t_atoms *atoms,*atoms_tpi;
 +    const t_blocka *excl;
 +    int    mb,nmol,nmolc,i,j,tpi,tpj,j1,j2,k,n,nexcl,q;
 +#if (defined SIZEOF_LONG_LONG_INT) && (SIZEOF_LONG_LONG_INT >= 8)    
 +    long long int  npair,npair_ij,tmpi,tmpj;
 +#else
 +    double npair, npair_ij,tmpi,tmpj;
 +#endif
 +    double csix,ctwelve;
 +    int    ntp,*typecount;
 +    gmx_bool   bBHAM;
 +    real   *nbfp;
 +
 +    ntp = fr->ntype;
 +    bBHAM = fr->bBHAM;
 +    nbfp = fr->nbfp;
 +    
 +    for(q=0; q<(fr->efep==efepNO ? 1 : 2); q++) {
 +        csix = 0;
 +        ctwelve = 0;
 +        npair = 0;
 +        nexcl = 0;
 +        if (!fr->n_tpi) {
 +            /* Count the types so we avoid natoms^2 operations */
 +            snew(typecount,ntp);
 +            for(mb=0; mb<mtop->nmolblock; mb++) {
 +                nmol  = mtop->molblock[mb].nmol;
 +                atoms = &mtop->moltype[mtop->molblock[mb].type].atoms;
 +                for(i=0; i<atoms->nr; i++) {
 +                    if (q == 0)
 +                    {
 +                        tpi = atoms->atom[i].type;
 +                    }
 +                    else
 +                    {
 +                        tpi = atoms->atom[i].typeB;
 +                    }
 +                    typecount[tpi] += nmol;
 +                }
 +            }
 +            for(tpi=0; tpi<ntp; tpi++) {
 +                for(tpj=tpi; tpj<ntp; tpj++) {
 +                    tmpi = typecount[tpi];
 +                    tmpj = typecount[tpj];
 +                    if (tpi != tpj)
 +                    {
 +                        npair_ij = tmpi*tmpj;
 +                    }
 +                    else
 +                    {
 +                        npair_ij = tmpi*(tmpi - 1)/2;
 +                    }
 +                    if (bBHAM) {
 +                        /* nbfp now includes the 6.0 derivative prefactor */
 +                        csix    += npair_ij*BHAMC(nbfp,ntp,tpi,tpj)/6.0;
 +                    } else {
 +                        /* nbfp now includes the 6.0/12.0 derivative prefactors */
 +                        csix    += npair_ij*   C6(nbfp,ntp,tpi,tpj)/6.0;
 +                        ctwelve += npair_ij*  C12(nbfp,ntp,tpi,tpj)/12.0;
 +                    }
 +                    npair += npair_ij;
 +                }
 +            }
 +            sfree(typecount);
 +            /* Subtract the excluded pairs.
 +             * The main reason for substracting exclusions is that in some cases
 +             * some combinations might never occur and the parameters could have
 +             * any value. These unused values should not influence the dispersion
 +             * correction.
 +             */
 +            for(mb=0; mb<mtop->nmolblock; mb++) {
 +                nmol  = mtop->molblock[mb].nmol;
 +                atoms = &mtop->moltype[mtop->molblock[mb].type].atoms;
 +                excl  = &mtop->moltype[mtop->molblock[mb].type].excls;
 +                for(i=0; (i<atoms->nr); i++) {
 +                    if (q == 0)
 +                    {
 +                        tpi = atoms->atom[i].type;
 +                    }
 +                    else
 +                    {
 +                        tpi = atoms->atom[i].typeB;
 +                    }
 +                    j1  = excl->index[i];
 +                    j2  = excl->index[i+1];
 +                    for(j=j1; j<j2; j++) {
 +                        k = excl->a[j];
 +                        if (k > i)
 +                        {
 +                            if (q == 0)
 +                            {
 +                                tpj = atoms->atom[k].type;
 +                            }
 +                            else
 +                            {
 +                                tpj = atoms->atom[k].typeB;
 +                            }
 +                            if (bBHAM) {
 +                                /* nbfp now includes the 6.0 derivative prefactor */
 +                               csix -= nmol*BHAMC(nbfp,ntp,tpi,tpj)/6.0;
 +                            } else {
 +                                /* nbfp now includes the 6.0/12.0 derivative prefactors */
 +                                csix    -= nmol*C6 (nbfp,ntp,tpi,tpj)/6.0;
 +                                ctwelve -= nmol*C12(nbfp,ntp,tpi,tpj)/12.0;
 +                            }
 +                            nexcl += nmol;
 +                        }
 +                    }
 +                }
 +            }
 +        } else {
 +            /* Only correct for the interaction of the test particle
 +             * with the rest of the system.
 +             */
 +            atoms_tpi =
 +                &mtop->moltype[mtop->molblock[mtop->nmolblock-1].type].atoms;
 +
 +            npair = 0;
 +            for(mb=0; mb<mtop->nmolblock; mb++) {
 +                nmol  = mtop->molblock[mb].nmol;
 +                atoms = &mtop->moltype[mtop->molblock[mb].type].atoms;
 +                for(j=0; j<atoms->nr; j++) {
 +                    nmolc = nmol;
 +                    /* Remove the interaction of the test charge group
 +                     * with itself.
 +                     */
 +                    if (mb == mtop->nmolblock-1)
 +                    {
 +                        nmolc--;
 +                        
 +                        if (mb == 0 && nmol == 1)
 +                        {
 +                            gmx_fatal(FARGS,"Old format tpr with TPI, please generate a new tpr file");
 +                        }
 +                    }
 +                    if (q == 0)
 +                    {
 +                        tpj = atoms->atom[j].type;
 +                    }
 +                    else
 +                    {
 +                        tpj = atoms->atom[j].typeB;
 +                    }
 +                    for(i=0; i<fr->n_tpi; i++)
 +                    {
 +                        if (q == 0)
 +                        {
 +                            tpi = atoms_tpi->atom[i].type;
 +                        }
 +                        else
 +                        {
 +                            tpi = atoms_tpi->atom[i].typeB;
 +                        }
 +                        if (bBHAM)
 +                        {
 +                            /* nbfp now includes the 6.0 derivative prefactor */
 +                            csix    += nmolc*BHAMC(nbfp,ntp,tpi,tpj)/6.0;
 +                        }
 +                        else
 +                        {
 +                            /* nbfp now includes the 6.0/12.0 derivative prefactors */
 +                            csix    += nmolc*C6 (nbfp,ntp,tpi,tpj)/6.0;
 +                            ctwelve += nmolc*C12(nbfp,ntp,tpi,tpj)/12.0;
 +                        }
 +                        npair += nmolc;
 +                    }
 +                }
 +            }
 +        }
 +        if (npair - nexcl <= 0 && fplog) {
 +            fprintf(fplog,"\nWARNING: There are no atom pairs for dispersion correction\n\n");
 +            csix     = 0;
 +            ctwelve  = 0;
 +        } else {
 +            csix    /= npair - nexcl;
 +            ctwelve /= npair - nexcl;
 +        }
 +        if (debug) {
 +            fprintf(debug,"Counted %d exclusions\n",nexcl);
 +            fprintf(debug,"Average C6 parameter is: %10g\n",(double)csix);
 +            fprintf(debug,"Average C12 parameter is: %10g\n",(double)ctwelve);
 +        }
 +        fr->avcsix[q]    = csix;
 +        fr->avctwelve[q] = ctwelve;
 +    }
 +    if (fplog != NULL)
 +    {
 +        if (fr->eDispCorr == edispcAllEner ||
 +            fr->eDispCorr == edispcAllEnerPres)
 +        {
 +            fprintf(fplog,"Long Range LJ corr.: <C6> %10.4e, <C12> %10.4e\n",
 +                    fr->avcsix[0],fr->avctwelve[0]);
 +        }
 +        else
 +        {
 +            fprintf(fplog,"Long Range LJ corr.: <C6> %10.4e\n",fr->avcsix[0]);
 +        }
 +    }
 +}
 +
 +
 +static void set_bham_b_max(FILE *fplog,t_forcerec *fr,
 +                           const gmx_mtop_t *mtop)
 +{
 +    const t_atoms *at1,*at2;
 +    int  mt1,mt2,i,j,tpi,tpj,ntypes;
 +    real b,bmin;
 +    real *nbfp;
 +
 +    if (fplog)
 +    {
 +        fprintf(fplog,"Determining largest Buckingham b parameter for table\n");
 +    }
 +    nbfp   = fr->nbfp;
 +    ntypes = fr->ntype;
 +    
 +    bmin           = -1;
 +    fr->bham_b_max = 0;
 +    for(mt1=0; mt1<mtop->nmoltype; mt1++)
 +    {
 +        at1 = &mtop->moltype[mt1].atoms;
 +        for(i=0; (i<at1->nr); i++)
 +        {
 +            tpi = at1->atom[i].type;
 +            if (tpi >= ntypes)
 +                gmx_fatal(FARGS,"Atomtype[%d] = %d, maximum = %d",i,tpi,ntypes);
 +            
 +            for(mt2=mt1; mt2<mtop->nmoltype; mt2++)
 +            {
 +                at2 = &mtop->moltype[mt2].atoms;
 +                for(j=0; (j<at2->nr); j++) {
 +                    tpj = at2->atom[j].type;
 +                    if (tpj >= ntypes)
 +                    {
 +                        gmx_fatal(FARGS,"Atomtype[%d] = %d, maximum = %d",j,tpj,ntypes);
 +                    }
 +                    b = BHAMB(nbfp,ntypes,tpi,tpj);
 +                    if (b > fr->bham_b_max)
 +                    {
 +                        fr->bham_b_max = b;
 +                    }
 +                    if ((b < bmin) || (bmin==-1))
 +                    {
 +                        bmin = b;
 +                    }
 +                }
 +            }
 +        }
 +    }
 +    if (fplog)
 +    {
 +        fprintf(fplog,"Buckingham b parameters, min: %g, max: %g\n",
 +                bmin,fr->bham_b_max);
 +    }
 +}
 +
 +static void make_nbf_tables(FILE *fp,const output_env_t oenv,
 +                            t_forcerec *fr,real rtab,
 +                            const t_commrec *cr,
 +                            const char *tabfn,char *eg1,char *eg2,
 +                            t_nblists *nbl)
 +{
 +    char buf[STRLEN];
 +    int i,j;
 +
 +    if (tabfn == NULL) {
 +        if (debug)
 +            fprintf(debug,"No table file name passed, can not read table, can not do non-bonded interactions\n");
 +        return;
 +    }
 +
 +    sprintf(buf,"%s",tabfn);
 +    if (eg1 && eg2)
 +    /* Append the two energy group names */
 +        sprintf(buf + strlen(tabfn) - strlen(ftp2ext(efXVG)) - 1,"_%s_%s.%s",
 +                eg1,eg2,ftp2ext(efXVG));
 +    nbl->table_elec_vdw = make_tables(fp,oenv,fr,MASTER(cr),buf,rtab,0);
 +    /* Copy the contents of the table to separate coulomb and LJ tables too,
 +     * to improve cache performance.
 +     */
 +    /* For performance reasons we want
 +     * the table data to be aligned to 16-byte. The pointers could be freed
 +     * but currently aren't.
 +     */
 +    nbl->table_elec.interaction = GMX_TABLE_INTERACTION_ELEC;
 +    nbl->table_elec.format = nbl->table_elec_vdw.format;
 +    nbl->table_elec.r = nbl->table_elec_vdw.r;
 +    nbl->table_elec.n = nbl->table_elec_vdw.n;
 +    nbl->table_elec.scale = nbl->table_elec_vdw.scale;
 +    nbl->table_elec.scale_exp = nbl->table_elec_vdw.scale_exp;
 +    nbl->table_elec.formatsize = nbl->table_elec_vdw.formatsize;
 +    nbl->table_elec.ninteractions = 1;
 +    nbl->table_elec.stride = nbl->table_elec.formatsize * nbl->table_elec.ninteractions;
 +    snew_aligned(nbl->table_elec.data,nbl->table_elec.stride*(nbl->table_elec.n+1),16);
 +
 +    nbl->table_vdw.interaction = GMX_TABLE_INTERACTION_VDWREP_VDWDISP;
 +    nbl->table_vdw.format = nbl->table_elec_vdw.format;
 +    nbl->table_vdw.r = nbl->table_elec_vdw.r;
 +    nbl->table_vdw.n = nbl->table_elec_vdw.n;
 +    nbl->table_vdw.scale = nbl->table_elec_vdw.scale;
 +    nbl->table_vdw.scale_exp = nbl->table_elec_vdw.scale_exp;
 +    nbl->table_vdw.formatsize = nbl->table_elec_vdw.formatsize;
 +    nbl->table_vdw.ninteractions = 2;
 +    nbl->table_vdw.stride = nbl->table_vdw.formatsize * nbl->table_vdw.ninteractions;
 +    snew_aligned(nbl->table_vdw.data,nbl->table_vdw.stride*(nbl->table_vdw.n+1),16);
 +
 +    for(i=0; i<=nbl->table_elec_vdw.n; i++)
 +    {
 +        for(j=0; j<4; j++)
 +            nbl->table_elec.data[4*i+j] = nbl->table_elec_vdw.data[12*i+j];
 +        for(j=0; j<8; j++)
 +            nbl->table_vdw.data[8*i+j] = nbl->table_elec_vdw.data[12*i+4+j];
 +    }
 +}
 +
 +static void count_tables(int ftype1,int ftype2,const gmx_mtop_t *mtop,
 +                         int *ncount,int **count)
 +{
 +    const gmx_moltype_t *molt;
 +    const t_ilist *il;
 +    int mt,ftype,stride,i,j,tabnr;
 +    
 +    for(mt=0; mt<mtop->nmoltype; mt++)
 +    {
 +        molt = &mtop->moltype[mt];
 +        for(ftype=0; ftype<F_NRE; ftype++)
 +        {
 +            if (ftype == ftype1 || ftype == ftype2) {
 +                il = &molt->ilist[ftype];
 +                stride = 1 + NRAL(ftype);
 +                for(i=0; i<il->nr; i+=stride) {
 +                    tabnr = mtop->ffparams.iparams[il->iatoms[i]].tab.table;
 +                    if (tabnr < 0)
 +                        gmx_fatal(FARGS,"A bonded table number is smaller than 0: %d\n",tabnr);
 +                    if (tabnr >= *ncount) {
 +                        srenew(*count,tabnr+1);
 +                        for(j=*ncount; j<tabnr+1; j++)
 +                            (*count)[j] = 0;
 +                        *ncount = tabnr+1;
 +                    }
 +                    (*count)[tabnr]++;
 +                }
 +            }
 +        }
 +    }
 +}
 +
 +static bondedtable_t *make_bonded_tables(FILE *fplog,
 +                                         int ftype1,int ftype2,
 +                                         const gmx_mtop_t *mtop,
 +                                         const char *basefn,const char *tabext)
 +{
 +    int  i,ncount,*count;
 +    char tabfn[STRLEN];
 +    bondedtable_t *tab;
 +    
 +    tab = NULL;
 +    
 +    ncount = 0;
 +    count = NULL;
 +    count_tables(ftype1,ftype2,mtop,&ncount,&count);
 +    
 +    if (ncount > 0) {
 +        snew(tab,ncount);
 +        for(i=0; i<ncount; i++) {
 +            if (count[i] > 0) {
 +                sprintf(tabfn,"%s",basefn);
 +                sprintf(tabfn + strlen(basefn) - strlen(ftp2ext(efXVG)) - 1,"_%s%d.%s",
 +                        tabext,i,ftp2ext(efXVG));
 +                tab[i] = make_bonded_table(fplog,tabfn,NRAL(ftype1)-2);
 +            }
 +        }
 +        sfree(count);
 +    }
 +  
 +    return tab;
 +}
 +
 +void forcerec_set_ranges(t_forcerec *fr,
 +                         int ncg_home,int ncg_force,
 +                         int natoms_force,
 +                         int natoms_force_constr,int natoms_f_novirsum)
 +{
 +    fr->cg0 = 0;
 +    fr->hcg = ncg_home;
 +
 +    /* fr->ncg_force is unused in the standard code,
 +     * but it can be useful for modified code dealing with charge groups.
 +     */
 +    fr->ncg_force           = ncg_force;
 +    fr->natoms_force        = natoms_force;
 +    fr->natoms_force_constr = natoms_force_constr;
 +
 +    if (fr->natoms_force_constr > fr->nalloc_force)
 +    {
 +        fr->nalloc_force = over_alloc_dd(fr->natoms_force_constr);
 +
 +        if (fr->bTwinRange)
 +        {
 +            srenew(fr->f_twin,fr->nalloc_force);
 +        }
 +    }
 +
 +    if (fr->bF_NoVirSum)
 +    {
 +        fr->f_novirsum_n = natoms_f_novirsum;
 +        if (fr->f_novirsum_n > fr->f_novirsum_nalloc)
 +        {
 +            fr->f_novirsum_nalloc = over_alloc_dd(fr->f_novirsum_n);
 +            srenew(fr->f_novirsum_alloc,fr->f_novirsum_nalloc);
 +        }
 +    }
 +    else
 +    {
 +        fr->f_novirsum_n = 0;
 +    }
 +}
 +
 +static real cutoff_inf(real cutoff)
 +{
 +    if (cutoff == 0)
 +    {
 +        cutoff = GMX_CUTOFF_INF;
 +    }
 +
 +    return cutoff;
 +}
 +
 +static void make_adress_tf_tables(FILE *fp,const output_env_t oenv,
 +                            t_forcerec *fr,const t_inputrec *ir,
 +                          const char *tabfn, const gmx_mtop_t *mtop,
 +                            matrix     box)
 +{
 +  char buf[STRLEN];
 +  int i,j;
 +
 +  if (tabfn == NULL) {
 +        gmx_fatal(FARGS,"No thermoforce table file given. Use -tabletf to specify a file\n");
 +    return;
 +  }
 +
 +  snew(fr->atf_tabs, ir->adress->n_tf_grps);
 +
 +  for (i=0; i<ir->adress->n_tf_grps; i++){
 +    j = ir->adress->tf_table_index[i]; /* get energy group index */
 +    sprintf(buf + strlen(tabfn) - strlen(ftp2ext(efXVG)) - 1,"tf_%s.%s",
 +        *(mtop->groups.grpname[mtop->groups.grps[egcENER].nm_ind[j]]) ,ftp2ext(efXVG));
 +    printf("loading tf table for energygrp index %d from %s\n", ir->adress->tf_table_index[j], buf);
 +    fr->atf_tabs[i] = make_atf_table(fp,oenv,fr,buf, box);
 +  }
 +
 +}
 +
 +gmx_bool can_use_allvsall(const t_inputrec *ir, const gmx_mtop_t *mtop,
 +                      gmx_bool bPrintNote,t_commrec *cr,FILE *fp)
 +{
 +    gmx_bool bAllvsAll;
 +
 +    bAllvsAll =
 +        (
 +         ir->rlist==0            &&
 +         ir->rcoulomb==0         &&
 +         ir->rvdw==0             &&
 +         ir->ePBC==epbcNONE      &&
 +         ir->vdwtype==evdwCUT    &&
 +         ir->coulombtype==eelCUT &&
 +         ir->efep==efepNO        &&
 +         (ir->implicit_solvent == eisNO || 
 +          (ir->implicit_solvent==eisGBSA && (ir->gb_algorithm==egbSTILL || 
 +                                             ir->gb_algorithm==egbHCT   || 
 +                                             ir->gb_algorithm==egbOBC))) &&
 +         getenv("GMX_NO_ALLVSALL") == NULL
 +            );
 +    
 +    if (bAllvsAll && ir->opts.ngener > 1)
 +    {
 +        const char *note="NOTE: Can not use all-vs-all force loops, because there are multiple energy monitor groups; you might get significantly higher performance when using only a single energy monitor group.\n";
 +
 +        if (bPrintNote)
 +        {
 +            if (MASTER(cr))
 +            {
 +                fprintf(stderr,"\n%s\n",note);
 +            }
 +            if (fp != NULL)
 +            {
 +                fprintf(fp,"\n%s\n",note);
 +            }
 +        }
 +        bAllvsAll = FALSE;
 +    }
 +
 +    if(bAllvsAll && fp && MASTER(cr))
 +    {
 +        fprintf(fp,"\nUsing accelerated all-vs-all kernels.\n\n");
 +    }
 +    
 +    return bAllvsAll;
 +}
 +
 +
 +static void init_forcerec_f_threads(t_forcerec *fr,int nenergrp)
 +{
 +    int t,i;
 +
 +    /* These thread local data structures are used for bondeds only */
 +    fr->nthreads = gmx_omp_nthreads_get(emntBonded);
 +
 +    if (fr->nthreads > 1)
 +    {
 +        snew(fr->f_t,fr->nthreads);
 +        /* Thread 0 uses the global force and energy arrays */
 +        for(t=1; t<fr->nthreads; t++)
 +        {
 +            fr->f_t[t].f = NULL;
 +            fr->f_t[t].f_nalloc = 0;
 +            snew(fr->f_t[t].fshift,SHIFTS);
 +            fr->f_t[t].grpp.nener = nenergrp*nenergrp;
 +            for(i=0; i<egNR; i++)
 +            {
 +                snew(fr->f_t[t].grpp.ener[i],fr->f_t[t].grpp.nener);
 +            }
 +        }
 +    }
 +}
 +
 +
 +static void pick_nbnxn_kernel_cpu(FILE *fp,
 +                                  const t_commrec *cr,
 +                                  const gmx_cpuid_t cpuid_info,
 +                                  int *kernel_type)
 +{
 +    *kernel_type = nbk4x4_PlainC;
 +
 +#ifdef GMX_X86_SSE2
 +    {
 +        /* On Intel Sandy-Bridge AVX-256 kernels are always faster.
 +         * On AMD Bulldozer AVX-256 is much slower than AVX-128.
 +         */
 +        if(gmx_cpuid_feature(cpuid_info, GMX_CPUID_FEATURE_X86_AVX) == 1 &&
 +           gmx_cpuid_vendor(cpuid_info) != GMX_CPUID_VENDOR_AMD)
 +        {
 +#ifdef GMX_X86_AVX_256
 +            *kernel_type = nbk4xN_X86_SIMD256;
 +#else
 +            *kernel_type = nbk4xN_X86_SIMD128;
 +#endif
 +        }
 +        else
 +        {
 +            *kernel_type = nbk4xN_X86_SIMD128;
 +        }
 +
 +        if (getenv("GMX_NBNXN_AVX128") != NULL)
 +        {
 +            *kernel_type = nbk4xN_X86_SIMD128;
 +        }
 +        if (getenv("GMX_NBNXN_AVX256") != NULL)
 +        {
 +#ifdef GMX_X86_AVX_256
 +            *kernel_type = nbk4xN_X86_SIMD256;
 +#else
 +            gmx_fatal(FARGS,"You requested AVX-256 nbnxn kernels, but GROMACS was built without AVX support");
 +#endif
 +        }
 +    }
 +#endif /* GMX_X86_SSE2 */
 +}
 +
 +
 +/* Note that _mm_... intrinsics can be converted to either SSE or AVX
 + * depending on compiler flags.
 + * For gcc we check for __AVX__
 + * At least a check for icc should be added (if there is a macro)
 + */
 +static const char *nbk_name[] =
 +  { "not set", "plain C 4x4",
 +#if !(defined GMX_X86_AVX_256 || defined GMX_X86_AVX128_FMA || defined __AVX__)
 +#ifndef GMX_X86_SSE4_1
 +#ifndef GMX_DOUBLE
 +    "SSE2 4x4",
 +#else
 +    "SSE2 4x2",
 +#endif
 +#else
 +#ifndef GMX_DOUBLE
 +    "SSE4.1 4x4",
 +#else
 +    "SSE4.1 4x2",
 +#endif
 +#endif
 +#else
 +#ifndef GMX_DOUBLE
 +    "AVX-128 4x4",
 +#else
 +    "AVX-128 4x2",
 +#endif
 +#endif
 +#ifndef GMX_DOUBLE
 +    "AVX-256 4x8",
 +#else
 +    "AVX-256 4x4",
 +#endif
 +    "CUDA 8x8x8", "plain C 8x8x8" };
 +
 +static void pick_nbnxn_kernel(FILE *fp,
 +                              const t_commrec *cr,
 +                              const gmx_hw_info_t *hwinfo,
 +                              gmx_bool use_cpu_acceleration,
 +                              gmx_bool *bUseGPU,
 +                              int *kernel_type)
 +{
 +    gmx_bool bEmulateGPU, bGPU;
 +    char gpu_err_str[STRLEN];
 +
 +    assert(kernel_type);
 +
 +    *kernel_type = nbkNotSet;
 +    /* if bUseGPU == NULL we don't want a GPU (e.g. hybrid mode kernel selection) */
 +    bGPU = (bUseGPU != NULL) && hwinfo->bCanUseGPU;
 +
 +    /* Run GPU emulation mode if GMX_EMULATE_GPU is defined or in case if nobonded
 +       calculations are turned off via GMX_NO_NONBONDED -- this is the simple way
 +       to turn off GPU/CUDA initializations as well.. */
 +    bEmulateGPU = ((getenv("GMX_EMULATE_GPU") != NULL) ||
 +                   (getenv("GMX_NO_NONBONDED") != NULL));
 +
 +    if (bGPU)
 +    {
 +        if (bEmulateGPU)
 +        {
 +            bGPU = FALSE;
 +        }
 +        else
 +        {
 +            /* Each PP node will use the intra-node id-th device from the
 +             * list of detected/selected GPUs. */ 
 +            if (!init_gpu(cr->nodeid_group_intra, gpu_err_str, &hwinfo->gpu_info))
 +            {
 +                /* At this point the init should never fail as we made sure that 
 +                 * we have all the GPUs we need. If it still does, we'll bail. */
 +                gmx_fatal(FARGS, "On node %d failed to initialize GPU #%d: %s",
 +                          cr->nodeid,
 +                          get_gpu_device_id(&hwinfo->gpu_info, cr->nodeid_group_intra),
 +                          gpu_err_str);
 +            }
 +        }
 +        *bUseGPU = bGPU;
 +    }
 +
 +    if (bEmulateGPU)
 +    {
 +        *kernel_type = nbk8x8x8_PlainC;
 +
 +        md_print_warn(cr, fp, "Emulating a GPU run on the CPU (slow)");
 +    }
 +    else if (bGPU)
 +    {
 +        *kernel_type = nbk8x8x8_CUDA;
 +    }
 +
 +    if (*kernel_type == nbkNotSet)
 +    {
 +        if (use_cpu_acceleration)
 +        {
 +            pick_nbnxn_kernel_cpu(fp,cr,hwinfo->cpuid_info,kernel_type);
 +        }
 +        else
 +        {
 +            *kernel_type = nbk4x4_PlainC;
 +        }
 +    }
 +
 +    if (fp != NULL)
 +    {
 +        if (MASTER(cr))
 +        {
 +            fprintf(stderr,"Using %s non-bonded kernels\n",
 +                    nbk_name[*kernel_type]);
 +        }
 +        fprintf(fp,"\nUsing %s non-bonded kernels\n\n",
 +                nbk_name[*kernel_type]);
 +    }
 +}
 +
 +gmx_bool uses_simple_tables(int cutoff_scheme,
 +                            nonbonded_verlet_t *nbv,
 +                            int group)
 +{
 +    gmx_bool bUsesSimpleTables = TRUE;
 +    int grp_index;
 +
 +    switch(cutoff_scheme)
 +    {
 +    case ecutsGROUP:
 +        bUsesSimpleTables = TRUE;
 +        break;
 +    case ecutsVERLET:
 +        assert(NULL != nbv && NULL != nbv->grp);
 +        grp_index = (group < 0) ? 0 : (nbv->ngrp - 1);
 +        bUsesSimpleTables = nbnxn_kernel_pairlist_simple(nbv->grp[grp_index].kernel_type);
 +        break;
 +    default:
 +        gmx_incons("unimplemented");
 +    }
 +    return bUsesSimpleTables;
 +}
 +
 +static void init_ewald_f_table(interaction_const_t *ic,
 +                               gmx_bool bUsesSimpleTables,
 +                               real rtab)
 +{
 +    real maxr;
 +
 +    if (bUsesSimpleTables)
 +    {
 +        /* With a spacing of 0.0005 we are at the force summation accuracy
 +         * for the SSE kernels for "normal" atomistic simulations.
 +         */
 +        ic->tabq_scale = ewald_spline3_table_scale(ic->ewaldcoeff,
 +                                                   ic->rcoulomb);
 +        
 +        maxr = (rtab>ic->rcoulomb) ? rtab : ic->rcoulomb;
 +        ic->tabq_size  = (int)(maxr*ic->tabq_scale) + 2;
 +    }
 +    else
 +    {
 +        ic->tabq_size = GPU_EWALD_COULOMB_FORCE_TABLE_SIZE;
 +        /* Subtract 2 iso 1 to avoid access out of range due to rounding */
 +        ic->tabq_scale = (ic->tabq_size - 2)/ic->rcoulomb;
 +    }
 +
 +    sfree_aligned(ic->tabq_coul_FDV0);
 +    sfree_aligned(ic->tabq_coul_F);
 +    sfree_aligned(ic->tabq_coul_V);
 +
 +    /* Create the original table data in FDV0 */
 +    snew_aligned(ic->tabq_coul_FDV0,ic->tabq_size*4,16);
 +    snew_aligned(ic->tabq_coul_F,ic->tabq_size,16);
 +    snew_aligned(ic->tabq_coul_V,ic->tabq_size,16);
 +    table_spline3_fill_ewald_lr(ic->tabq_coul_F,ic->tabq_coul_V,ic->tabq_coul_FDV0,
 +                                ic->tabq_size,1/ic->tabq_scale,ic->ewaldcoeff);
 +}
 +
 +void init_interaction_const_tables(FILE *fp, 
 +                                   interaction_const_t *ic,
 +                                   gmx_bool bUsesSimpleTables,
 +                                   real rtab)
 +{
 +    real spacing;
 +
 +    if (ic->eeltype == eelEWALD || EEL_PME(ic->eeltype))
 +    {
 +        init_ewald_f_table(ic,bUsesSimpleTables,rtab);
 +
 +        if (fp != NULL)
 +        {
 +            fprintf(fp,"Initialized non-bonded Ewald correction tables, spacing: %.2e size: %d\n\n",
 +                    1/ic->tabq_scale,ic->tabq_size);
 +        }
 +    }
 +}
 +
 +void init_interaction_const(FILE *fp, 
 +                            interaction_const_t **interaction_const,
 +                            const t_forcerec *fr,
 +                            real  rtab)
 +{
 +    interaction_const_t *ic;
 +    gmx_bool bUsesSimpleTables = TRUE;
 +
 +    snew(ic, 1);
 +
 +    /* Just allocate something so we can free it */
 +    snew_aligned(ic->tabq_coul_FDV0,16,16);
 +    snew_aligned(ic->tabq_coul_F,16,16);
 +    snew_aligned(ic->tabq_coul_V,16,16);
 +
 +    ic->rlist       = fr->rlist;
 +    ic->rlistlong   = fr->rlistlong;
 +    
 +    /* Lennard-Jones */
 +    ic->rvdw        = fr->rvdw;
 +    if (fr->vdw_modifier==eintmodPOTSHIFT)
 +    {
 +        ic->sh_invrc6 = pow(ic->rvdw,-6.0);
 +    }
 +    else
 +    {
 +        ic->sh_invrc6 = 0;
 +    }
 +
 +    /* Electrostatics */
 +    ic->eeltype     = fr->eeltype;
 +    ic->rcoulomb    = fr->rcoulomb;
 +    ic->epsilon_r   = fr->epsilon_r;
 +    ic->epsfac      = fr->epsfac;
 +
 +    /* Ewald */
 +    ic->ewaldcoeff  = fr->ewaldcoeff;
 +    if (fr->coulomb_modifier==eintmodPOTSHIFT)
 +    {
 +        ic->sh_ewald = gmx_erfc(ic->ewaldcoeff*ic->rcoulomb);
 +    }
 +    else
 +    {
 +        ic->sh_ewald = 0;
 +    }
 +
 +    /* Reaction-field */
 +    if (EEL_RF(ic->eeltype))
 +    {
 +        ic->epsilon_rf = fr->epsilon_rf;
 +        ic->k_rf       = fr->k_rf;
 +        ic->c_rf       = fr->c_rf;
 +    }
 +    else
 +    {
 +        /* For plain cut-off we might use the reaction-field kernels */
 +        ic->epsilon_rf = ic->epsilon_r;
 +        ic->k_rf       = 0;
 +        if (fr->coulomb_modifier==eintmodPOTSHIFT)
 +        {
 +            ic->c_rf   = 1/ic->rcoulomb;
 +        }
 +        else
 +        {
 +            ic->c_rf   = 0;
 +        }
 +    }
 +
 +    if (fp != NULL)
 +    {
 +        fprintf(fp,"Potential shift: LJ r^-12: %.3f r^-6 %.3f",
 +                sqr(ic->sh_invrc6),ic->sh_invrc6);
 +        if (ic->eeltype == eelCUT)
 +        {
 +            fprintf(fp,", Coulomb %.3f",ic->c_rf);
 +        }
 +        else if (EEL_PME(ic->eeltype))
 +        {
 +            fprintf(fp,", Ewald %.3e",ic->sh_ewald);
 +        }
 +        fprintf(fp,"\n");
 +    }
 +
 +    *interaction_const = ic;
 +
 +    if (fr->nbv != NULL && fr->nbv->bUseGPU)
 +    {
 +        nbnxn_cuda_init_const(fr->nbv->cu_nbv, ic, fr->nbv);
 +    }
 +
 +    bUsesSimpleTables = uses_simple_tables(fr->cutoff_scheme, fr->nbv, -1);
 +    init_interaction_const_tables(fp,ic,bUsesSimpleTables,rtab);
 +}
 +
 +static void init_nb_verlet(FILE *fp,
 +                           nonbonded_verlet_t **nb_verlet,
 +                           const t_inputrec *ir,
 +                           const t_forcerec *fr,
 +                           const t_commrec *cr,
 +                           const char *nbpu_opt)
 +{
 +    nonbonded_verlet_t *nbv;
 +    int  i;
 +    char *env;
 +    gmx_bool bHybridGPURun = FALSE;
 +
 +    nbnxn_alloc_t *nb_alloc;
 +    nbnxn_free_t  *nb_free;
 +
 +    snew(nbv, 1);
 +
 +    nbv->nbs = NULL;
 +
 +    nbv->ngrp = (DOMAINDECOMP(cr) ? 2 : 1);
 +    for(i=0; i<nbv->ngrp; i++)
 +    {
 +        nbv->grp[i].nbl_lists.nnbl = 0;
 +        nbv->grp[i].nbat           = NULL;
 +        nbv->grp[i].kernel_type    = nbkNotSet;
 +
 +        if (i == 0) /* local */
 +        {
 +            pick_nbnxn_kernel(fp, cr, fr->hwinfo, fr->use_cpu_acceleration,
 +                              &nbv->bUseGPU,
 +                              &nbv->grp[i].kernel_type);
 +        }
 +        else /* non-local */
 +        {
 +            if (nbpu_opt != NULL && strcmp(nbpu_opt,"gpu_cpu") == 0)
 +            {
 +                /* Use GPU for local, select a CPU kernel for non-local */
 +                pick_nbnxn_kernel(fp, cr, fr->hwinfo, fr->use_cpu_acceleration,
 +                                  NULL,
 +                                  &nbv->grp[i].kernel_type);
 +
 +                bHybridGPURun = TRUE;
 +            }
 +            else
 +            {
 +                /* Use the same kernel for local and non-local interactions */
 +                nbv->grp[i].kernel_type = nbv->grp[0].kernel_type;
 +            }
 +        }
 +    }
 +
 +    if (nbv->bUseGPU)
 +    {
 +        /* init the NxN GPU data; the last argument tells whether we'll have
 +         * both local and non-local NB calculation on GPU */
 +        nbnxn_cuda_init(fp, &nbv->cu_nbv,
 +                        &fr->hwinfo->gpu_info, cr->nodeid_group_intra,
 +                        (nbv->ngrp > 1) && !bHybridGPURun);
 +
 +        if ((env = getenv("GMX_NB_MIN_CI")) != NULL)
 +        {
 +            char *end;
 +
 +            nbv->min_ci_balanced = strtol(env, &end, 10);
 +            if (!end || (*end != 0) || nbv->min_ci_balanced <= 0)
 +            {
 +                gmx_fatal(FARGS, "Invalid value passed in GMX_NB_MIN_CI=%s, positive integer required", env);
 +            }
 +
 +            if (debug)
 +            {
 +                fprintf(debug, "Neighbor-list balancing parameter: %d (passed as env. var.)\n", 
 +                        nbv->min_ci_balanced);
 +            }
 +        }
 +        else
 +        {
 +            nbv->min_ci_balanced = nbnxn_cuda_min_ci_balanced(nbv->cu_nbv);
 +            if (debug)
 +            {
 +                fprintf(debug, "Neighbor-list balancing parameter: %d (auto-adjusted to the number of GPU multi-processors)\n",
 +                        nbv->min_ci_balanced);
 +            }
 +        }
 +    }
 +    else
 +    {
 +        nbv->min_ci_balanced = 0;
 +    }
 +
 +    *nb_verlet = nbv;
 +
 +    nbnxn_init_search(&nbv->nbs,
 +                      DOMAINDECOMP(cr) ? & cr->dd->nc : NULL,
 +                      DOMAINDECOMP(cr) ? domdec_zones(cr->dd) : NULL,
 +                      gmx_omp_nthreads_get(emntNonbonded));
 +
 +    for(i=0; i<nbv->ngrp; i++)
 +    {
 +        if (nbv->grp[0].kernel_type == nbk8x8x8_CUDA)
 +        {
 +            nb_alloc = &pmalloc;
 +            nb_free  = &pfree;
 +        }
 +        else
 +        {
 +            nb_alloc = NULL;
 +            nb_free  = NULL;
 +        }
 +
 +        nbnxn_init_pairlist_set(&nbv->grp[i].nbl_lists,
 +                                nbnxn_kernel_pairlist_simple(nbv->grp[i].kernel_type),
 +                                /* 8x8x8 "non-simple" lists are ATM always combined */
 +                                !nbnxn_kernel_pairlist_simple(nbv->grp[i].kernel_type),
 +                                nb_alloc, nb_free);
 +
 +        if (i == 0 ||
 +            nbv->grp[0].kernel_type != nbv->grp[i].kernel_type)
 +        {
 +            snew(nbv->grp[i].nbat,1);
 +            nbnxn_atomdata_init(fp,
 +                                nbv->grp[i].nbat,
 +                                nbv->grp[i].kernel_type,
 +                                fr->ntype,fr->nbfp,
 +                                ir->opts.ngener,
 +                                nbnxn_kernel_pairlist_simple(nbv->grp[i].kernel_type) ? gmx_omp_nthreads_get(emntNonbonded) : 1,
 +                                nb_alloc, nb_free);
 +        }
 +        else
 +        {
 +            nbv->grp[i].nbat = nbv->grp[0].nbat;
 +        }
 +    }
 +}
 +
 +void init_forcerec(FILE *fp,
 +                   const output_env_t oenv,
 +                   t_forcerec *fr,
 +                   t_fcdata   *fcd,
 +                   const t_inputrec *ir,
 +                   const gmx_mtop_t *mtop,
 +                   const t_commrec  *cr,
 +                   matrix     box,
 +                   gmx_bool       bMolEpot,
 +                   const char *tabfn,
 +                   const char *tabafn,
 +                   const char *tabpfn,
 +                   const char *tabbfn,
 +                   const char *nbpu_opt,
 +                   gmx_bool   bNoSolvOpt,
 +                   real       print_force)
 +{
 +    int     i,j,m,natoms,ngrp,negp_pp,negptable,egi,egj;
 +    real    rtab;
 +    char    *env;
 +    double  dbl;
 +    rvec    box_size;
 +    const t_block *cgs;
 +    gmx_bool    bGenericKernelOnly;
 +    gmx_bool    bTab,bSep14tab,bNormalnblists;
 +    t_nblists *nbl;
 +    int     *nm_ind,egp_flags;
 +    
 +    /* By default we turn acceleration on, but it might be turned off further down... */
 +    fr->use_cpu_acceleration = TRUE;
 +
 +    fr->bDomDec = DOMAINDECOMP(cr);
 +
 +    natoms = mtop->natoms;
 +
 +    if (check_box(ir->ePBC,box))
 +    {
 +        gmx_fatal(FARGS,check_box(ir->ePBC,box));
 +    }
 +    
 +    /* Test particle insertion ? */
 +    if (EI_TPI(ir->eI)) {
 +        /* Set to the size of the molecule to be inserted (the last one) */
 +        /* Because of old style topologies, we have to use the last cg
 +         * instead of the last molecule type.
 +         */
 +        cgs = &mtop->moltype[mtop->molblock[mtop->nmolblock-1].type].cgs;
 +        fr->n_tpi = cgs->index[cgs->nr] - cgs->index[cgs->nr-1];
 +        if (fr->n_tpi != mtop->mols.index[mtop->mols.nr] - mtop->mols.index[mtop->mols.nr-1]) {
 +            gmx_fatal(FARGS,"The molecule to insert can not consist of multiple charge groups.\nMake it a single charge group.");
 +        }
 +    } else {
 +        fr->n_tpi = 0;
 +    }
 +    
 +    /* Copy AdResS parameters */
 +    if (ir->bAdress) {
 +      fr->adress_type     = ir->adress->type;
 +      fr->adress_const_wf = ir->adress->const_wf;
 +      fr->adress_ex_width = ir->adress->ex_width;
 +      fr->adress_hy_width = ir->adress->hy_width;
 +      fr->adress_icor     = ir->adress->icor;
 +      fr->adress_site     = ir->adress->site;
 +      fr->adress_ex_forcecap = ir->adress->ex_forcecap;
 +      fr->adress_do_hybridpairs = ir->adress->do_hybridpairs;
 +
 +
 +      snew(fr->adress_group_explicit , ir->adress->n_energy_grps);
 +      for (i=0; i< ir->adress->n_energy_grps; i++){
 +          fr->adress_group_explicit[i]= ir->adress->group_explicit[i];
 +      }
 +
 +      fr->n_adress_tf_grps = ir->adress->n_tf_grps;
 +      snew(fr->adress_tf_table_index, fr->n_adress_tf_grps);
 +      for (i=0; i< fr->n_adress_tf_grps; i++){
 +          fr->adress_tf_table_index[i]= ir->adress->tf_table_index[i];
 +      }
 +      copy_rvec(ir->adress->refs,fr->adress_refs);
 +    } else {
 +      fr->adress_type = eAdressOff;
 +      fr->adress_do_hybridpairs = FALSE;
 +    }
 +    
 +    /* Copy the user determined parameters */
 +    fr->userint1 = ir->userint1;
 +    fr->userint2 = ir->userint2;
 +    fr->userint3 = ir->userint3;
 +    fr->userint4 = ir->userint4;
 +    fr->userreal1 = ir->userreal1;
 +    fr->userreal2 = ir->userreal2;
 +    fr->userreal3 = ir->userreal3;
 +    fr->userreal4 = ir->userreal4;
 +    
 +    /* Shell stuff */
 +    fr->fc_stepsize = ir->fc_stepsize;
 +    
 +    /* Free energy */
 +    fr->efep       = ir->efep;
 +    fr->sc_alphavdw = ir->fepvals->sc_alpha;
 +    if (ir->fepvals->bScCoul)
 +    {
 +        fr->sc_alphacoul = ir->fepvals->sc_alpha;
 +        fr->sc_sigma6_min = pow(ir->fepvals->sc_sigma_min,6);
 +    }
 +    else
 +    {
 +        fr->sc_alphacoul = 0;
 +        fr->sc_sigma6_min = 0; /* only needed when bScCoul is on */
 +    }
 +    fr->sc_power   = ir->fepvals->sc_power;
 +    fr->sc_r_power   = ir->fepvals->sc_r_power;
 +    fr->sc_sigma6_def = pow(ir->fepvals->sc_sigma,6);
 +
 +    env = getenv("GMX_SCSIGMA_MIN");
 +    if (env != NULL)
 +    {
 +        dbl = 0;
 +        sscanf(env,"%lf",&dbl);
 +        fr->sc_sigma6_min = pow(dbl,6);
 +        if (fp)
 +        {
 +            fprintf(fp,"Setting the minimum soft core sigma to %g nm\n",dbl);
 +        }
 +    }
 +
 +    fr->bNonbonded = TRUE;
 +    if (getenv("GMX_NO_NONBONDED") != NULL)
 +    {
 +        /* turn off non-bonded calculations */
 +        fr->bNonbonded = FALSE;
 +        md_print_warn(cr,fp,
 +                      "Found environment variable GMX_NO_NONBONDED.\n"
 +                      "Disabling nonbonded calculations.\n");
 +    }
 +
 +    bGenericKernelOnly = FALSE;
 +
 +    /* We now check in the NS code whether a particular combination of interactions
 +     * can be used with water optimization, and disable it if that is not the case.
 +     */
 +
 +    if (getenv("GMX_NB_GENERIC") != NULL)
 +    {
 +        if (fp != NULL)
 +        {
 +            fprintf(fp,
 +                    "Found environment variable GMX_NB_GENERIC.\n"
 +                    "Disabling all interaction-specific nonbonded kernels, will only\n"
 +                    "use the slow generic ones in src/gmxlib/nonbonded/nb_generic.c\n\n");
 +        }
 +        bGenericKernelOnly = TRUE;
 +    }
 +
 +    if (bGenericKernelOnly==TRUE)
 +    {
 +        bNoSolvOpt         = TRUE;
 +    }
 +
 +    if( (getenv("GMX_DISABLE_CPU_ACCELERATION") != NULL) || (getenv("GMX_NOOPTIMIZEDKERNELS") != NULL) )
 +    {
 +        fr->use_cpu_acceleration = FALSE;
 +        if (fp != NULL)
 +        {
 +            fprintf(fp,
 +                    "\nFound environment variable GMX_DISABLE_CPU_ACCELERATION.\n"
 +                    "Disabling all CPU architecture-specific (e.g. SSE2/SSE4/AVX) routines.\n\n");
 +        }
 +    }
 +
 +    fr->bBHAM = (mtop->ffparams.functype[0] == F_BHAM);
 +
 +    /* Check if we can/should do all-vs-all kernels */
 +    fr->bAllvsAll       = can_use_allvsall(ir,mtop,FALSE,NULL,NULL);
 +    fr->AllvsAll_work   = NULL;
 +    fr->AllvsAll_workgb = NULL;
 +
 +
 +    /* Neighbour searching stuff */
 +    fr->cutoff_scheme = ir->cutoff_scheme;
 +    fr->bGrid         = (ir->ns_type == ensGRID);
 +    fr->ePBC          = ir->ePBC;
 +
 +    /* Determine if we will do PBC for distances in bonded interactions */
 +    if (fr->ePBC == epbcNONE)
 +    {
 +        fr->bMolPBC = FALSE;
 +    }
 +    else
 +    {
 +        if (!DOMAINDECOMP(cr))
 +        {
 +            /* The group cut-off scheme and SHAKE assume charge groups
 +             * are whole, but not using molpbc is faster in most cases.
 +             */
 +            if (fr->cutoff_scheme == ecutsGROUP ||
 +                (ir->eConstrAlg == econtSHAKE &&
 +                 (gmx_mtop_ftype_count(mtop,F_CONSTR) > 0 ||
 +                  gmx_mtop_ftype_count(mtop,F_CONSTRNC) > 0)))
 +            {
 +                fr->bMolPBC = ir->bPeriodicMols;
 +            }
 +            else
 +            {
 +                fr->bMolPBC = TRUE;
 +                if (getenv("GMX_USE_GRAPH") != NULL)
 +                {
 +                    fr->bMolPBC = FALSE;
 +                    if (fp)
 +                    {
 +                        fprintf(fp,"\nGMX_MOLPBC is set, using the graph for bonded interactions\n\n");
 +                    }
 +                }
 +            }
 +        }
 +        else
 +        {
 +            fr->bMolPBC = dd_bonded_molpbc(cr->dd,fr->ePBC);
 +        }
 +    }
 +
 +    fr->rc_scaling = ir->refcoord_scaling;
 +    copy_rvec(ir->posres_com,fr->posres_com);
 +    copy_rvec(ir->posres_comB,fr->posres_comB);
 +    fr->rlist      = cutoff_inf(ir->rlist);
 +    fr->rlistlong  = cutoff_inf(ir->rlistlong);
 +    fr->eeltype    = ir->coulombtype;
 +    fr->vdwtype    = ir->vdwtype;
 +
 +    fr->coulomb_modifier = ir->coulomb_modifier;
 +    fr->vdw_modifier     = ir->vdw_modifier;
 +
 +    /* Electrostatics: Translate from interaction-setting-in-mdp-file to kernel interaction format */
 +    switch(fr->eeltype)
 +    {
 +        case eelCUT:
 +            fr->nbkernel_elec_interaction = GMX_NBKERNEL_ELEC_COULOMB;
 +            break;
 +
 +        case eelRF:
 +        case eelGRF:
 +        case eelRF_NEC:
 +            fr->nbkernel_elec_interaction = GMX_NBKERNEL_ELEC_REACTIONFIELD;
 +            break;
 +
 +        case eelRF_ZERO:
 +            fr->nbkernel_elec_interaction = GMX_NBKERNEL_ELEC_REACTIONFIELD;
 +            fr->coulomb_modifier          = eintmodEXACTCUTOFF;
 +            break;
 +
 +        case eelSWITCH:
 +        case eelSHIFT:
 +        case eelUSER:
 +        case eelENCADSHIFT:
 +        case eelPMESWITCH:
 +        case eelPMEUSER:
 +        case eelPMEUSERSWITCH:
 +            fr->nbkernel_elec_interaction = GMX_NBKERNEL_ELEC_CUBICSPLINETABLE;
 +            break;
 +
 +        case eelPME:
 +        case eelEWALD:
 +            fr->nbkernel_elec_interaction = GMX_NBKERNEL_ELEC_EWALD;
 +            break;
 +
 +        default:
 +            gmx_fatal(FARGS,"Unsupported electrostatic interaction: %s",eel_names[fr->eeltype]);
 +            break;
 +    }
 +
 +    /* Vdw: Translate from mdp settings to kernel format */
 +    switch(fr->vdwtype)
 +    {
 +        case evdwCUT:
 +            if(fr->bBHAM)
 +            {
 +                fr->nbkernel_vdw_interaction = GMX_NBKERNEL_VDW_BUCKINGHAM;
 +            }
 +            else
 +            {
 +                fr->nbkernel_vdw_interaction = GMX_NBKERNEL_VDW_LENNARDJONES;
 +            }
 +            break;
 +
 +        case evdwSWITCH:
 +        case evdwSHIFT:
 +        case evdwUSER:
 +        case evdwENCADSHIFT:
 +            fr->nbkernel_vdw_interaction = GMX_NBKERNEL_VDW_CUBICSPLINETABLE;
 +            break;
 +
 +        default:
 +            gmx_fatal(FARGS,"Unsupported vdw interaction: %s",evdw_names[fr->vdwtype]);
 +            break;
 +    }
 +
 +    /* These start out identical to ir, but might be altered if we e.g. tabulate the interaction in the kernel */
 +    fr->nbkernel_elec_modifier    = fr->coulomb_modifier;
 +    fr->nbkernel_vdw_modifier     = fr->vdw_modifier;
 +
 +    fr->bTwinRange = fr->rlistlong > fr->rlist;
 +    fr->bEwald     = (EEL_PME(fr->eeltype) || fr->eeltype==eelEWALD);
 +    
 +    fr->reppow     = mtop->ffparams.reppow;
 +
 +    if (ir->cutoff_scheme == ecutsGROUP)
 +    {
 +        fr->bvdwtab    = (fr->vdwtype != evdwCUT ||
 +                          !gmx_within_tol(fr->reppow,12.0,10*GMX_DOUBLE_EPS));
 +        /* We have special kernels for standard Ewald and PME, but the pme-switch ones are tabulated above */
 +        fr->bcoultab   = !(fr->eeltype == eelCUT ||
 +                           fr->eeltype == eelEWALD ||
 +                           fr->eeltype == eelPME ||
 +                           fr->eeltype == eelRF ||
 +                           fr->eeltype == eelRF_ZERO);
 +
 +        /* If the user absolutely wants different switch/shift settings for coul/vdw, it is likely
 +         * going to be faster to tabulate the interaction than calling the generic kernel.
 +         */
 +        if(fr->nbkernel_elec_modifier==eintmodPOTSWITCH && fr->nbkernel_vdw_modifier==eintmodPOTSWITCH)
 +        {
 +            if((fr->rcoulomb_switch != fr->rvdw_switch) || (fr->rcoulomb != fr->rvdw))
 +            {
 +                fr->bcoultab = TRUE;
 +            }
 +        }
 +        else if((fr->nbkernel_elec_modifier==eintmodPOTSHIFT && fr->nbkernel_vdw_modifier==eintmodPOTSHIFT) ||
 +                ((fr->nbkernel_elec_interaction == GMX_NBKERNEL_ELEC_REACTIONFIELD &&
 +                  fr->nbkernel_elec_modifier==eintmodEXACTCUTOFF &&
 +                  (fr->nbkernel_vdw_modifier==eintmodPOTSWITCH || fr->nbkernel_vdw_modifier==eintmodPOTSHIFT))))
 +        {
 +            if(fr->rcoulomb != fr->rvdw)
 +            {
 +                fr->bcoultab = TRUE;
 +            }
 +        }
 +
 +        if (getenv("GMX_REQUIRE_TABLES"))
 +        {
 +            fr->bvdwtab  = TRUE;
 +            fr->bcoultab = TRUE;
 +        }
 +
 +        if (fp)
 +        {
 +            fprintf(fp,"Table routines are used for coulomb: %s\n",bool_names[fr->bcoultab]);
 +            fprintf(fp,"Table routines are used for vdw:     %s\n",bool_names[fr->bvdwtab ]);
 +        }
 +
 +        if(fr->bvdwtab==TRUE)
 +        {
 +            fr->nbkernel_vdw_interaction = GMX_NBKERNEL_VDW_CUBICSPLINETABLE;
 +            fr->nbkernel_vdw_modifier    = eintmodNONE;
 +        }
 +        if(fr->bcoultab==TRUE)
 +        {
 +            fr->nbkernel_elec_interaction = GMX_NBKERNEL_ELEC_CUBICSPLINETABLE;
 +            fr->nbkernel_elec_modifier    = eintmodNONE;
 +        }
 +    }
 +
 +    if (ir->cutoff_scheme == ecutsVERLET)
 +    {
 +        if (!gmx_within_tol(fr->reppow,12.0,10*GMX_DOUBLE_EPS))
 +        {
 +            gmx_fatal(FARGS,"Cut-off scheme %S only supports LJ repulsion power 12",ecutscheme_names[ir->cutoff_scheme]);
 +        }
 +        fr->bvdwtab  = FALSE;
 +        fr->bcoultab = FALSE;
 +    }
 +    
 +    /* Tables are used for direct ewald sum */
 +    if(fr->bEwald)
 +    {
 +        if (EEL_PME(ir->coulombtype))
 +        {
 +            if (fp)
 +                fprintf(fp,"Will do PME sum in reciprocal space.\n");
 +            if (ir->coulombtype == eelP3M_AD)
 +            {
 +                please_cite(fp,"Hockney1988");
 +                please_cite(fp,"Ballenegger2012");
 +            }
 +            else
 +            {
 +                please_cite(fp,"Essmann95a");
 +            }
 +            
 +            if (ir->ewald_geometry == eewg3DC)
 +            {
 +                if (fp)
 +                {
 +                    fprintf(fp,"Using the Ewald3DC correction for systems with a slab geometry.\n");
 +                }
 +                please_cite(fp,"In-Chul99a");
 +            }
 +        }
 +        fr->ewaldcoeff=calc_ewaldcoeff(ir->rcoulomb, ir->ewald_rtol);
 +        init_ewald_tab(&(fr->ewald_table), cr, ir, fp);
 +        if (fp)
 +        {
 +            fprintf(fp,"Using a Gaussian width (1/beta) of %g nm for Ewald\n",
 +                    1/fr->ewaldcoeff);
 +        }
 +    }
 +    
 +    /* Electrostatics */
 +    fr->epsilon_r  = ir->epsilon_r;
 +    fr->epsilon_rf = ir->epsilon_rf;
 +    fr->fudgeQQ    = mtop->ffparams.fudgeQQ;
 +    fr->rcoulomb_switch = ir->rcoulomb_switch;
 +    fr->rcoulomb        = cutoff_inf(ir->rcoulomb);
 +    
 +    /* Parameters for generalized RF */
 +    fr->zsquare = 0.0;
 +    fr->temp    = 0.0;
 +    
 +    if (fr->eeltype == eelGRF)
 +    {
 +        init_generalized_rf(fp,mtop,ir,fr);
 +    }
 +    else if (fr->eeltype == eelSHIFT)
 +    {
 +        for(m=0; (m<DIM); m++)
 +            box_size[m]=box[m][m];
 +        
 +        if ((fr->eeltype == eelSHIFT && fr->rcoulomb > fr->rcoulomb_switch))
 +            set_shift_consts(fp,fr->rcoulomb_switch,fr->rcoulomb,box_size,fr);
 +    }
 +    
 +    fr->bF_NoVirSum = (EEL_FULL(fr->eeltype) ||
 +                       gmx_mtop_ftype_count(mtop,F_POSRES) > 0 ||
 +                       gmx_mtop_ftype_count(mtop,F_FBPOSRES) > 0 ||
 +                       IR_ELEC_FIELD(*ir) ||
 +                       (fr->adress_icor != eAdressICOff)
 +                      );
 +    
 +    if (fr->cutoff_scheme == ecutsGROUP &&
 +        ncg_mtop(mtop) > fr->cg_nalloc && !DOMAINDECOMP(cr)) {
 +        /* Count the total number of charge groups */
 +        fr->cg_nalloc = ncg_mtop(mtop);
 +        srenew(fr->cg_cm,fr->cg_nalloc);
 +    }
 +    if (fr->shift_vec == NULL)
 +        snew(fr->shift_vec,SHIFTS);
 +    
 +    if (fr->fshift == NULL)
 +        snew(fr->fshift,SHIFTS);
 +    
 +    if (fr->nbfp == NULL) {
 +        fr->ntype = mtop->ffparams.atnr;
 +        fr->nbfp  = mk_nbfp(&mtop->ffparams,fr->bBHAM);
 +    }
 +    
 +    /* Copy the energy group exclusions */
 +    fr->egp_flags = ir->opts.egp_flags;
 +    
 +    /* Van der Waals stuff */
 +    fr->rvdw        = cutoff_inf(ir->rvdw);
 +    fr->rvdw_switch = ir->rvdw_switch;
 +    if ((fr->vdwtype != evdwCUT) && (fr->vdwtype != evdwUSER) && !fr->bBHAM) {
 +        if (fr->rvdw_switch >= fr->rvdw)
 +            gmx_fatal(FARGS,"rvdw_switch (%f) must be < rvdw (%f)",
 +                      fr->rvdw_switch,fr->rvdw);
 +        if (fp)
 +            fprintf(fp,"Using %s Lennard-Jones, switch between %g and %g nm\n",
 +                    (fr->eeltype==eelSWITCH) ? "switched":"shifted",
 +                    fr->rvdw_switch,fr->rvdw);
 +    } 
 +    
 +    if (fr->bBHAM && (fr->vdwtype == evdwSHIFT || fr->vdwtype == evdwSWITCH))
 +        gmx_fatal(FARGS,"Switch/shift interaction not supported with Buckingham");
 +    
 +    if (fp)
 +        fprintf(fp,"Cut-off's:   NS: %g   Coulomb: %g   %s: %g\n",
 +                fr->rlist,fr->rcoulomb,fr->bBHAM ? "BHAM":"LJ",fr->rvdw);
 +    
 +    fr->eDispCorr = ir->eDispCorr;
 +    if (ir->eDispCorr != edispcNO)
 +    {
 +        set_avcsixtwelve(fp,fr,mtop);
 +    }
 +    
 +    if (fr->bBHAM)
 +    {
 +        set_bham_b_max(fp,fr,mtop);
 +    }
 +
 +    fr->bGB = (ir->implicit_solvent == eisGBSA);
 +      fr->gb_epsilon_solvent = ir->gb_epsilon_solvent;
 +
 +    /* Copy the GBSA data (radius, volume and surftens for each
 +     * atomtype) from the topology atomtype section to forcerec.
 +     */
 +    snew(fr->atype_radius,fr->ntype);
 +    snew(fr->atype_vol,fr->ntype);
 +    snew(fr->atype_surftens,fr->ntype);
 +    snew(fr->atype_gb_radius,fr->ntype);
 +    snew(fr->atype_S_hct,fr->ntype);
 +
 +    if (mtop->atomtypes.nr > 0)
 +    {
 +        for(i=0;i<fr->ntype;i++)
 +            fr->atype_radius[i] =mtop->atomtypes.radius[i];
 +        for(i=0;i<fr->ntype;i++)
 +            fr->atype_vol[i] = mtop->atomtypes.vol[i];
 +        for(i=0;i<fr->ntype;i++)
 +            fr->atype_surftens[i] = mtop->atomtypes.surftens[i];
 +        for(i=0;i<fr->ntype;i++)
 +            fr->atype_gb_radius[i] = mtop->atomtypes.gb_radius[i];
 +        for(i=0;i<fr->ntype;i++)
 +            fr->atype_S_hct[i] = mtop->atomtypes.S_hct[i];
 +    }  
 +      
 +      /* Generate the GB table if needed */
 +      if(fr->bGB)
 +      {
 +#ifdef GMX_DOUBLE
 +              fr->gbtabscale=2000;
 +#else
 +              fr->gbtabscale=500;
 +#endif
 +              
 +              fr->gbtabr=100;
 +              fr->gbtab=make_gb_table(fp,oenv,fr,tabpfn,fr->gbtabscale);
 +
 +        init_gb(&fr->born,cr,fr,ir,mtop,ir->rgbradii,ir->gb_algorithm);
 +
 +        /* Copy local gb data (for dd, this is done in dd_partition_system) */
 +        if (!DOMAINDECOMP(cr))
 +        {
 +            make_local_gb(cr,fr->born,ir->gb_algorithm);
 +        }
 +    }
 +
 +    /* Set the charge scaling */
 +    if (fr->epsilon_r != 0)
 +        fr->epsfac = ONE_4PI_EPS0/fr->epsilon_r;
 +    else
 +        /* eps = 0 is infinite dieletric: no coulomb interactions */
 +        fr->epsfac = 0;
 +    
 +    /* Reaction field constants */
 +    if (EEL_RF(fr->eeltype))
 +        calc_rffac(fp,fr->eeltype,fr->epsilon_r,fr->epsilon_rf,
 +                   fr->rcoulomb,fr->temp,fr->zsquare,box,
 +                   &fr->kappa,&fr->k_rf,&fr->c_rf);
 +    
 +    set_chargesum(fp,fr,mtop);
 +    
 +    /* if we are using LR electrostatics, and they are tabulated,
 +     * the tables will contain modified coulomb interactions.
 +     * Since we want to use the non-shifted ones for 1-4
 +     * coulombic interactions, we must have an extra set of tables.
 +     */
 +    
 +    /* Construct tables.
 +     * A little unnecessary to make both vdw and coul tables sometimes,
 +     * but what the heck... */
 +    
 +    bTab = fr->bcoultab || fr->bvdwtab || fr->bEwald;
 +
 +    bSep14tab = ((!bTab || fr->eeltype!=eelCUT || fr->vdwtype!=evdwCUT ||
 +                  fr->bBHAM || fr->bEwald) &&
 +                 (gmx_mtop_ftype_count(mtop,F_LJ14) > 0 ||
 +                  gmx_mtop_ftype_count(mtop,F_LJC14_Q) > 0 ||
 +                  gmx_mtop_ftype_count(mtop,F_LJC_PAIRS_NB) > 0));
 +
 +    negp_pp = ir->opts.ngener - ir->nwall;
 +    negptable = 0;
 +    if (!bTab) {
 +        bNormalnblists = TRUE;
 +        fr->nnblists = 1;
 +    } else {
 +        bNormalnblists = (ir->eDispCorr != edispcNO);
 +        for(egi=0; egi<negp_pp; egi++) {
 +            for(egj=egi;  egj<negp_pp; egj++) {
 +                egp_flags = ir->opts.egp_flags[GID(egi,egj,ir->opts.ngener)];
 +                if (!(egp_flags & EGP_EXCL)) {
 +                    if (egp_flags & EGP_TABLE) {
 +                        negptable++;
 +                    } else {
 +                        bNormalnblists = TRUE;
 +                    }
 +                }
 +            }
 +        }
 +        if (bNormalnblists) {
 +            fr->nnblists = negptable + 1;
 +        } else {
 +            fr->nnblists = negptable;
 +        }
 +        if (fr->nnblists > 1)
 +            snew(fr->gid2nblists,ir->opts.ngener*ir->opts.ngener);
 +    }
 +    snew(fr->nblists,fr->nnblists);
 +    
 +    /* This code automatically gives table length tabext without cut-off's,
 +     * in that case grompp should already have checked that we do not need
 +     * normal tables and we only generate tables for 1-4 interactions.
 +     */
 +    rtab = ir->rlistlong + ir->tabext;
 +
 +    if (bTab) {
 +        /* make tables for ordinary interactions */
 +        if (bNormalnblists) {
 +            make_nbf_tables(fp,oenv,fr,rtab,cr,tabfn,NULL,NULL,&fr->nblists[0]);
 +            if (!bSep14tab)
 +                fr->tab14 = fr->nblists[0].table_elec_vdw;
 +            m = 1;
 +        } else {
 +            m = 0;
 +        }
 +        if (negptable > 0) {
 +            /* Read the special tables for certain energy group pairs */
 +            nm_ind = mtop->groups.grps[egcENER].nm_ind;
 +            for(egi=0; egi<negp_pp; egi++) {
 +                for(egj=egi;  egj<negp_pp; egj++) {
 +                    egp_flags = ir->opts.egp_flags[GID(egi,egj,ir->opts.ngener)];
 +                    if ((egp_flags & EGP_TABLE) && !(egp_flags & EGP_EXCL)) {
 +                        nbl = &(fr->nblists[m]);
 +                        if (fr->nnblists > 1) {
 +                            fr->gid2nblists[GID(egi,egj,ir->opts.ngener)] = m;
 +                        }
 +                        /* Read the table file with the two energy groups names appended */
 +                        make_nbf_tables(fp,oenv,fr,rtab,cr,tabfn,
 +                                        *mtop->groups.grpname[nm_ind[egi]],
 +                                        *mtop->groups.grpname[nm_ind[egj]],
 +                                        &fr->nblists[m]);
 +                        m++;
 +                    } else if (fr->nnblists > 1) {
 +                        fr->gid2nblists[GID(egi,egj,ir->opts.ngener)] = 0;
 +                    }
 +                }
 +            }
 +        }
 +    }
 +    if (bSep14tab)
 +    {
 +        /* generate extra tables with plain Coulomb for 1-4 interactions only */
 +        fr->tab14 = make_tables(fp,oenv,fr,MASTER(cr),tabpfn,rtab,
 +                                GMX_MAKETABLES_14ONLY);
 +    }
 +
 +    /* Read AdResS Thermo Force table if needed */
 +    if(fr->adress_icor == eAdressICThermoForce)
 +    {
 +        /* old todo replace */ 
 +        
 +        if (ir->adress->n_tf_grps > 0){
 +            make_adress_tf_tables(fp,oenv,fr,ir,tabfn, mtop, box);
 +
 +        }else{
 +            /* load the default table */
 +            snew(fr->atf_tabs, 1);
 +            fr->atf_tabs[DEFAULT_TF_TABLE] = make_atf_table(fp,oenv,fr,tabafn, box);
 +        }
 +    }
 +    
 +    /* Wall stuff */
 +    fr->nwall = ir->nwall;
 +    if (ir->nwall && ir->wall_type==ewtTABLE)
 +    {
 +        make_wall_tables(fp,oenv,ir,tabfn,&mtop->groups,fr);
 +    }
 +    
 +    if (fcd && tabbfn) {
 +        fcd->bondtab  = make_bonded_tables(fp,
 +                                           F_TABBONDS,F_TABBONDSNC,
 +                                           mtop,tabbfn,"b");
 +        fcd->angletab = make_bonded_tables(fp,
 +                                           F_TABANGLES,-1,
 +                                           mtop,tabbfn,"a");
 +        fcd->dihtab   = make_bonded_tables(fp,
 +                                           F_TABDIHS,-1,
 +                                           mtop,tabbfn,"d");
 +    } else {
 +        if (debug)
 +            fprintf(debug,"No fcdata or table file name passed, can not read table, can not do bonded interactions\n");
 +    }
 +    
 +    /* QM/MM initialization if requested
 +     */
 +    if (ir->bQMMM)
 +    {
 +        fprintf(stderr,"QM/MM calculation requested.\n");
 +    }
 +    
 +    fr->bQMMM      = ir->bQMMM;   
 +    fr->qr         = mk_QMMMrec();
 +    
 +    /* Set all the static charge group info */
 +    fr->cginfo_mb = init_cginfo_mb(fp,mtop,fr,bNoSolvOpt,
 +                                   &fr->bExcl_IntraCGAll_InterCGNone);
 +    if (DOMAINDECOMP(cr)) {
 +        fr->cginfo = NULL;
 +    } else {
 +        fr->cginfo = cginfo_expand(mtop->nmolblock,fr->cginfo_mb);
 +    }
 +    
 +    if (!DOMAINDECOMP(cr))
 +    {
 +        /* When using particle decomposition, the effect of the second argument,
 +         * which sets fr->hcg, is corrected later in do_md and init_em.
 +         */
 +        forcerec_set_ranges(fr,ncg_mtop(mtop),ncg_mtop(mtop),
 +                            mtop->natoms,mtop->natoms,mtop->natoms);
 +    }
 +    
 +    fr->print_force = print_force;
 +
 +
 +    /* coarse load balancing vars */
 +    fr->t_fnbf=0.;
 +    fr->t_wait=0.;
 +    fr->timesteps=0;
 +    
 +    /* Initialize neighbor search */
 +    init_ns(fp,cr,&fr->ns,fr,mtop,box);
 +
 +    if (cr->duty & DUTY_PP)
 +    {
 +        gmx_nonbonded_setup(fp,fr,bGenericKernelOnly);
 +    /*
 +     if (ir->bAdress)
 +        {
 +            gmx_setup_adress_kernels(fp,bGenericKernelOnly);
 +        }
 +     */
 +    }
 +
 +    /* Initialize the thread working data for bonded interactions */
 +    init_forcerec_f_threads(fr,mtop->groups.grps[egcENER].nr);
 +    
 +    snew(fr->excl_load,fr->nthreads+1);
 +
 +    if (fr->cutoff_scheme == ecutsVERLET)
 +    {
 +        if (ir->rcoulomb != ir->rvdw)
 +        {
 +            gmx_fatal(FARGS,"With Verlet lists rcoulomb and rvdw should be identical");
 +        }
 +
 +        init_nb_verlet(fp, &fr->nbv, ir, fr, cr, nbpu_opt);
 +    }
 +
 +    /* fr->ic is used both by verlet and group kernels (to some extent) now */
 +    init_interaction_const(fp, &fr->ic, fr, rtab);
 +    if (ir->eDispCorr != edispcNO)
 +    {
 +        calc_enervirdiff(fp,ir->eDispCorr,fr);
 +    }
 +}
 +
 +#define pr_real(fp,r) fprintf(fp,"%s: %e\n",#r,r)
 +#define pr_int(fp,i)  fprintf((fp),"%s: %d\n",#i,i)
 +#define pr_bool(fp,b) fprintf((fp),"%s: %s\n",#b,bool_names[b])
 +
 +void pr_forcerec(FILE *fp,t_forcerec *fr,t_commrec *cr)
 +{
 +  int i;
 +
 +  pr_real(fp,fr->rlist);
 +  pr_real(fp,fr->rcoulomb);
 +  pr_real(fp,fr->fudgeQQ);
 +  pr_bool(fp,fr->bGrid);
 +  pr_bool(fp,fr->bTwinRange);
 +  /*pr_int(fp,fr->cg0);
 +    pr_int(fp,fr->hcg);*/
 +  for(i=0; i<fr->nnblists; i++)
 +    pr_int(fp,fr->nblists[i].table_elec_vdw.n);
 +  pr_real(fp,fr->rcoulomb_switch);
 +  pr_real(fp,fr->rcoulomb);
 +  
 +  fflush(fp);
 +}
 +
 +void forcerec_set_excl_load(t_forcerec *fr,
 +                            const gmx_localtop_t *top,const t_commrec *cr)
 +{
 +    const int *ind,*a;
 +    int t,i,j,ntot,n,ntarget;
 +
 +    if (cr != NULL && PARTDECOMP(cr))
 +    {
 +        /* No OpenMP with particle decomposition */
 +        pd_at_range(cr,
 +                    &fr->excl_load[0],
 +                    &fr->excl_load[1]);
 +
 +        return;
 +    }
 +
 +    ind = top->excls.index;
 +    a   = top->excls.a;
 +
 +    ntot = 0;
 +    for(i=0; i<top->excls.nr; i++)
 +    {
 +        for(j=ind[i]; j<ind[i+1]; j++)
 +        {
 +            if (a[j] > i)
 +            {
 +                ntot++;
 +            }
 +        }
 +    }
 +
 +    fr->excl_load[0] = 0;
 +    n = 0;
 +    i = 0;
 +    for(t=1; t<=fr->nthreads; t++)
 +    {
 +        ntarget = (ntot*t)/fr->nthreads;
 +        while(i < top->excls.nr && n < ntarget)
 +        {
 +            for(j=ind[i]; j<ind[i+1]; j++)
 +            {
 +                if (a[j] > i)
 +                {
 +                    n++;
 +                }
 +            }
 +            i++;
 +        }
 +        fr->excl_load[t] = i;
 +    }
 +}
 +
index d1e0849138c7bc38e937df4613d550c80a429971,0000000000000000000000000000000000000000..8184fddb8c6de8c6d198eb2971bea685ea4f9c08
mode 100644,000000..100644
--- /dev/null
@@@ -1,1358 -1,0 +1,1358 @@@
- #include "rdgroup.h"
 +/* -*- 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 <math.h>
 +#include <stdio.h>
 +#include <stdlib.h>
 +#include "futil.h"
++#include "index.h"
 +#include "statutil.h"
 +#include "gmxfio.h"
 +#include "vec.h" 
 +#include "typedefs.h"
 +#include "network.h"
 +#include "filenm.h"
 +#include <string.h>
 +#include "smalloc.h"
 +#include "pull.h"
 +#include "xvgr.h"
 +#include "names.h"
 +#include "partdec.h"
 +#include "pbc.h"
 +#include "mtop_util.h"
 +#include "mdrun.h"
 +#include "gmx_ga2la.h"
 +#include "copyrite.h"
 +#include "macros.h"
 +
 +static void pull_print_x_grp(FILE *out,gmx_bool bRef,ivec dim,t_pullgrp *pgrp) 
 +{
 +    int m;
 +    
 +    for(m=0; m<DIM; m++)
 +    {
 +        if (dim[m])
 +        {
 +            fprintf(out,"\t%g",bRef ? pgrp->x[m] : pgrp->dr[m]);
 +        }
 +    }
 +}
 +
 +static void pull_print_x(FILE *out,t_pull *pull,double t) 
 +{
 +    int g;
 +  
 +    fprintf(out, "%.4f", t);
 +    
 +    if (PULL_CYL(pull))
 +    {
 +        for (g=1; g<1+pull->ngrp; g++)
 +        {
 +            pull_print_x_grp(out,TRUE ,pull->dim,&pull->dyna[g]);
 +            pull_print_x_grp(out,FALSE,pull->dim,&pull->grp[g]);
 +        }
 +    }
 +    else
 +    {
 +        for (g=0; g<1+pull->ngrp; g++)
 +        {
 +            if (pull->grp[g].nat > 0)
 +            {
 +                pull_print_x_grp(out,g==0,pull->dim,&pull->grp[g]);
 +            }
 +        }
 +    }
 +    fprintf(out,"\n");
 +}
 +
 +static void pull_print_f(FILE *out,t_pull *pull,double t) 
 +{
 +    int g,d;
 +    
 +    fprintf(out, "%.4f", t);
 +    
 +    for(g=1; g<1+pull->ngrp; g++)
 +    {
 +        if (pull->eGeom == epullgPOS)
 +        {
 +            for(d=0; d<DIM; d++)
 +            {
 +                if (pull->dim[d])
 +                {
 +                    fprintf(out,"\t%g",pull->grp[g].f[d]);
 +                }
 +            }
 +        }
 +        else
 +        {
 +            fprintf(out,"\t%g",pull->grp[g].f_scal);
 +        }
 +    }
 +    fprintf(out,"\n");
 +}
 +
 +void pull_print_output(t_pull *pull, gmx_large_int_t step, double time)
 +{
 +    if ((pull->nstxout != 0) && (step % pull->nstxout == 0))
 +    {
 +        pull_print_x(pull->out_x,pull,time);
 +    }
 +    
 +    if ((pull->nstfout != 0) && (step % pull->nstfout == 0))
 +    {
 +        pull_print_f(pull->out_f,pull,time);
 +    }
 +}
 +
 +static FILE *open_pull_out(const char *fn,t_pull *pull,const output_env_t oenv, 
 +                           gmx_bool bCoord, unsigned long Flags)
 +{
 +    FILE *fp;
 +    int  nsets,g,m;
 +    char **setname,buf[10];
 +    
 +    if(Flags & MD_APPENDFILES)
 +    {
 +        fp = gmx_fio_fopen(fn,"a+");
 +    }
 +    else
 +    {
 +        fp = gmx_fio_fopen(fn,"w+");
 +        if (bCoord)
 +        {
 +            xvgr_header(fp,"Pull COM",  "Time (ps)","Position (nm)",
 +                        exvggtXNY,oenv);
 +        }
 +        else
 +        {
 +            xvgr_header(fp,"Pull force","Time (ps)","Force (kJ/mol/nm)",
 +                        exvggtXNY,oenv);
 +        }
 +        
 +        snew(setname,(1+pull->ngrp)*DIM);
 +        nsets = 0;
 +        for(g=0; g<1+pull->ngrp; g++)
 +        {
 +            if (pull->grp[g].nat > 0 &&
 +                (g > 0 || (bCoord && !PULL_CYL(pull))))
 +            {
 +                if (bCoord || pull->eGeom == epullgPOS)
 +                {
 +                    if (PULL_CYL(pull))
 +                    {
 +                        for(m=0; m<DIM; m++)
 +                        {
 +                            if (pull->dim[m])
 +                            {
 +                                sprintf(buf,"%d %s%c",g,"c",'X'+m);
 +                                setname[nsets] = strdup(buf);
 +                                nsets++;
 +                            }
 +                        }
 +                    }
 +                    for(m=0; m<DIM; m++)
 +                    {
 +                        if (pull->dim[m])
 +                        {
 +                            sprintf(buf,"%d %s%c",
 +                                    g,(bCoord && g > 0)?"d":"",'X'+m);
 +                            setname[nsets] = strdup(buf);
 +                            nsets++;
 +                        }
 +                    }
 +                }
 +                else
 +                {
 +                    sprintf(buf,"%d",g);
 +                    setname[nsets] = strdup(buf);
 +                    nsets++;
 +                }
 +            }
 +        }
 +        if (bCoord || nsets > 1)
 +        {
 +            xvgr_legend(fp,nsets,(const char**)setname,oenv);
 +        }
 +        for(g=0; g<nsets; g++)
 +        {
 +            sfree(setname[g]);
 +        }
 +        sfree(setname);
 +    }
 +    
 +    return fp;
 +}
 +
 +/* Apply forces in a mass weighted fashion */
 +static void apply_forces_grp(t_pullgrp *pgrp, t_mdatoms * md,
 +                             gmx_ga2la_t ga2la,
 +                             dvec f_pull, int sign, rvec *f)
 +{
 +    int i,ii,m,start,end;
 +    double wmass,inv_wm;
 +    
 +    start = md->start;
 +    end   = md->homenr + start;
 +    
 +    inv_wm = pgrp->wscale*pgrp->invtm;
 +    
 +    for(i=0; i<pgrp->nat_loc; i++)
 +    {
 +        ii = pgrp->ind_loc[i];
 +        wmass = md->massT[ii];
 +        if (pgrp->weight_loc)
 +        {
 +            wmass *= pgrp->weight_loc[i];
 +        }
 +    
 +        for(m=0; m<DIM; m++)
 +        {
 +            f[ii][m] += sign * wmass * f_pull[m] * inv_wm;
 +        }
 +    }
 +}
 +
 +/* Apply forces in a mass weighted fashion */
 +static void apply_forces(t_pull * pull, t_mdatoms * md, gmx_ga2la_t ga2la,
 +                         rvec *f)
 +{
 +    int i;
 +    t_pullgrp *pgrp;
 +    
 +    for(i=1; i<pull->ngrp+1; i++)
 +    {
 +        pgrp = &(pull->grp[i]);
 +        apply_forces_grp(pgrp,md,ga2la,pgrp->f,1,f);
 +        if (pull->grp[0].nat)
 +        {
 +            if (PULL_CYL(pull))
 +            {
 +                apply_forces_grp(&(pull->dyna[i]),md,ga2la,pgrp->f,-1,f);
 +            }
 +            else
 +            {
 +                apply_forces_grp(&(pull->grp[0]),md,ga2la,pgrp->f,-1,f);
 +            }
 +        }
 +    }
 +}
 +
 +static double max_pull_distance2(const t_pull *pull,const t_pbc *pbc)
 +{
 +    double max_d2;
 +    int    m;
 +
 +    max_d2 = GMX_DOUBLE_MAX;
 +
 +    if (pull->eGeom != epullgDIRPBC)
 +    {
 +        for(m=0; m<pbc->ndim_ePBC; m++)
 +        {
 +            if (pull->dim[m] != 0)
 +            {
 +                max_d2 = min(max_d2,norm2(pbc->box[m]));
 +            }
 +        }
 +    }
 +    
 +    return 0.25*max_d2;
 +}
 +
 +static void get_pullgrps_dr(const t_pull *pull,const t_pbc *pbc,int g,double t,
 +                            dvec xg,dvec xref,double max_dist2,
 +                            dvec dr)
 +{
 +    t_pullgrp *pref,*pgrp;
 +    int       m;
 +    dvec      xrefr,dref={0,0,0};
 +    double    dr2;
 +    
 +    pgrp = &pull->grp[g];
 +    
 +    copy_dvec(xref,xrefr);
 +
 +    if (pull->eGeom == epullgDIRPBC)
 +    {
 +        for(m=0; m<DIM; m++)
 +        {
 +            dref[m] = (pgrp->init[0] + pgrp->rate*t)*pull->grp[g].vec[m];
 +        }
 +        /* Add the reference position, so we use the correct periodic image */
 +        dvec_inc(xrefr,dref);
 +    }
 +  
 +    pbc_dx_d(pbc, xg, xrefr, dr);
 +    dr2 = 0;
 +    for(m=0; m<DIM; m++)
 +    {
 +        dr[m] *= pull->dim[m];
 +        dr2 += dr[m]*dr[m];
 +    }
 +    if (max_dist2 >= 0 && dr2 > 0.98*0.98*max_dist2)
 +    {
 +        gmx_fatal(FARGS,"Distance of pull group %d (%f nm) is larger than 0.49 times the box size (%f)",g,sqrt(dr2),sqrt(max_dist2));
 +    }
 +
 +    if (pull->eGeom == epullgDIRPBC)
 +    {
 +        dvec_inc(dr,dref);
 +    }
 +}
 +
 +static void get_pullgrp_dr(const t_pull *pull,const t_pbc *pbc,int g,double t,
 +                           dvec dr)
 +{
 +    double md2;
 +
 +    if (pull->eGeom == epullgDIRPBC)
 +    {
 +        md2 = -1;
 +    }
 +    else
 +    {
 +        md2 = max_pull_distance2(pull,pbc);
 +    }
 +
 +    get_pullgrps_dr(pull,pbc,g,t,
 +                    pull->grp[g].x,
 +                    PULL_CYL(pull) ? pull->dyna[g].x : pull->grp[0].x,
 +                    md2,
 +                    dr);
 +}
 +
 +void get_pullgrp_distance(t_pull *pull,t_pbc *pbc,int g,double t,
 +                          dvec dr,dvec dev)
 +{
 +    static gmx_bool bWarned=FALSE; /* TODO: this should be fixed for thread-safety, 
 +                                  but is fairly benign */
 +    t_pullgrp *pgrp;
 +    int       m;
 +    dvec      ref;
 +    double    drs,inpr;
 +    
 +    pgrp = &pull->grp[g];
 +    
 +    get_pullgrp_dr(pull,pbc,g,t,dr);
 +    
 +    if (pull->eGeom == epullgPOS)
 +    {
 +        for(m=0; m<DIM; m++)
 +        {
 +            ref[m] = pgrp->init[m] + pgrp->rate*t*pgrp->vec[m];
 +        }
 +    }
 +    else
 +    {
 +        ref[0] = pgrp->init[0] + pgrp->rate*t;
 +    }
 +    
 +    switch (pull->eGeom)
 +    {
 +    case epullgDIST:
 +        /* Pull along the vector between the com's */
 +        if (ref[0] < 0 && !bWarned)
 +        {
 +            fprintf(stderr,"\nPull reference distance for group %d is negative (%f)\n",g,ref[0]);
 +            bWarned = TRUE;
 +        }
 +        drs = dnorm(dr);
 +        if (drs == 0)
 +        {
 +            /* With no vector we can not determine the direction for the force,
 +             * so we set the force to zero.
 +             */
 +            dev[0] = 0;
 +        }
 +        else
 +        {
 +            /* Determine the deviation */
 +            dev[0] = drs - ref[0];
 +        }
 +        break;
 +    case epullgDIR:
 +    case epullgDIRPBC:
 +    case epullgCYL:
 +        /* Pull along vec */
 +        inpr = 0;
 +        for(m=0; m<DIM; m++)
 +        {
 +            inpr += pgrp->vec[m]*dr[m];
 +        }
 +        dev[0] = inpr - ref[0];
 +        break;
 +    case epullgPOS:
 +        /* Determine the difference of dr and ref along each dimension */
 +        for(m=0; m<DIM; m++)
 +        {
 +            dev[m] = (dr[m] - ref[m])*pull->dim[m];
 +        }
 +        break;
 +    }
 +}
 +
 +void clear_pull_forces(t_pull *pull)
 +{
 +    int i;
 +    
 +    /* Zeroing the forces is only required for constraint pulling.
 +     * It can happen that multiple constraint steps need to be applied
 +     * and therefore the constraint forces need to be accumulated.
 +     */
 +    for(i=0; i<1+pull->ngrp; i++)
 +    {
 +        clear_dvec(pull->grp[i].f);
 +        pull->grp[i].f_scal = 0;
 +    }
 +}
 +
 +/* Apply constraint using SHAKE */
 +static void do_constraint(t_pull *pull, t_mdatoms *md, t_pbc *pbc,
 +                          rvec *x, rvec *v,
 +                          gmx_bool bMaster, tensor vir,
 +                          double dt, double t) 
 +{
 +
 +    dvec *r_ij;  /* x[i] com of i in prev. step. Obeys constr. -> r_ij[i] */
 +    dvec unc_ij; /* xp[i] com of i this step, before constr.   -> unc_ij  */
 +
 +    dvec *rinew;           /* current 'new' position of group i */
 +    dvec *rjnew;           /* current 'new' position of group j */
 +    dvec  ref,vec;
 +    double d0,inpr;
 +    double lambda, rm, mass, invdt=0;
 +    gmx_bool bConverged_all,bConverged=FALSE;
 +    int niter=0,g,ii,j,m,max_iter=100;
 +    double q,a,b,c;  /* for solving the quadratic equation, 
 +                        see Num. Recipes in C ed 2 p. 184 */
 +    dvec *dr;        /* correction for group i */
 +    dvec ref_dr;     /* correction for group j */
 +    dvec f;          /* the pull force */
 +    dvec tmp,tmp3;
 +    t_pullgrp *pdyna,*pgrp,*pref;
 +    
 +    snew(r_ij,pull->ngrp+1);
 +    if (PULL_CYL(pull))
 +    {
 +        snew(rjnew,pull->ngrp+1);
 +    }
 +    else
 +    {
 +        snew(rjnew,1);
 +    }
 +    snew(dr,pull->ngrp+1);
 +    snew(rinew,pull->ngrp+1);
 +    
 +    /* copy the current unconstrained positions for use in iterations. We 
 +       iterate until rinew[i] and rjnew[j] obey the constraints. Then
 +       rinew - pull.x_unc[i] is the correction dr to group i */
 +    for(g=1; g<1+pull->ngrp; g++)
 +    {
 +        copy_dvec(pull->grp[g].xp,rinew[g]);
 +    }
 +    if (PULL_CYL(pull))
 +    {
 +        for(g=1; g<1+pull->ngrp; g++)
 +        {
 +            copy_dvec(pull->dyna[g].xp,rjnew[g]);
 +        }
 +    }
 +    else
 +    {
 +        copy_dvec(pull->grp[0].xp,rjnew[0]);
 +    }
 +    
 +    /* Determine the constraint directions from the old positions */
 +    for(g=1; g<1+pull->ngrp; g++)
 +    {
 +        get_pullgrp_dr(pull,pbc,g,t,r_ij[g]);
 +        /* Store the difference vector at time t for printing */
 +        copy_dvec(r_ij[g],pull->grp[g].dr);
 +        if (debug)
 +        {
 +            fprintf(debug,"Pull group %d dr %f %f %f\n",
 +                    g,r_ij[g][XX],r_ij[g][YY],r_ij[g][ZZ]);
 +        }
 +        
 +        if (pull->eGeom == epullgDIR || pull->eGeom == epullgDIRPBC)
 +        {
 +            /* Select the component along vec */
 +            a = 0;
 +            for(m=0; m<DIM; m++)
 +            {
 +                a += pull->grp[g].vec[m]*r_ij[g][m];
 +            }
 +            for(m=0; m<DIM; m++)
 +            {
 +                r_ij[g][m] = a*pull->grp[g].vec[m];
 +            }
 +        }
 +    }
 +    
 +    bConverged_all = FALSE;
 +    while (!bConverged_all && niter < max_iter)
 +    {
 +        bConverged_all = TRUE;
 +
 +        /* loop over all constraints */
 +        for(g=1; g<1+pull->ngrp; g++)
 +        {
 +            pgrp = &pull->grp[g];
 +            if (PULL_CYL(pull))
 +                pref = &pull->dyna[g];
 +            else
 +                pref = &pull->grp[0];
 +
 +            /* Get the current difference vector */
 +            get_pullgrps_dr(pull,pbc,g,t,rinew[g],rjnew[PULL_CYL(pull) ? g : 0],
 +                            -1,unc_ij);
 +
 +            if (pull->eGeom == epullgPOS)
 +            {
 +                for(m=0; m<DIM; m++)
 +                {
 +                    ref[m] = pgrp->init[m] + pgrp->rate*t*pgrp->vec[m];
 +                }
 +            }
 +            else
 +            {
 +                ref[0] = pgrp->init[0] + pgrp->rate*t;
 +                /* Keep the compiler happy */
 +                ref[1] = 0;
 +                ref[2] = 0;
 +            }
 +            
 +            if (debug)
 +            {
 +                fprintf(debug,"Pull group %d, iteration %d\n",g,niter);
 +            }
 +            
 +            rm = 1.0/(pull->grp[g].invtm + pref->invtm);
 +            
 +            switch (pull->eGeom)
 +            {
 +            case epullgDIST:
 +                if (ref[0] <= 0)
 +                {
 +                    gmx_fatal(FARGS,"The pull constraint reference distance for group %d is <= 0 (%f)",g,ref[0]);
 +                }
 +                
 +                a = diprod(r_ij[g],r_ij[g]); 
 +                b = diprod(unc_ij,r_ij[g])*2;
 +                c = diprod(unc_ij,unc_ij) - dsqr(ref[0]);
 +                
 +                if (b < 0)
 +                {
 +                    q = -0.5*(b - sqrt(b*b - 4*a*c));
 +                    lambda = -q/a;
 +                }
 +                else
 +                {
 +                    q = -0.5*(b + sqrt(b*b - 4*a*c));
 +                    lambda = -c/q;
 +                }
 +                
 +                if (debug)
 +                {
 +                    fprintf(debug,
 +                            "Pull ax^2+bx+c=0: a=%e b=%e c=%e lambda=%e\n",
 +                            a,b,c,lambda);
 +                }
 +                
 +                /* The position corrections dr due to the constraints */
 +                dsvmul(-lambda*rm*pgrp->invtm, r_ij[g],  dr[g]);
 +                dsvmul( lambda*rm*pref->invtm, r_ij[g], ref_dr);
 +                break;
 +            case epullgDIR:
 +            case epullgDIRPBC:
 +            case epullgCYL:
 +                /* A 1-dimensional constraint along a vector */
 +                a = 0;
 +                for(m=0; m<DIM; m++)
 +                {
 +                    vec[m] = pgrp->vec[m];
 +                    a += unc_ij[m]*vec[m];
 +                }
 +                /* Select only the component along the vector */
 +                dsvmul(a,vec,unc_ij);
 +                lambda = a - ref[0];
 +                if (debug)
 +                {
 +                    fprintf(debug,"Pull inpr %e lambda: %e\n",a,lambda);
 +                }
 +                
 +                /* The position corrections dr due to the constraints */
 +                dsvmul(-lambda*rm*pull->grp[g].invtm, vec, dr[g]);
 +                dsvmul( lambda*rm*       pref->invtm, vec,ref_dr);
 +                break;
 +            case epullgPOS:
 +                for(m=0; m<DIM; m++)
 +                {
 +                    if (pull->dim[m])
 +                    {
 +                        lambda = r_ij[g][m] - ref[m];
 +                        /* The position corrections dr due to the constraints */
 +                        dr[g][m]  = -lambda*rm*pull->grp[g].invtm;
 +                        ref_dr[m] =  lambda*rm*pref->invtm;
 +                    }
 +                    else
 +                    {
 +                        dr[g][m]  = 0;
 +                        ref_dr[m] = 0;
 +                    }
 +                }
 +                break;
 +            }
 +            
 +            /* DEBUG */
 +            if (debug)
 +            {
 +                j = (PULL_CYL(pull) ? g : 0);
 +                get_pullgrps_dr(pull,pbc,g,t,rinew[g],rjnew[j],-1,tmp);
 +                get_pullgrps_dr(pull,pbc,g,t,dr[g]   ,ref_dr  ,-1,tmp3);
 +                fprintf(debug,
 +                        "Pull cur %8.5f %8.5f %8.5f j:%8.5f %8.5f %8.5f d: %8.5f\n",
 +                        rinew[g][0],rinew[g][1],rinew[g][2], 
 +                        rjnew[j][0],rjnew[j][1],rjnew[j][2], dnorm(tmp));
 +                if (pull->eGeom == epullgPOS)
 +                {
 +                    fprintf(debug,
 +                            "Pull ref %8.5f %8.5f %8.5f\n",
 +                            pgrp->vec[0],pgrp->vec[1],pgrp->vec[2]);
 +                }
 +                else
 +                {
 +                    fprintf(debug,
 +                            "Pull ref %8s %8s %8s   %8s %8s %8s d: %8.5f %8.5f %8.5f\n",
 +                            "","","","","","",ref[0],ref[1],ref[2]);
 +                }
 +                fprintf(debug,
 +                        "Pull cor %8.5f %8.5f %8.5f j:%8.5f %8.5f %8.5f d: %8.5f\n",
 +                        dr[g][0],dr[g][1],dr[g][2],
 +                        ref_dr[0],ref_dr[1],ref_dr[2],
 +                        dnorm(tmp3));
 +                fprintf(debug,
 +                        "Pull cor %10.7f %10.7f %10.7f\n",
 +                        dr[g][0],dr[g][1],dr[g][2]);
 +            } /* END DEBUG */
 +            
 +            /* Update the COMs with dr */
 +            dvec_inc(rinew[g],                     dr[g]);
 +            dvec_inc(rjnew[PULL_CYL(pull) ? g : 0],ref_dr);
 +        }
 +        
 +        /* Check if all constraints are fullfilled now */
 +        for(g=1; g<1+pull->ngrp; g++)
 +        {
 +            pgrp = &pull->grp[g];
 +            
 +            get_pullgrps_dr(pull,pbc,g,t,rinew[g],rjnew[PULL_CYL(pull) ? g : 0],
 +                            -1,unc_ij);
 +            
 +            switch (pull->eGeom)
 +            {
 +            case epullgDIST:
 +                bConverged = fabs(dnorm(unc_ij) - ref[0]) < pull->constr_tol;
 +                break;
 +            case epullgDIR:
 +            case epullgDIRPBC:
 +            case epullgCYL:
 +                for(m=0; m<DIM; m++)
 +                {
 +                    vec[m] = pgrp->vec[m];
 +                }
 +                inpr = diprod(unc_ij,vec);
 +                dsvmul(inpr,vec,unc_ij);
 +                bConverged =
 +                    fabs(diprod(unc_ij,vec) - ref[0]) < pull->constr_tol;
 +                break;
 +            case epullgPOS:
 +                bConverged = TRUE;
 +                for(m=0; m<DIM; m++)
 +                {
 +                    if (pull->dim[m] && 
 +                        fabs(unc_ij[m] - ref[m]) >= pull->constr_tol)
 +                    {
 +                        bConverged = FALSE;
 +                    }
 +                }
 +                break;
 +            }
 +            
 +            if (!bConverged)
 +            {
 +                if (debug)
 +                {
 +                    fprintf(debug,"NOT CONVERGED YET: Group %d:"
 +                            "d_ref = %f %f %f, current d = %f\n",
 +                            g,ref[0],ref[1],ref[2],dnorm(unc_ij));
 +                }
 +
 +                bConverged_all = FALSE;
 +            }
 +        }
 +        
 +        niter++;
 +        /* if after all constraints are dealt with and bConverged is still TRUE
 +           we're finished, if not we do another iteration */
 +    }
 +    if (niter > max_iter)
 +    {
 +        gmx_fatal(FARGS,"Too many iterations for constraint run: %d",niter);
 +    }
 +    
 +    /* DONE ITERATING, NOW UPDATE COORDINATES AND CALC. CONSTRAINT FORCES */
 +    
 +    if (v)
 +    {
 +        invdt = 1/dt;
 +    }
 +    
 +    /* update the normal groups */
 +    for(g=1; g<1+pull->ngrp; g++)
 +    {
 +        pgrp = &pull->grp[g];
 +        /* get the final dr and constraint force for group i */
 +        dvec_sub(rinew[g],pgrp->xp,dr[g]);
 +        /* select components of dr */
 +        for(m=0; m<DIM; m++)
 +        {
 +            dr[g][m] *= pull->dim[m];
 +        }
 +        dsvmul(1.0/(pgrp->invtm*dt*dt),dr[g],f);
 +        dvec_inc(pgrp->f,f);
 +        switch (pull->eGeom)
 +        {
 +        case epullgDIST:
 +            for(m=0; m<DIM; m++)
 +            {
 +                pgrp->f_scal += r_ij[g][m]*f[m]/dnorm(r_ij[g]);
 +            }
 +            break;
 +        case epullgDIR:
 +        case epullgDIRPBC:
 +        case epullgCYL:
 +            for(m=0; m<DIM; m++)
 +            {
 +                pgrp->f_scal += pgrp->vec[m]*f[m];
 +            }
 +            break;
 +        case epullgPOS:
 +            break;
 +        }
 +        
 +        if (vir && bMaster) {
 +            /* Add the pull contribution to the virial */
 +            for(j=0; j<DIM; j++)
 +            {
 +                for(m=0; m<DIM; m++)
 +                {
 +                    vir[j][m] -= 0.5*f[j]*r_ij[g][m];
 +                }
 +            }
 +        }
 +        
 +        /* update the atom positions */
 +        copy_dvec(dr[g],tmp);
 +        for(j=0;j<pgrp->nat_loc;j++)
 +        {
 +            ii = pgrp->ind_loc[j];
 +            if (pgrp->weight_loc)
 +            {
 +                dsvmul(pgrp->wscale*pgrp->weight_loc[j],dr[g],tmp); 
 +            }
 +            for(m=0; m<DIM; m++)
 +            {
 +                x[ii][m] += tmp[m];
 +            }
 +            if (v)
 +            {
 +                for(m=0; m<DIM; m++)
 +                {
 +                    v[ii][m] += invdt*tmp[m];
 +                }
 +            }
 +        }
 +    }
 +    
 +    /* update the reference groups */
 +    if (PULL_CYL(pull))
 +    {
 +        /* update the dynamic reference groups */
 +        for(g=1; g<1+pull->ngrp; g++)
 +        {
 +            pdyna = &pull->dyna[g];
 +            dvec_sub(rjnew[g],pdyna->xp,ref_dr);
 +            /* select components of ref_dr */
 +            for(m=0; m<DIM; m++)
 +            {
 +                ref_dr[m] *= pull->dim[m];
 +            }
 +            
 +            for(j=0;j<pdyna->nat_loc;j++)
 +            {
 +                /* reset the atoms with dr, weighted by w_i */
 +                dsvmul(pdyna->wscale*pdyna->weight_loc[j],ref_dr,tmp); 
 +                ii = pdyna->ind_loc[j];
 +                for(m=0; m<DIM; m++)
 +                {
 +                    x[ii][m] += tmp[m];
 +                }
 +                if (v)
 +                {
 +                    for(m=0; m<DIM; m++)
 +                    {
 +                        v[ii][m] += invdt*tmp[m];
 +                    }
 +                }
 +            }
 +        }
 +    }
 +    else
 +    {
 +        pgrp = &pull->grp[0];
 +        /* update the reference group */
 +        dvec_sub(rjnew[0],pgrp->xp, ref_dr); 
 +        /* select components of ref_dr */
 +        for(m=0;m<DIM;m++)
 +        {
 +            ref_dr[m] *= pull->dim[m];
 +        }
 +        
 +        copy_dvec(ref_dr,tmp);
 +        for(j=0; j<pgrp->nat_loc;j++)
 +        {
 +            ii = pgrp->ind_loc[j];
 +            if (pgrp->weight_loc)
 +            {
 +                dsvmul(pgrp->wscale*pgrp->weight_loc[j],ref_dr,tmp); 
 +            }
 +            for(m=0; m<DIM; m++)
 +            {
 +                x[ii][m] += tmp[m];
 +            }
 +            if (v)
 +            {
 +                for(m=0; m<DIM; m++)
 +                {
 +                    v[ii][m] += invdt*tmp[m];
 +                }
 +            }
 +        }
 +    }
 +    
 +    /* finished! I hope. Give back some memory */
 +    sfree(r_ij);
 +    sfree(rinew);
 +    sfree(rjnew);
 +    sfree(dr);
 +}
 +
 +/* Pulling with a harmonic umbrella potential or constant force */
 +static void do_pull_pot(int ePull,
 +                        t_pull *pull, t_pbc *pbc, double t, real lambda,
 +                        real *V, tensor vir, real *dVdl)
 +{
 +    int       g,j,m;
 +    dvec      dev;
 +    double    ndr,invdr;
 +    real      k,dkdl;
 +    t_pullgrp *pgrp;
 +    
 +    /* loop over the groups that are being pulled */
 +    *V    = 0;
 +    *dVdl = 0;
 +    for(g=1; g<1+pull->ngrp; g++)
 +    {
 +        pgrp = &pull->grp[g];
 +        get_pullgrp_distance(pull,pbc,g,t,pgrp->dr,dev);
 +        
 +        k    = (1.0 - lambda)*pgrp->k + lambda*pgrp->kB;
 +        dkdl = pgrp->kB - pgrp->k;
 +        
 +        switch (pull->eGeom)
 +        {
 +        case epullgDIST:
 +            ndr   = dnorm(pgrp->dr);
 +            invdr = 1/ndr;
 +            if (ePull == epullUMBRELLA)
 +            {
 +                pgrp->f_scal  =       -k*dev[0];
 +                *V           += 0.5*   k*dsqr(dev[0]);
 +                *dVdl        += 0.5*dkdl*dsqr(dev[0]);
 +            }
 +            else
 +            {
 +                pgrp->f_scal  =   -k;
 +                *V           +=    k*ndr;
 +                *dVdl        += dkdl*ndr;
 +            }
 +            for(m=0; m<DIM; m++)
 +            {
 +                pgrp->f[m]    = pgrp->f_scal*pgrp->dr[m]*invdr;
 +            }
 +            break;
 +        case epullgDIR:
 +        case epullgDIRPBC:
 +        case epullgCYL:
 +            if (ePull == epullUMBRELLA)
 +            {
 +                pgrp->f_scal  =       -k*dev[0];
 +                *V           += 0.5*   k*dsqr(dev[0]);
 +                *dVdl        += 0.5*dkdl*dsqr(dev[0]);
 +            }
 +            else
 +            {
 +                ndr = 0;
 +                for(m=0; m<DIM; m++)
 +                {
 +                    ndr += pgrp->vec[m]*pgrp->dr[m];
 +                }
 +                pgrp->f_scal  =   -k;
 +                *V           +=    k*ndr;
 +                *dVdl        += dkdl*ndr;
 +            }
 +            for(m=0; m<DIM; m++)
 +            {
 +                pgrp->f[m]    = pgrp->f_scal*pgrp->vec[m];
 +            }
 +            break;
 +        case epullgPOS:
 +            for(m=0; m<DIM; m++)
 +            {
 +                if (ePull == epullUMBRELLA)
 +                {
 +                    pgrp->f[m]  =       -k*dev[m];
 +                    *V         += 0.5*   k*dsqr(dev[m]);
 +                    *dVdl      += 0.5*dkdl*dsqr(dev[m]);
 +                }
 +                else
 +                {
 +                    pgrp->f[m]  =   -k*pull->dim[m];
 +                    *V         +=    k*pgrp->dr[m]*pull->dim[m];
 +                    *dVdl      += dkdl*pgrp->dr[m]*pull->dim[m];
 +                }
 +            }
 +            break;
 +        }
 +        
 +        if (vir)
 +        {
 +            /* Add the pull contribution to the virial */
 +            for(j=0; j<DIM; j++)
 +            {
 +                for(m=0;m<DIM;m++)
 +                {
 +                    vir[j][m] -= 0.5*pgrp->f[j]*pgrp->dr[m];
 +                }
 +            }
 +        }
 +    }
 +}
 +
 +real pull_potential(int ePull,t_pull *pull, t_mdatoms *md, t_pbc *pbc,
 +                  t_commrec *cr, double t, real lambda,
 +                  rvec *x, rvec *f, tensor vir, real *dvdlambda)
 +{
 +  real V,dVdl;
 +
 +  pull_calc_coms(cr,pull,md,pbc,t,x,NULL);
 +
 +  do_pull_pot(ePull,pull,pbc,t,lambda,
 +            &V,pull->bVirial && MASTER(cr) ? vir : NULL,&dVdl);
 +
 +  /* Distribute forces over pulled groups */
 +  apply_forces(pull, md, DOMAINDECOMP(cr) ? cr->dd->ga2la : NULL, f);
 +
 +  if (MASTER(cr)) {
 +    *dvdlambda += dVdl;
 +  }
 +
 +  return (MASTER(cr) ? V : 0.0);
 +}
 +
 +void pull_constraint(t_pull *pull, t_mdatoms *md, t_pbc *pbc,
 +                   t_commrec *cr, double dt, double t,
 +                   rvec *x, rvec *xp, rvec *v, tensor vir)
 +{
 +  pull_calc_coms(cr,pull,md,pbc,t,x,xp);
 +
 +  do_constraint(pull,md,pbc,xp,v,pull->bVirial && MASTER(cr),vir,dt,t);
 +}
 +
 +static void make_local_pull_group(gmx_ga2la_t ga2la,
 +                                t_pullgrp *pg,int start,int end)
 +{
 +  int i,ii;
 +
 +  pg->nat_loc = 0;
 +  for(i=0; i<pg->nat; i++) {
 +    ii = pg->ind[i];
 +    if (ga2la) {
 +      if (!ga2la_get_home(ga2la,ii,&ii)) {
 +        ii = -1;
 +      }
 +    }
 +    if (ii >= start && ii < end) {
 +      /* This is a home atom, add it to the local pull group */
 +      if (pg->nat_loc >= pg->nalloc_loc) {
 +      pg->nalloc_loc = over_alloc_dd(pg->nat_loc+1);
 +      srenew(pg->ind_loc,pg->nalloc_loc);
 +      if (pg->epgrppbc == epgrppbcCOS || pg->weight) {
 +        srenew(pg->weight_loc,pg->nalloc_loc);
 +      }
 +      }
 +      pg->ind_loc[pg->nat_loc] = ii;
 +      if (pg->weight) {
 +        pg->weight_loc[pg->nat_loc] = pg->weight[i];
 +      }
 +      pg->nat_loc++;
 +    }
 +  }
 +}
 +
 +void dd_make_local_pull_groups(gmx_domdec_t *dd,t_pull *pull,t_mdatoms *md)
 +{
 +  gmx_ga2la_t ga2la;
 +  int g;
 +  
 +  if (dd) {
 +    ga2la = dd->ga2la;
 +  } else {
 +    ga2la = NULL;
 +  }
 +
 +  if (pull->grp[0].nat > 0)
 +    make_local_pull_group(ga2la,&pull->grp[0],md->start,md->start+md->homenr);
 +  for(g=1; g<1+pull->ngrp; g++)
 +    make_local_pull_group(ga2la,&pull->grp[g],md->start,md->start+md->homenr);
 +}
 +
 +static void init_pull_group_index(FILE *fplog,t_commrec *cr,
 +                                  int start,int end,
 +                                  int g,t_pullgrp *pg,ivec pulldims,
 +                                  gmx_mtop_t *mtop,t_inputrec *ir, real lambda)
 +{
 +  int i,ii,d,nfrozen,ndim;
 +  real m,w,mbd;
 +  double tmass,wmass,wwmass;
 +  gmx_bool bDomDec;
 +  gmx_ga2la_t ga2la=NULL;
 +  gmx_groups_t *groups;
 +  gmx_mtop_atomlookup_t alook;
 +  t_atom *atom;
 +
 +  bDomDec = (cr && DOMAINDECOMP(cr));
 +  if (bDomDec) {
 +    ga2la = cr->dd->ga2la;
 +  }
 +
 +  if (EI_ENERGY_MINIMIZATION(ir->eI) || ir->eI == eiBD) {
 +    /* There are no masses in the integrator.
 +     * But we still want to have the correct mass-weighted COMs.
 +     * So we store the real masses in the weights.
 +     * We do not set nweight, so these weights do not end up in the tpx file.
 +     */
 +    if (pg->nweight == 0) {
 +      snew(pg->weight,pg->nat);
 +    }
 +  }
 +
 +  if (cr && PAR(cr)) {
 +    pg->nat_loc    = 0;
 +    pg->nalloc_loc = 0;
 +    pg->ind_loc    = NULL;
 +    pg->weight_loc = NULL;
 +  } else {
 +    pg->nat_loc = pg->nat;
 +    pg->ind_loc = pg->ind;
 +    if (pg->epgrppbc == epgrppbcCOS) {
 +      snew(pg->weight_loc,pg->nat);
 +    } else {
 +      pg->weight_loc = pg->weight;
 +    }
 +  }
 +
 +  groups = &mtop->groups;
 +
 +  alook = gmx_mtop_atomlookup_init(mtop);
 +
 +  nfrozen = 0;
 +  tmass  = 0;
 +  wmass  = 0;
 +  wwmass = 0;
 +  for(i=0; i<pg->nat; i++) {
 +    ii = pg->ind[i];
 +    gmx_mtop_atomnr_to_atom(alook,ii,&atom);
 +    if (cr && PAR(cr) && !bDomDec && ii >= start && ii < end)
 +      pg->ind_loc[pg->nat_loc++] = ii;
 +    if (ir->opts.nFreeze) {
 +      for(d=0; d<DIM; d++)
 +      if (pulldims[d] && ir->opts.nFreeze[ggrpnr(groups,egcFREEZE,ii)][d])
 +        nfrozen++;
 +    }
 +    if (ir->efep == efepNO) {
 +      m = atom->m;
 +    } else {
 +      m = (1 - lambda)*atom->m + lambda*atom->mB;
 +    }
 +    if (pg->nweight > 0) {
 +      w = pg->weight[i];
 +    } else {
 +      w = 1;
 +    }
 +    if (EI_ENERGY_MINIMIZATION(ir->eI)) {
 +      /* Move the mass to the weight */
 +      w *= m;
 +      m = 1;
 +      pg->weight[i] = w;
 +    } else if (ir->eI == eiBD) {
 +      if (ir->bd_fric) {
 +      mbd = ir->bd_fric*ir->delta_t;
 +      } else {
 +      if (groups->grpnr[egcTC] == NULL) {
 +        mbd = ir->delta_t/ir->opts.tau_t[0];
 +      } else {
 +        mbd = ir->delta_t/ir->opts.tau_t[groups->grpnr[egcTC][ii]];
 +      }
 +      }
 +      w *= m/mbd;
 +      m = mbd;
 +      pg->weight[i] = w;
 +    }
 +    tmass  += m;
 +    wmass  += m*w;
 +    wwmass += m*w*w;
 +  }
 +
 +  gmx_mtop_atomlookup_destroy(alook);
 +
 +  if (wmass == 0) {
 +    gmx_fatal(FARGS,"The total%s mass of pull group %d is zero",
 +            pg->weight ? " weighted" : "",g);
 +  }
 +  if (fplog) {
 +    fprintf(fplog,
 +          "Pull group %d: %5d atoms, mass %9.3f",g,pg->nat,tmass);
 +    if (pg->weight || EI_ENERGY_MINIMIZATION(ir->eI) || ir->eI == eiBD) {
 +      fprintf(fplog,", weighted mass %9.3f",wmass*wmass/wwmass);
 +    }
 +    if (pg->epgrppbc == epgrppbcCOS) {
 +      fprintf(fplog,", cosine weighting will be used");
 +    }
 +    fprintf(fplog,"\n");
 +  }
 +  
 +  if (nfrozen == 0) {
 +    /* A value > 0 signals not frozen, it is updated later */
 +    pg->invtm  = 1.0;
 +  } else {
 +    ndim = 0;
 +    for(d=0; d<DIM; d++)
 +      ndim += pulldims[d]*pg->nat;
 +    if (fplog && nfrozen > 0 && nfrozen < ndim) {
 +      fprintf(fplog,
 +            "\nWARNING: In pull group %d some, but not all of the degrees of freedom\n"
 +            "         that are subject to pulling are frozen.\n"
 +            "         For pulling the whole group will be frozen.\n\n",
 +            g);
 +    }
 +    pg->invtm  = 0.0;
 +    pg->wscale = 1.0;
 +  }
 +}
 +
 +void init_pull(FILE *fplog,t_inputrec *ir,int nfile,const t_filenm fnm[],
 +               gmx_mtop_t *mtop,t_commrec *cr,const output_env_t oenv, real lambda,
 +               gmx_bool bOutFile, unsigned long Flags)
 +{
 +    t_pull    *pull;
 +    t_pullgrp *pgrp;
 +    int       g,start=0,end=0,m;
 +    gmx_bool      bCite;
 +    
 +    pull = ir->pull;
 +    
 +    pull->ePBC = ir->ePBC;
 +    switch (pull->ePBC)
 +    {
 +    case epbcNONE: pull->npbcdim = 0; break;
 +    case epbcXY:   pull->npbcdim = 2; break;
 +    default:       pull->npbcdim = 3; break;
 +    }
 +    
 +    if (fplog)
 +    {
 +        fprintf(fplog,"\nWill apply %s COM pulling in geometry '%s'\n",
 +                EPULLTYPE(ir->ePull),EPULLGEOM(pull->eGeom));
 +        if (pull->grp[0].nat > 0)
 +        {
 +            fprintf(fplog,"between a reference group and %d group%s\n",
 +                    pull->ngrp,pull->ngrp==1 ? "" : "s");
 +        }
 +        else
 +        {
 +            fprintf(fplog,"with an absolute reference on %d group%s\n",
 +                    pull->ngrp,pull->ngrp==1 ? "" : "s");
 +        }
 +        bCite = FALSE;
 +        for(g=0; g<pull->ngrp+1; g++)
 +        {
 +            if (pull->grp[g].nat > 1 &&
 +                pull->grp[g].pbcatom < 0)
 +            {
 +                /* We are using cosine weighting */
 +                fprintf(fplog,"Cosine weighting is used for group %d\n",g);
 +                bCite = TRUE;
 +            }
 +        }
 +        if (bCite)
 +        {
 +            please_cite(fplog,"Engin2010");
 +        }
 +    }
 +    
 +    /* We always add the virial contribution,
 +     * except for geometry = direction_periodic where this is impossible.
 +     */
 +    pull->bVirial = (pull->eGeom != epullgDIRPBC);
 +    if (getenv("GMX_NO_PULLVIR") != NULL)
 +    {
 +        if (fplog)
 +        {
 +            fprintf(fplog,"Found env. var., will not add the virial contribution of the COM pull forces\n");
 +        }
 +        pull->bVirial = FALSE;
 +    }
 +    
 +    if (cr && PARTDECOMP(cr))
 +    {
 +        pd_at_range(cr,&start,&end);
 +    }
 +    pull->rbuf=NULL;
 +    pull->dbuf=NULL;
 +    pull->dbuf_cyl=NULL;
 +    pull->bRefAt = FALSE;
 +    pull->cosdim = -1;
 +    for(g=0; g<pull->ngrp+1; g++)
 +    {
 +        pgrp = &pull->grp[g];
 +        pgrp->epgrppbc = epgrppbcNONE;
 +        if (pgrp->nat > 0)
 +        {
 +            /* Determine if we need to take PBC into account for calculating
 +             * the COM's of the pull groups.
 +             */
 +            for(m=0; m<pull->npbcdim; m++)
 +            {
 +                if (pull->dim[m] && pgrp->nat > 1)
 +                {
 +                    if (pgrp->pbcatom >= 0)
 +                    {
 +                        pgrp->epgrppbc = epgrppbcREFAT;
 +                        pull->bRefAt   = TRUE;
 +                    }
 +                    else
 +                    {
 +                        if (pgrp->weight)
 +                        {
 +                            gmx_fatal(FARGS,"Pull groups can not have relative weights and cosine weighting at same time");
 +                        }
 +                        pgrp->epgrppbc = epgrppbcCOS;
 +                        if (pull->cosdim >= 0 && pull->cosdim != m)
 +                        {
 +                            gmx_fatal(FARGS,"Can only use cosine weighting with pulling in one dimension (use mdp option pull_dim)");
 +                        }
 +                        pull->cosdim = m;
 +                    }
 +                }
 +            }
 +            /* Set the indices */
 +            init_pull_group_index(fplog,cr,start,end,g,pgrp,pull->dim,mtop,ir,lambda);
 +            if (PULL_CYL(pull) && pgrp->invtm == 0)
 +            {
 +                gmx_fatal(FARGS,"Can not have frozen atoms in a cylinder pull group");
 +            }
 +        }
 +        else
 +        {
 +            /* Absolute reference, set the inverse mass to zero */
 +            pgrp->invtm  = 0;
 +            pgrp->wscale = 1;
 +        }
 +    }      
 +    
 +    /* if we use dynamic reference groups, do some initialising for them */
 +    if (PULL_CYL(pull))
 +    {
 +        if (pull->grp[0].nat == 0)
 +        {
 +            gmx_fatal(FARGS, "Dynamic reference groups are not supported when using absolute reference!\n");
 +        }
 +        snew(pull->dyna,pull->ngrp+1);
 +    }
 +    
 +    /* Only do I/O when we are doing dynamics and if we are the MASTER */
 +    pull->out_x = NULL;
 +    pull->out_f = NULL;
 +    if (bOutFile)
 +    {
 +        if (pull->nstxout > 0)
 +        {
 +            pull->out_x = open_pull_out(opt2fn("-px",nfile,fnm),pull,oenv,TRUE,Flags);
 +        }
 +        if (pull->nstfout > 0)
 +        {
 +            pull->out_f = open_pull_out(opt2fn("-pf",nfile,fnm),pull,oenv,
 +                                        FALSE,Flags);
 +        }
 +    }
 +}
 +
 +void finish_pull(FILE *fplog,t_pull *pull)
 +{
 +    if (pull->out_x)
 +    {
 +        gmx_fio_fclose(pull->out_x);
 +    }
 +    if (pull->out_f)
 +    {
 +        gmx_fio_fclose(pull->out_f);
 +    }
 +}
Simple merge
index ccce5f82473a1d9005c94006313796ae7f068b29,0000000000000000000000000000000000000000..539e718f57e12f87338a6bb8a55a182751e81fe8
mode 100644,000000..100644
--- /dev/null
@@@ -1,2634 -1,0 +1,2631 @@@
-     /* if we use the GPU turn off the nonbonded */
 +/* -*- 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 "sim_util.h"
 +#include "update.h"
 +#include "physics.h"
 +#include "main.h"
 +#include "mdatoms.h"
 +#include "force.h"
 +#include "bondf.h"
 +#include "pme.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 "gmx_random.h"
 +#include "domdec.h"
 +#include "partdec.h"
 +#include "gmx_wallcycle.h"
 +#include "genborn.h"
 +#include "nbnxn_atomdata.h"
 +#include "nbnxn_search.h"
 +#include "nbnxn_kernels/nbnxn_kernel_ref.h"
 +#include "nbnxn_kernels/nbnxn_kernel_x86_simd128.h"
 +#include "nbnxn_kernels/nbnxn_kernel_x86_simd256.h"
 +#include "nbnxn_kernels/nbnxn_kernel_gpu_ref.h"
 +
 +#ifdef GMX_LIB_MPI
 +#include <mpi.h>
 +#endif
 +#ifdef GMX_THREAD_MPI
 +#include "tmpi.h"
 +#endif
 +
 +#include "adress.h"
 +#include "qmmm.h"
 +
 +#include "nbnxn_cuda_data_mgmt.h"
 +#include "nbnxn_cuda/nbnxn_cuda.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;
 +      double seconds;
 +
 +      gettimeofday(&t,NULL);
 +
 +      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_THREAD_MPI
 +    if (!PAR(cr))
 +#endif
 +    {
 +        fprintf(out,"\r");
 +    }
 +    fprintf(out,"step %s",gmx_step_str(step,buf));
 +    if ((step >= ir->nstlist))
 +    {
 +        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_THREAD_MPI
 +    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 posres_wrapper(FILE *fplog,
 +                           int flags,
 +                           gmx_bool bSepDVDL,
 +                           t_inputrec *ir,
 +                           t_nrnb *nrnb,
 +                           gmx_localtop_t *top,
 +                           matrix box,rvec x[],
 +                           rvec f[],
 +                           gmx_enerdata_t *enerd,
 +                           real *lambda,
 +                           t_forcerec *fr)
 +{
 +    t_pbc pbc;
 +    real  v,dvdl;
 +    int   i;
 +
 +    /* Position restraints always require full pbc */
 +    set_pbc(&pbc,ir->ePBC,box);
 +    dvdl = 0;
 +    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,
 +               ir->ePBC==epbcNONE ? NULL : &pbc,
 +               lambda[efptRESTRAINT],&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;
 +    /* If just the force constant changes, the FEP term is linear,
 +     * but if k changes, it is not.
 +     */
 +    enerd->dvdl_nonlin[efptRESTRAINT] += dvdl;
 +    inc_nrnb(nrnb,eNR_POSRES,top->idef.il[F_POSRES].nr/2);
 +
 +    if ((ir->fepvals->n_lambda > 0) && (flags & GMX_FORCE_DHDL))
 +    {
 +        for(i=0; i<enerd->n_lambda; i++)
 +        {
 +            real dvdl_dum,lambda_dum;
 +
 +            lambda_dum = (i==0 ? lambda[efptRESTRAINT] : ir->fepvals->all_lambda[efptRESTRAINT][i-1]);
 +            v = posres(top->idef.il[F_POSRES].nr,top->idef.il[F_POSRES].iatoms,
 +                       top->idef.iparams_posres,
 +                       (const rvec*)x,NULL,NULL,
 +                       ir->ePBC==epbcNONE ? NULL : &pbc,lambda_dum,&dvdl,
 +                       fr->rc_scaling,fr->ePBC,fr->posres_com,fr->posres_comB);
 +            enerd->enerpart_lambda[i] += v;
 +        }
 +    }
 +}
 +
 +static void pull_potential_wrapper(FILE *fplog,
 +                                   gmx_bool bSepDVDL,
 +                                   t_commrec *cr,
 +                                   t_inputrec *ir,
 +                                   matrix box,rvec x[],
 +                                   rvec f[],
 +                                   tensor vir_force,
 +                                   t_mdatoms *mdatoms,
 +                                   gmx_enerdata_t *enerd,
 +                                   real *lambda,
 +                                   double t)
 +{
 +    t_pbc  pbc;
 +    real   dvdl;
 +
 +    /* 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,ir->ePBC,box);
 +    dvdl = 0; 
 +    enerd->term[F_COM_PULL] +=
 +        pull_potential(ir->ePull,ir->pull,mdatoms,&pbc,
 +                       cr,t,lambda[efptRESTRAINT],x,f,vir_force,&dvdl);
 +    if (bSepDVDL)
 +    {
 +        fprintf(fplog,sepdvdlformat,"Com pull",enerd->term[F_COM_PULL],dvdl);
 +    }
 +    enerd->dvdl_lin[efptRESTRAINT] += dvdl;
 +}
 +
 +static void pme_receive_force_ener(FILE *fplog,
 +                                   gmx_bool bSepDVDL,
 +                                   t_commrec *cr,
 +                                   gmx_wallcycle_t wcycle,
 +                                   gmx_enerdata_t *enerd,
 +                                   t_forcerec *fr)
 +{
 +    real   e,v,dvdl;    
 +    float  cycles_ppdpme,cycles_seppme;
 +
 +    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[efptCOUL] += dvdl;
 +    if (wcycle)
 +    {
 +        dd_cycles_add(cr->dd,cycles_seppme,ddCyclPME);
 +    }
 +    wallcycle_stop(wcycle,ewcPP_PMEWAITRECVF);
 +}
 +
 +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));
 +    }
 +  }
 +}
 +
 +static void post_process_forces(FILE *fplog,
 +                                t_commrec *cr,
 +                                gmx_large_int_t step,
 +                                t_nrnb *nrnb,gmx_wallcycle_t wcycle,
 +                                gmx_localtop_t *top,
 +                                matrix box,rvec x[],
 +                                rvec f[],
 +                                tensor vir_force,
 +                                t_mdatoms *mdatoms,
 +                                t_graph *graph,
 +                                t_forcerec *fr,gmx_vsite_t *vsite,
 +                                int flags)
 +{
 +    if (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,
 +                           (flags & GMX_FORCE_VIRIAL),fr->vir_el_recip,
 +                           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(mdatoms->start,mdatoms->start+mdatoms->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);
 +            }
 +        }
 +    }
 +    
 +    if (fr->print_force >= 0)
 +    {
 +        print_large_forces(stderr,mdatoms,cr,step,fr->print_force,x,f);
 +    }
 +}
 +
 +static void do_nb_verlet(t_forcerec *fr,
 +                         interaction_const_t *ic,
 +                         gmx_enerdata_t *enerd,
 +                         int flags, int ilocality,
 +                         int clearF,
 +                         t_nrnb *nrnb,
 +                         gmx_wallcycle_t wcycle)
 +{
 +    int     nnbl, kernel_type, sh_e;
 +    char    *env;
 +    nonbonded_verlet_group_t  *nbvg;
 +
 +    if (!(flags & GMX_FORCE_NONBONDED))
 +    {
 +        /* skip non-bonded calculation */
 +        return;
 +    }
 +
 +    nbvg = &fr->nbv->grp[ilocality];
 +
 +    /* CUDA kernel launch overhead is already timed separately */
 +    if (fr->cutoff_scheme != ecutsVERLET)
 +    {
 +        gmx_incons("Invalid cut-off scheme passed!");
 +    }
 +
 +    if (nbvg->kernel_type != nbk8x8x8_CUDA)
 +    {
 +        wallcycle_sub_start(wcycle, ewcsNONBONDED);
 +    }
 +    switch (nbvg->kernel_type)
 +    {
 +        case nbk4x4_PlainC:
 +            nbnxn_kernel_ref(&nbvg->nbl_lists,
 +                             nbvg->nbat, ic,
 +                             fr->shift_vec,
 +                             flags,
 +                             clearF,
 +                             fr->fshift[0],
 +                             enerd->grpp.ener[egCOULSR],
 +                             fr->bBHAM ?
 +                             enerd->grpp.ener[egBHAMSR] :
 +                             enerd->grpp.ener[egLJSR]);
 +            break;
 +        
 +        case nbk4xN_X86_SIMD128:
 +            nbnxn_kernel_x86_simd128(&nbvg->nbl_lists,
 +                                     nbvg->nbat, ic,
 +                                     fr->shift_vec,
 +                                     flags,
 +                                     clearF,
 +                                     fr->fshift[0],
 +                                     enerd->grpp.ener[egCOULSR],
 +                                     fr->bBHAM ?
 +                                     enerd->grpp.ener[egBHAMSR] :
 +                                     enerd->grpp.ener[egLJSR]);
 +            break;
 +        case nbk4xN_X86_SIMD256:
 +            nbnxn_kernel_x86_simd256(&nbvg->nbl_lists,
 +                                     nbvg->nbat, ic,
 +                                     fr->shift_vec,
 +                                     flags,
 +                                     clearF,
 +                                     fr->fshift[0],
 +                                     enerd->grpp.ener[egCOULSR],
 +                                     fr->bBHAM ?
 +                                     enerd->grpp.ener[egBHAMSR] :
 +                                     enerd->grpp.ener[egLJSR]);
 +            break;
 +
 +        case nbk8x8x8_CUDA:
 +            nbnxn_cuda_launch_kernel(fr->nbv->cu_nbv, nbvg->nbat, flags, ilocality);
 +            break;
 +
 +        case nbk8x8x8_PlainC:
 +            nbnxn_kernel_gpu_ref(nbvg->nbl_lists.nbl[0],
 +                                 nbvg->nbat, ic,
 +                                 fr->shift_vec,
 +                                 flags,
 +                                 clearF,
 +                                 nbvg->nbat->out[0].f,
 +                                 fr->fshift[0],
 +                                 enerd->grpp.ener[egCOULSR],
 +                                 fr->bBHAM ?
 +                                 enerd->grpp.ener[egBHAMSR] :
 +                                 enerd->grpp.ener[egLJSR]);
 +            break;
 +
 +        default:
 +            gmx_incons("Invalid nonbonded kernel type passed!");
 +
 +    }
 +    if (nbvg->kernel_type != nbk8x8x8_CUDA)
 +    {
 +        wallcycle_sub_stop(wcycle, ewcsNONBONDED);
 +    }
 +
 +    /* In eNR_??? the nbnxn F+E kernels are always the F kernel + 1 */
 +    sh_e = ((flags & GMX_FORCE_ENERGY) ? 1 : 0);
 +    inc_nrnb(nrnb,
 +             ((EEL_RF(ic->eeltype) || ic->eeltype == eelCUT) ?
 +              eNR_NBNXN_LJ_RF : eNR_NBNXN_LJ_TAB) + sh_e,
 +             nbvg->nbl_lists.natpair_ljq);
 +    inc_nrnb(nrnb,eNR_NBNXN_LJ+sh_e,nbvg->nbl_lists.natpair_lj);
 +    inc_nrnb(nrnb,
 +             ((EEL_RF(ic->eeltype) || ic->eeltype == eelCUT) ?
 +              eNR_NBNXN_RF : eNR_NBNXN_TAB)+sh_e,
 +             nbvg->nbl_lists.natpair_q);
 +}
 +
 +void do_force_cutsVERLET(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, interaction_const_t *ic,
 +              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;
 +    int     nb_kernel_type;
 +    double  mu[2*DIM];
 +    gmx_bool   bSepDVDL,bStateChanged,bNS,bFillGrid,bCalcCGCM,bBS;
 +    gmx_bool   bDoLongRange,bDoForces,bSepLRF,bUseGPU,bUseOrEmulGPU;
 +    gmx_bool   bDiffKernels=FALSE;
 +    matrix  boxs;
 +    rvec    vzero,box_diag;
 +    real    e,v,dvdl;
 +    float  cycles_pme,cycles_force;
 +    nonbonded_verlet_t *nbv;
 +
 +    cycles_force = 0;
 +    nbv = fr->nbv;
 +    nb_kernel_type = fr->nbv->grp[0].kernel_type;
 +
 +    start  = mdatoms->start;
 +    homenr = mdatoms->homenr;
 +
 +    bSepDVDL = (fr->bSepDVDL && do_per_step(step,inputrec->nstlog));
 +
 +    clear_mat(vir_force);
 +
 +    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_DO_LR));
 +    bDoForces     = (flags & GMX_FORCE_FORCES);
 +    bSepLRF       = (bDoLongRange && bDoForces && (flags & GMX_FORCE_SEPLRF));
 +    bUseGPU       = fr->nbv->bUseGPU;
 +    bUseOrEmulGPU = bUseGPU || (nbv->grp[0].kernel_type == nbk8x8x8_PlainC);
 +
 +    if (bStateChanged)
 +    {
 +        update_forcerec(fplog,fr,box);
 +
 +        if (NEED_MUTOT(*inputrec))
 +        {
 +            /* 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_atoms_in_box_omp(fr->ePBC,box,homenr,x);
 +            inc_nrnb(nrnb,eNR_SHIFTX,homenr);
 +        } 
 +        else if (EI_ENERGY_MINIMIZATION(inputrec->eI) && graph) {
 +            unshift_self(graph,box,x);
 +        }
 +    } 
 +
 +    nbnxn_atomdata_copy_shiftvec(flags & GMX_FORCE_DYNAMICBOX,
 +                                  fr->shift_vec,nbv->grp[0].nbat);
 +
 +#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);
 +
 +        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[efptCOUL],
 +                       (flags & (GMX_FORCE_VIRIAL | GMX_FORCE_ENERGY)),step);
 +
 +        wallcycle_stop(wcycle,ewcPP_PMESENDX);
 +    }
 +#endif /* GMX_MPI */
 +
 +    /* do gridding for pair search */
 +    if (bNS)
 +    {
 +        if (graph && bStateChanged)
 +        {
 +            /* Calculate intramolecular shift vectors to make molecules whole */
 +            mk_mshift(fplog,graph,fr->ePBC,box,x);
 +        }
 +
 +        clear_rvec(vzero);
 +        box_diag[XX] = box[XX][XX];
 +        box_diag[YY] = box[YY][YY];
 +        box_diag[ZZ] = box[ZZ][ZZ];
 +
 +        wallcycle_start(wcycle,ewcNS);
 +        if (!fr->bDomDec)
 +        {
 +            wallcycle_sub_start(wcycle,ewcsNBS_GRID_LOCAL);
 +            nbnxn_put_on_grid(nbv->nbs,fr->ePBC,box,
 +                              0,vzero,box_diag,
 +                              0,mdatoms->homenr,-1,fr->cginfo,x,
 +                              0,NULL,
 +                              nbv->grp[eintLocal].kernel_type,
 +                              nbv->grp[eintLocal].nbat);
 +            wallcycle_sub_stop(wcycle,ewcsNBS_GRID_LOCAL);
 +        }
 +        else
 +        {
 +            wallcycle_sub_start(wcycle,ewcsNBS_GRID_NONLOCAL);
 +            nbnxn_put_on_grid_nonlocal(nbv->nbs,domdec_zones(cr->dd),
 +                                       fr->cginfo,x,
 +                                       nbv->grp[eintNonlocal].kernel_type,
 +                                       nbv->grp[eintNonlocal].nbat);
 +            wallcycle_sub_stop(wcycle,ewcsNBS_GRID_NONLOCAL);
 +        }
 +
 +        if (nbv->ngrp == 1 ||
 +            nbv->grp[eintNonlocal].nbat == nbv->grp[eintLocal].nbat)
 +        {
 +            nbnxn_atomdata_set(nbv->grp[eintLocal].nbat,eatAll,
 +                                nbv->nbs,mdatoms,fr->cginfo);
 +        }
 +        else
 +        {
 +            nbnxn_atomdata_set(nbv->grp[eintLocal].nbat,eatLocal,
 +                                nbv->nbs,mdatoms,fr->cginfo);
 +            nbnxn_atomdata_set(nbv->grp[eintNonlocal].nbat,eatAll,
 +                                nbv->nbs,mdatoms,fr->cginfo);
 +        }
 +        wallcycle_stop(wcycle, ewcNS);
 +    }
 +
 +    /* initialize the GPU atom data and copy shift vector */
 +    if (bUseGPU)
 +    {
 +        if (bNS)
 +        {
 +            wallcycle_start_nocount(wcycle, ewcLAUNCH_GPU_NB);
 +            nbnxn_cuda_init_atomdata(nbv->cu_nbv, nbv->grp[eintLocal].nbat);
 +            wallcycle_stop(wcycle, ewcLAUNCH_GPU_NB);
 +        }
 +
 +        wallcycle_start_nocount(wcycle, ewcLAUNCH_GPU_NB);
 +        nbnxn_cuda_upload_shiftvec(nbv->cu_nbv, nbv->grp[eintLocal].nbat);
 +        wallcycle_stop(wcycle, ewcLAUNCH_GPU_NB);
 +    }
 +
 +    /* do local pair search */
 +    if (bNS)
 +    {
 +        wallcycle_start_nocount(wcycle,ewcNS);
 +        wallcycle_sub_start(wcycle,ewcsNBS_SEARCH_LOCAL);
 +        nbnxn_make_pairlist(nbv->nbs,nbv->grp[eintLocal].nbat,
 +                            &top->excls,
 +                            ic->rlist,
 +                            nbv->min_ci_balanced,
 +                            &nbv->grp[eintLocal].nbl_lists,
 +                            eintLocal,
 +                            nbv->grp[eintLocal].kernel_type,
 +                            nrnb);
 +        wallcycle_sub_stop(wcycle,ewcsNBS_SEARCH_LOCAL);
 +
 +        if (bUseGPU)
 +        {
 +            /* initialize local pair-list on the GPU */
 +            nbnxn_cuda_init_pairlist(nbv->cu_nbv,
 +                                     nbv->grp[eintLocal].nbl_lists.nbl[0],
 +                                     eintLocal);
 +        }
 +        wallcycle_stop(wcycle, ewcNS);
 +    }
 +    else
 +    {
 +        wallcycle_start(wcycle, ewcNB_XF_BUF_OPS);
 +        wallcycle_sub_start(wcycle, ewcsNB_X_BUF_OPS);
 +        nbnxn_atomdata_copy_x_to_nbat_x(nbv->nbs,eatLocal,FALSE,x,
 +                                        nbv->grp[eintLocal].nbat);
 +        wallcycle_sub_stop(wcycle, ewcsNB_X_BUF_OPS);
 +        wallcycle_stop(wcycle, ewcNB_XF_BUF_OPS);
 +    }
 +
 +    if (bUseGPU)
 +    {
 +        wallcycle_start(wcycle,ewcLAUNCH_GPU_NB);
 +        /* launch local nonbonded F on GPU */
 +        do_nb_verlet(fr, ic, enerd, flags, eintLocal, enbvClearFNo,
 +                     nrnb, wcycle);
 +        wallcycle_stop(wcycle,ewcLAUNCH_GPU_NB);
 +    }
 +
 +    /* Communicate coordinates and sum dipole if necessary + 
 +       do non-local pair search */
 +    if (DOMAINDECOMP(cr))
 +    {
 +        bDiffKernels = (nbv->grp[eintNonlocal].kernel_type !=
 +                        nbv->grp[eintLocal].kernel_type);
 +
 +        if (bDiffKernels)
 +        {
 +            /* With GPU+CPU non-bonded calculations we need to copy
 +             * the local coordinates to the non-local nbat struct
 +             * (in CPU format) as the non-local kernel call also
 +             * calculates the local - non-local interactions.
 +             */
 +            wallcycle_start(wcycle, ewcNB_XF_BUF_OPS);
 +            wallcycle_sub_start(wcycle, ewcsNB_X_BUF_OPS);
 +            nbnxn_atomdata_copy_x_to_nbat_x(nbv->nbs,eatLocal,TRUE,x,
 +                                             nbv->grp[eintNonlocal].nbat);
 +            wallcycle_sub_stop(wcycle, ewcsNB_X_BUF_OPS);
 +            wallcycle_stop(wcycle, ewcNB_XF_BUF_OPS);
 +        }
 +
 +        if (bNS)
 +        {
 +            wallcycle_start_nocount(wcycle,ewcNS);
 +            wallcycle_sub_start(wcycle,ewcsNBS_SEARCH_NONLOCAL);
 +
 +            if (bDiffKernels)
 +            {
 +                nbnxn_grid_add_simple(nbv->nbs,nbv->grp[eintNonlocal].nbat);
 +            }
 +
 +            nbnxn_make_pairlist(nbv->nbs,nbv->grp[eintNonlocal].nbat,
 +                                &top->excls,
 +                                ic->rlist,
 +                                nbv->min_ci_balanced,
 +                                &nbv->grp[eintNonlocal].nbl_lists,
 +                                eintNonlocal,
 +                                nbv->grp[eintNonlocal].kernel_type,
 +                                nrnb);
 +
 +            wallcycle_sub_stop(wcycle,ewcsNBS_SEARCH_NONLOCAL);
 +
 +            if (nbv->grp[eintNonlocal].kernel_type == nbk8x8x8_CUDA)
 +            {
 +                /* initialize non-local pair-list on the GPU */
 +                nbnxn_cuda_init_pairlist(nbv->cu_nbv,
 +                                         nbv->grp[eintNonlocal].nbl_lists.nbl[0],
 +                                         eintNonlocal);
 +            }
 +            wallcycle_stop(wcycle,ewcNS);
 +        } 
 +        else
 +        {
 +            wallcycle_start(wcycle,ewcMOVEX);
 +            dd_move_x(cr->dd,box,x);
 +
 +            /* 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);
 +
 +            wallcycle_start(wcycle, ewcNB_XF_BUF_OPS);
 +            wallcycle_sub_start(wcycle, ewcsNB_X_BUF_OPS);
 +            nbnxn_atomdata_copy_x_to_nbat_x(nbv->nbs,eatNonlocal,FALSE,x,
 +                                            nbv->grp[eintNonlocal].nbat);
 +            wallcycle_sub_stop(wcycle, ewcsNB_X_BUF_OPS);
 +            cycles_force += wallcycle_stop(wcycle, ewcNB_XF_BUF_OPS);
 +        }
 +
 +        if (bUseGPU && !bDiffKernels)
 +        { 
 +            wallcycle_start(wcycle,ewcLAUNCH_GPU_NB);
 +            /* launch non-local nonbonded F on GPU */
 +            do_nb_verlet(fr, ic, enerd, flags, eintNonlocal, enbvClearFNo,
 +                         nrnb, wcycle);
 +            cycles_force += wallcycle_stop(wcycle,ewcLAUNCH_GPU_NB);
 +        }
 +    }
 +
 +    if (bUseGPU)
 +    {
 +        /* launch D2H copy-back F */
 +        wallcycle_start_nocount(wcycle, ewcLAUNCH_GPU_NB);
 +        if (DOMAINDECOMP(cr) && !bDiffKernels)
 +        {
 +            nbnxn_cuda_launch_cpyback(nbv->cu_nbv, nbv->grp[eintNonlocal].nbat,
 +                                      flags, eatNonlocal);
 +        }
 +        nbnxn_cuda_launch_cpyback(nbv->cu_nbv, nbv->grp[eintLocal].nbat,
 +                                  flags, eatLocal);
 +        cycles_force += wallcycle_stop(wcycle,ewcLAUNCH_GPU_NB);
 +    }
 +
 +    if (bStateChanged && NEED_MUTOT(*inputrec))
 +    {
 +        if (PAR(cr))
 +        {
 +            gmx_sumd(2*DIM,mu,cr);
 +        } 
 +
 +        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[efptCOUL])*fr->mu_tot[0][j] +
 +                lambda[efptCOUL]*fr->mu_tot[1][j];
 +        }
 +    }
 +
 +    /* Reset energies */
 +    reset_enerdata(&(inputrec->opts),fr,bNS,enerd,MASTER(cr));
 +    clear_rvecs(SHIFTS,fr->fshift);
 +
 +    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;
 +                if (fr->bDomDec)
 +                {
 +                    clear_rvecs(fr->f_novirsum_n,fr->f_novirsum);
 +                }
 +                else
 +                {
 +                    clear_rvecs(homenr,fr->f_novirsum+start);
 +                }
 +            }
 +            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;
 +            }
 +        }
 +
 +        /* Clear the short- and long-range forces */
 +        clear_rvecs(fr->natoms_force_constr,f);
 +        if(bSepLRF && do_per_step(step,inputrec->nstcalclr))
 +        {
 +            clear_rvecs(fr->natoms_force_constr,fr->f_twin);
 +        }
 +        
 +        clear_rvec(fr->vir_diag_posres);
 +    }
 +    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)
 +    {
 +        posres_wrapper(fplog,flags,bSepDVDL,inputrec,nrnb,top,box,x,
 +                       f,enerd,lambda,fr);
 +    }
 +
 +    /* Compute the bonded and non-bonded energies and optionally forces */    
-                       ((nb_kernel_type == nbk8x8x8_CUDA || nb_kernel_type == nbk8x8x8_PlainC) 
-                         ? flags&~GMX_FORCE_NONBONDED : flags),
-                       &cycles_pme);
 +    do_force_lowlevel(fplog,step,fr,inputrec,&(top->idef),
 +                      cr,nrnb,wcycle,mdatoms,&(inputrec->opts),
 +                      x,hist,f, bSepLRF ? fr->f_twin : f,enerd,fcd,mtop,top,fr->born,
 +                      &(top->atomtypes),bBornRadii,box,
 +                      inputrec->fepvals,lambda,graph,&(top->excls),fr->mu_tot,
++                      flags, &cycles_pme);
 +
 +    if(bSepLRF)
 +    {
 +        if (do_per_step(step,inputrec->nstcalclr))
 +        {
 +            /* Add the long range forces to the short range forces */
 +            for(i=0; i<fr->natoms_force_constr; i++)
 +            {
 +                rvec_add(fr->f_twin[i],f[i],f[i]);
 +            }
 +        }
 +    }
 +    
 +    if (!bUseOrEmulGPU)
 +    {
 +        /* Maybe we should move this into do_force_lowlevel */
 +        do_nb_verlet(fr, ic, enerd, flags, eintLocal, enbvClearFYes,
 +                     nrnb, wcycle);
 +    }
 +        
 +
 +    if (!bUseOrEmulGPU || bDiffKernels)
 +    {
 +        int aloc;
 +
 +        if (DOMAINDECOMP(cr))
 +        {
 +            do_nb_verlet(fr, ic, enerd, flags, eintNonlocal,
 +                         bDiffKernels ? enbvClearFYes : enbvClearFNo,
 +                         nrnb, wcycle);
 +        }
 +
 +        if (!bUseOrEmulGPU)
 +        {
 +            aloc = eintLocal;
 +        }
 +        else
 +        {
 +            aloc = eintNonlocal;
 +        }
 +
 +        /* Add all the non-bonded force to the normal force array.
 +         * This can be split into a local a non-local part when overlapping
 +         * communication with calculation with domain decomposition.
 +         */
 +        cycles_force += wallcycle_stop(wcycle,ewcFORCE);
 +        wallcycle_start(wcycle, ewcNB_XF_BUF_OPS);
 +        wallcycle_sub_start(wcycle, ewcsNB_F_BUF_OPS);
 +        nbnxn_atomdata_add_nbat_f_to_f(nbv->nbs,eatAll,nbv->grp[aloc].nbat,f);
 +        wallcycle_sub_stop(wcycle, ewcsNB_F_BUF_OPS);
 +        cycles_force += wallcycle_stop(wcycle, ewcNB_XF_BUF_OPS);
 +        wallcycle_start_nocount(wcycle,ewcFORCE);
 +
 +        /* if there are multiple fshift output buffers reduce them */
 +        if ((flags & GMX_FORCE_VIRIAL) &&
 +            nbv->grp[aloc].nbl_lists.nnbl > 1)
 +        {
 +            nbnxn_atomdata_add_nbat_fshift_to_fshift(nbv->grp[aloc].nbat,
 +                                                      fr->fshift);
 +        }
 +    }
 +    
 +    cycles_force += wallcycle_stop(wcycle,ewcFORCE);
 +    
 +    if (ed)
 +    {
 +        do_flood(fplog,cr,x,f,ed,box,step,bNS);
 +    }
 +
 +    if (bUseOrEmulGPU && !bDiffKernels)
 +    {
 +        /* wait for non-local forces (or calculate in emulation mode) */
 +        if (DOMAINDECOMP(cr))
 +        {
 +            if (bUseGPU)
 +            {
 +                wallcycle_start(wcycle,ewcWAIT_GPU_NB_NL);
 +                nbnxn_cuda_wait_gpu(nbv->cu_nbv,
 +                                    nbv->grp[eintNonlocal].nbat,
 +                                    flags, eatNonlocal,
 +                                    enerd->grpp.ener[egLJSR], enerd->grpp.ener[egCOULSR],
 +                                    fr->fshift);
 +                cycles_force += wallcycle_stop(wcycle,ewcWAIT_GPU_NB_NL);
 +            }
 +            else
 +            {
 +                wallcycle_start_nocount(wcycle,ewcFORCE);
 +                do_nb_verlet(fr, ic, enerd, flags, eintNonlocal, enbvClearFYes,
 +                             nrnb, wcycle);
 +                cycles_force += wallcycle_stop(wcycle,ewcFORCE);
 +            }            
 +            wallcycle_start(wcycle, ewcNB_XF_BUF_OPS);
 +            wallcycle_sub_start(wcycle, ewcsNB_F_BUF_OPS);
 +            /* skip the reduction if there was no non-local work to do */
 +            if (nbv->grp[eintLocal].nbl_lists.nbl[0]->nsci > 0)
 +            {
 +                nbnxn_atomdata_add_nbat_f_to_f(nbv->nbs,eatNonlocal,
 +                                               nbv->grp[eintNonlocal].nbat,f);
 +            }
 +            wallcycle_sub_stop(wcycle, ewcsNB_F_BUF_OPS);
 +            cycles_force += wallcycle_stop(wcycle, ewcNB_XF_BUF_OPS);
 +        }
 +    }
 +
 +    if (bDoForces)
 +    {
 +        /* 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);
 +                }
 +            }
 +            wallcycle_stop(wcycle,ewcMOVEF);
 +        }
 +    }
 + 
 +    if (bUseOrEmulGPU)
 +    {
 +        /* wait for local forces (or calculate in emulation mode) */
 +        if (bUseGPU)
 +        {
 +            wallcycle_start(wcycle,ewcWAIT_GPU_NB_L);
 +            nbnxn_cuda_wait_gpu(nbv->cu_nbv,
 +                                nbv->grp[eintLocal].nbat,
 +                                flags, eatLocal,
 +                                enerd->grpp.ener[egLJSR], enerd->grpp.ener[egCOULSR],
 +                                fr->fshift);
 +            wallcycle_stop(wcycle,ewcWAIT_GPU_NB_L);
 +
 +            /* now clear the GPU outputs while we finish the step on the CPU */
 +            nbnxn_cuda_clear_outputs(nbv->cu_nbv, flags);
 +        }
 +        else
 +        {            
 +            wallcycle_start_nocount(wcycle,ewcFORCE);
 +            do_nb_verlet(fr, ic, enerd, flags, eintLocal,
 +                         DOMAINDECOMP(cr) ? enbvClearFNo : enbvClearFYes,
 +                         nrnb, wcycle);
 +            wallcycle_stop(wcycle,ewcFORCE);
 +        }
 +        wallcycle_start(wcycle, ewcNB_XF_BUF_OPS);
 +        wallcycle_sub_start(wcycle, ewcsNB_F_BUF_OPS);
 +        if (nbv->grp[eintLocal].nbl_lists.nbl[0]->nsci > 0)
 +        {
 +            /* skip the reduction if there was no non-local work to do */
 +            nbnxn_atomdata_add_nbat_f_to_f(nbv->nbs,eatLocal,
 +                                           nbv->grp[eintLocal].nbat,f);
 +        }
 +        wallcycle_sub_stop(wcycle, ewcsNB_F_BUF_OPS);
 +        wallcycle_stop(wcycle, ewcNB_XF_BUF_OPS);
 +    }
 +    
 +    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);
 +        }
 +
 +        /* 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,FALSE,NULL,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,FALSE,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)
 +    {
 +        pull_potential_wrapper(fplog,bSepDVDL,cr,inputrec,box,x,
 +                               f,vir_force,mdatoms,enerd,lambda,t);
 +    }
 +
 +    if (PAR(cr) && !(cr->duty & DUTY_PME))
 +    {
 +        /* In case of node-splitting, the PP nodes receive the long-range 
 +         * forces, virial and energy from the PME nodes here.
 +         */    
 +        pme_receive_force_ener(fplog,bSepDVDL,cr,wcycle,enerd,fr);
 +    }
 +
 +    if (bDoForces)
 +    {
 +        post_process_forces(fplog,cr,step,nrnb,wcycle,
 +                            top,box,x,f,vir_force,mdatoms,graph,fr,vsite,
 +                            flags);
 +    }
 +    
 +    /* Sum the potential energy terms from group contributions */
 +    sum_epot(&(inputrec->opts),enerd);
 +}
 +
 +void do_force_cutsGROUP(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   bDoLongRangeNS,bDoForces,bDoPotential,bSepLRF;
 +    gmx_bool   bDoAdressWF;
 +    matrix boxs;
 +    rvec   vzero,box_diag;
 +    real   e,v,dvdlambda[efptNR];
 +    t_pbc  pbc;
 +    float  cycles_pme,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);
 +    /* Should we update the long-range neighborlists at this step? */
 +    bDoLongRangeNS = fr->bTwinRange && bNS;
 +    /* Should we perform the long-range nonbonded evaluation inside the neighborsearching? */
 +    bFillGrid      = (bNS && bStateChanged);
 +    bCalcCGCM      = (bFillGrid && !DOMAINDECOMP(cr));
 +    bDoForces      = (flags & GMX_FORCE_FORCES);
 +    bDoPotential   = (flags & GMX_FORCE_ENERGY);
 +    bSepLRF        = ((inputrec->nstcalclr>1) && bDoForces &&
 +                      (flags & GMX_FORCE_SEPLRF) && (flags & GMX_FORCE_DO_LR));
 +
 +    /* should probably move this to the forcerec since it doesn't change */
 +    bDoAdressWF   = ((fr->adress_type!=eAdressOff));
 +
 +    if (bStateChanged)
 +    {
 +        update_forcerec(fplog,fr,box);
 +
 +        if (NEED_MUTOT(*inputrec))
 +        {
 +            /* 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);
 +
 +        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[efptCOUL],
 +                       (flags & (GMX_FORCE_VIRIAL | GMX_FORCE_ENERGY)),step);
 +
 +        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);
 +        }
 +        wallcycle_stop(wcycle,ewcMOVEX);
 +    }
 +
 +    /* update adress weight beforehand */
 +    if(bStateChanged && bDoAdressWF)
 +    {
 +        /* need pbc for adress weight calculation with pbc_dx */
 +        set_pbc(&pbc,inputrec->ePBC,box);
 +        if(fr->adress_site == eAdressSITEcog)
 +        {
 +            update_adress_weights_cog(top->idef.iparams,top->idef.il,x,fr,mdatoms,
 +                                      inputrec->ePBC==epbcNONE ? NULL : &pbc);
 +        }
 +        else if (fr->adress_site == eAdressSITEcom)
 +        {
 +            update_adress_weights_com(fplog,cg0,cg1,&(top->cgs),x,fr,mdatoms,
 +                                      inputrec->ePBC==epbcNONE ? NULL : &pbc);
 +        }
 +        else if (fr->adress_site == eAdressSITEatomatom){
 +            update_adress_weights_atom_per_atom(cg0,cg1,&(top->cgs),x,fr,mdatoms,
 +                                                inputrec->ePBC==epbcNONE ? NULL : &pbc);
 +        }
 +        else
 +        {
 +            update_adress_weights_atom(cg0,cg1,&(top->cgs),x,fr,mdatoms,
 +                                       inputrec->ePBC==epbcNONE ? NULL : &pbc);
 +        }
 +    }
 +
 +    if (NEED_MUTOT(*inputrec))
 +    {
 +
 +        if (bStateChanged)
 +        {
 +            if (PAR(cr))
 +            {
 +                gmx_sumd(2*DIM,mu,cr);
 +            }
 +            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[efptCOUL])*fr->mu_tot[0][j] + lambda[efptCOUL]*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);
 +        }
 +
 +        /* Do the actual neighbour searching and if twin range electrostatics
 +         * also do the calculation of long range forces and energies.
 +         */
 +        for (i=0;i<efptNR;i++) {dvdlambda[i] = 0;}
 +        ns(fplog,fr,x,box,
 +           groups,&(inputrec->opts),top,mdatoms,
 +           cr,nrnb,lambda,dvdlambda,&enerd->grpp,bFillGrid,
 +           bDoLongRangeNS);
 +        if (bSepDVDL)
 +        {
 +            fprintf(fplog,sepdvdlformat,"LR non-bonded",0.0,dvdlambda);
 +        }
 +        enerd->dvdl_lin[efptVDW] += dvdlambda[efptVDW];
 +        enerd->dvdl_lin[efptCOUL] += dvdlambda[efptCOUL];
 +
 +        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 to allow
 +         * for proper load-balancing */
 +        wallcycle_start(wcycle,ewcROT);
 +        do_rotation(cr,inputrec,box,x,t,step,wcycle,bNS);
 +        wallcycle_stop(wcycle,ewcROT);
 +    }
 +
 +    /* 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;
 +                if (fr->bDomDec)
 +                {
 +                    clear_rvecs(fr->f_novirsum_n,fr->f_novirsum);
 +                }
 +                else
 +                {
 +                    clear_rvecs(homenr,fr->f_novirsum+start);
 +                }
 +            }
 +            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;
 +            }
 +        }
 +
 +        /* Clear the short- and long-range forces */
 +        clear_rvecs(fr->natoms_force_constr,f);
 +        if(bSepLRF && do_per_step(step,inputrec->nstcalclr))
 +        {
 +            clear_rvecs(fr->natoms_force_constr,fr->f_twin);
 +        }
 +        
 +        clear_rvec(fr->vir_diag_posres);
 +    }
 +    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)
 +    {
 +        posres_wrapper(fplog,flags,bSepDVDL,inputrec,nrnb,top,box,x,
 +                       f,enerd,lambda,fr);
 +    }
 +
 +    if ((flags & GMX_FORCE_BONDED) && top->idef.il[F_FBPOSRES].nr > 0)
 +    {
 +        /* Flat-bottomed position restraints always require full pbc */
 +        if(!(bStateChanged && bDoAdressWF))
 +        {
 +            set_pbc(&pbc,inputrec->ePBC,box);
 +        }
 +        v = fbposres(top->idef.il[F_FBPOSRES].nr,top->idef.il[F_FBPOSRES].iatoms,
 +                     top->idef.iparams_fbposres,
 +                     (const rvec*)x,fr->f_novirsum,fr->vir_diag_posres,
 +                     inputrec->ePBC==epbcNONE ? NULL : &pbc,
 +                     fr->rc_scaling,fr->ePBC,fr->posres_com);
 +        enerd->term[F_FBPOSRES] += v;
 +        inc_nrnb(nrnb,eNR_FBPOSRES,top->idef.il[F_FBPOSRES].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, bSepLRF ? fr->f_twin : f,enerd,fcd,mtop,top,fr->born,
 +                      &(top->atomtypes),bBornRadii,box,
 +                      inputrec->fepvals,lambda,
 +                      graph,&(top->excls),fr->mu_tot,
 +                      flags,
 +                      &cycles_pme);
 +
 +    if(bSepLRF)
 +    {
 +        if (do_per_step(step,inputrec->nstcalclr))
 +        {
 +            /* Add the long range forces to the short range forces */
 +            for(i=0; i<fr->natoms_force_constr; i++)
 +            {
 +                rvec_add(fr->f_twin[i],f[i],f[i]);
 +            }
 +        }
 +    }
 +    
 +    cycles_force = wallcycle_stop(wcycle,ewcFORCE);
 +
 +    if (ed)
 +    {
 +        do_flood(fplog,cr,x,f,ed,box,step,bNS);
 +    }
 +
 +    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);
 +        }
 +
 +        if (bDoAdressWF && fr->adress_icor == eAdressICThermoForce)
 +        {
 +            /* Compute thermodynamic force in hybrid AdResS region */
 +            adress_thermo_force(start,homenr,&(top->cgs),x,fr->f_novirsum,fr,mdatoms,
 +                                inputrec->ePBC==epbcNONE ? NULL : &pbc);
 +        }
 +
 +        /* 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,FALSE,NULL,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,FALSE,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)
 +    {
 +        pull_potential_wrapper(fplog,bSepDVDL,cr,inputrec,box,x,
 +                               f,vir_force,mdatoms,enerd,lambda,t);
 +    }
 +
 +    /* Add the forces from enforced rotation potentials (if any) */
 +    if (inputrec->bRot)
 +    {
 +        wallcycle_start(wcycle,ewcROTadd);
 +        enerd->term[F_COM_PULL] += add_rot_forces(inputrec->rot, f, cr,step,t);
 +        wallcycle_stop(wcycle,ewcROTadd);
 +    }
 +
 +    if (PAR(cr) && !(cr->duty & DUTY_PME))
 +    {
 +        /* In case of node-splitting, the PP nodes receive the long-range 
 +         * forces, virial and energy from the PME nodes here.
 +         */
 +        pme_receive_force_ener(fplog,bSepDVDL,cr,wcycle,enerd,fr);
 +    }
 +
 +    if (bDoForces)
 +    {
 +        post_process_forces(fplog,cr,step,nrnb,wcycle,
 +                            top,box,x,f,vir_force,mdatoms,graph,fr,vsite,
 +                            flags);
 +    }
 +
 +    /* Sum the potential energy terms from group contributions */
 +    sum_epot(&(inputrec->opts),enerd);
 +}
 +
 +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)
 +{
 +    /* modify force flag if not doing nonbonded */
 +    if (!fr->bNonbonded)
 +    {
 +        flags &= ~GMX_FORCE_NONBONDED;
 +    }
 +
 +    switch (inputrec->cutoff_scheme)
 +    {
 +        case ecutsVERLET:
 +            do_force_cutsVERLET(fplog, cr, inputrec,
 +                                step, nrnb, wcycle,
 +                                top, mtop,
 +                                groups,
 +                                box, x, hist,
 +                                f, vir_force,
 +                                mdatoms,
 +                                enerd, fcd,
 +                                lambda, graph,
 +                                fr, fr->ic, 
 +                                vsite, mu_tot,
 +                                t, field, ed,
 +                                bBornRadii,
 +                                flags);
 +            break;
 +        case ecutsGROUP:
 +             do_force_cutsGROUP(fplog, cr, inputrec,
 +                                step, nrnb, wcycle,
 +                                top, mtop,
 +                                groups,
 +                                box, x, hist,
 +                                f, vir_force,
 +                                mdatoms,
 +                                enerd, fcd,
 +                                lambda, graph,
 +                                fr, vsite, mu_tot,
 +                                t, field, ed,
 +                                bBornRadii,
 +                                flags);
 +            break;
 +        default:
 +            gmx_incons("Invalid cut-off scheme passed!");
 +    }
 +}
 +
 +
 +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;
 +    real   dt=ir->delta_t;
 +    real   dvdl_dum;
 +    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));
 +    }
 +    dvdl_dum = 0;
 +
 +    /* constrain the current position */
 +    constrain(NULL,TRUE,FALSE,constr,&(top->idef),
 +              ir,NULL,cr,step,0,md,
 +              state->x,state->x,NULL,
 +              fr->bMolPBC,state->box,
 +              state->lambda[efptBONDED],&dvdl_dum,
 +              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,
 +                  fr->bMolPBC,state->box,
 +                  state->lambda[efptBONDED],&dvdl_dum,
 +                  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));
 +        }
 +        dvdl_dum = 0;
 +        constrain(NULL,TRUE,FALSE,constr,&(top->idef),
 +                  ir,NULL,cr,step,-1,md,
 +                  state->x,savex,NULL,
 +                  fr->bMolPBC,state->box,
 +                  state->lambda[efptBONDED],&dvdl_dum,
 +                  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];
 +            }
 +        }
 +    }
 +    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,tabfactor,tmp;
 +
 +  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].table_elec_vdw.scale;
 +      vdwtab = fr->nblists[0].table_vdw.data;
 +
 +      /* 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.
 +           * Table has a scale factor since we have scaled it down to compensate
 +           * for scaling-up c6/c12 with the derivative factors to save flops in analytical kernels.
 +           */
 +          fr->enershiftsix    = (real)(-1.0/(rc3*rc3)) - 6.0*vdwtab[8*ri0];
 +          fr->enershifttwelve = (real)( 1.0/(rc9*rc3)) - 12.0*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;
 +            /* Since the dispersion table has been scaled down a factor 6.0 and the repulsion
 +             * a factor 12.0 to compensate for the c6/c12 parameters inside nbfp[] being scaled
 +             * up (to save flops in kernels), we need to correct for this.
 +             */
 +            tabfactor = 6.0;
 +        }
 +        else
 +        {
 +            offstart = 4;
 +            tabfactor = 12.0;
 +        }
 +      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*tabfactor;
 +        virsum  *= 4.0*M_PI*tabfactor;
 +        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;
 +      /* Contribution beyond the cut-off */
 +      eners[0] += -4.0*M_PI/(3.0*rc3);
 +      eners[1] +=  4.0*M_PI/(9.0*rc9);
 +      if (fr->vdw_modifier==eintmodPOTSHIFT) {
 +          /* Contribution within the cut-off */
 +          eners[0] += -4.0*M_PI/(3.0*rc3);
 +          eners[1] +=  4.0*M_PI/(3.0*rc9);
 +      }
 +      /* Contribution beyond the cut-off */
 +      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,
 +                wallclock_gpu_t *gputimes,
 +                int omp_nth_pp,
 +                gmx_bool bWriteStat)
 +{
 +    int    i,j;
 +    t_nrnb *nrnb_tot=NULL;
 +    real   delta_t;
 +    double nbfs,mflop;
 +
 +    wallcycle_sum(cr,wcycle);
 +
 +    if (cr->nnodes > 1)
 +    {
 +        snew(nrnb_tot,1);
 +#ifdef GMX_MPI
 +        MPI_Allreduce(nrnb->n,nrnb_tot->n,eNRNB,MPI_DOUBLE,MPI_SUM,
 +                      cr->mpi_comm_mysim);
 +#endif
 +    }
 +    else
 +    {
 +        nrnb_tot = nrnb;
 +    }
 +
 +#if defined(GMX_MPI) && !defined(GMX_THREAD_MPI)
 +    if (cr->nnodes > 1)
 +    {
 +        /* reduce nodetime over all MPI processes in the current simulation */
 +        double sum;
 +        MPI_Allreduce(&runtime->proctime,&sum,1,MPI_DOUBLE,MPI_SUM,
 +                      cr->mpi_comm_mysim);
 +        runtime->proctime = sum;
 +    }
 +#endif
 +
 +    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,gputimes);
 +
 +        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,
 +                       omp_nth_pp);
 +        }
 +        if (bWriteStat)
 +        {
 +            print_perf(stderr,runtime->proctime,runtime->realtime,
 +                       cr->nnodes-cr->npmenodes,
 +                       runtime->nsteps_done,delta_t,nbfs,mflop,
 +                       omp_nth_pp);
 +        }
 +    }
 +}
 +
 +extern void initialize_lambdas(FILE *fplog,t_inputrec *ir,int *fep_state,real *lambda,double *lam0)
 +{
 +    /* this function works, but could probably use a logic rewrite to keep all the different
 +       types of efep straight. */
 +
 +    int i;
 +    t_lambda *fep = ir->fepvals;
 +
 +    if ((ir->efep==efepNO) && (ir->bSimTemp == FALSE)) {
 +        for (i=0;i<efptNR;i++)  {
 +            lambda[i] = 0.0;
 +            if (lam0)
 +            {
 +                lam0[i] = 0.0;
 +            }
 +        }
 +        return;
 +    } else {
 +        *fep_state = fep->init_fep_state; /* this might overwrite the checkpoint
 +                                             if checkpoint is set -- a kludge is in for now
 +                                             to prevent this.*/
 +        for (i=0;i<efptNR;i++)
 +        {
 +            /* overwrite lambda state with init_lambda for now for backwards compatibility */
 +            if (fep->init_lambda>=0) /* if it's -1, it was never initializd */
 +            {
 +                lambda[i] = fep->init_lambda;
 +                if (lam0) {
 +                    lam0[i] = lambda[i];
 +                }
 +            }
 +            else
 +            {
 +                lambda[i] = fep->all_lambda[i][*fep_state];
 +                if (lam0) {
 +                    lam0[i] = lambda[i];
 +                }
 +            }
 +        }
 +        if (ir->bSimTemp) {
 +            /* need to rescale control temperatures to match current state */
 +            for (i=0;i<ir->opts.ngtc;i++) {
 +                if (ir->opts.ref_t[i] > 0) {
 +                    ir->opts.ref_t[i] = ir->simtempvals->temperatures[*fep_state];
 +                }
 +            }
 +        }
 +    }
 +
 +    /* Send to the log the information on the current lambdas */
 +    if (fplog != NULL)
 +    {
 +        fprintf(fplog,"Initial vector of lambda components:[ ");
 +        for (i=0;i<efptNR;i++)
 +        {
 +            fprintf(fplog,"%10.4f ",lambda[i]);
 +        }
 +        fprintf(fplog,"]\n");
 +    }
 +    return;
 +}
 +
 +
 +void init_md(FILE *fplog,
 +             t_commrec *cr,t_inputrec *ir,const output_env_t oenv,
 +             double *t,double *t0,
 +             real *lambda, int *fep_state, 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;
 +
 +    *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);
 +    }
 +
 +    /* Initialize lambda variables */
 +    initialize_lambdas(fplog,ir,fep_state,lambda,lam0);
 +
 +    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);
 +    }
 +
 +    if (ir->bAdress)
 +    {
 +      please_cite(fplog,"Fritsch12");
 +      please_cite(fplog,"Junghans10");
 +    }
 +    /* Initiate variables */
 +    clear_mat(force_vir);
 +    clear_mat(shake_vir);
 +    clear_rvec(mu_tot);
 +
 +    debug_gmx();
 +}
 +
index b330f848880274dcf3ad23c0c8e6809a162f6894,0000000000000000000000000000000000000000..3c542cac0fbc33ec559fa77138b130c67dc84f63
mode 100644,000000..100644
--- /dev/null
@@@ -1,9 -1,0 +1,9 @@@
- file(GLOB PROTONATE_SOURCES g_protonate.c)
 +include_directories(${CMAKE_SOURCE_DIR}/src/gromacs/gmxpreprocess)
 +
++file(GLOB PROTONATE_SOURCES g_protonate.c ../main.cpp)
 +
 +add_executable(g_protonate ${PROTONATE_SOURCES})
 +gmx_add_man_page(g_protonate)
 +target_link_libraries(g_protonate ${GMX_EXTRA_LIBRARIES} libgromacs ${GMX_EXE_LINKER_FLAGS})
 +set_target_properties(g_protonate PROPERTIES OUTPUT_NAME "g_protonate${GMX_BINARY_SUFFIX}")
 +install(TARGETS g_protonate DESTINATION ${BIN_INSTALL_DIR} COMPONENT runtime)
index 6d965db387f1024b567fa4a5ec2302ee26a98c9c,0000000000000000000000000000000000000000..0280d4962a2cbdccd39e61c2d758267e6ced4d69
mode 100644,000000..100644
--- /dev/null
@@@ -1,9 -1,0 +1,9 @@@
- file(GLOB X2TOP_SOURCES g_x2top.c nm2type.c)
 +include_directories(${CMAKE_SOURCE_DIR}/src/gromacs/gmxpreprocess)
 +
++file(GLOB X2TOP_SOURCES g_x2top.c nm2type.c ../main.cpp)
 +
 +add_executable(g_x2top ${X2TOP_SOURCES})
 +gmx_add_man_page(g_x2top)
 +target_link_libraries(g_x2top ${GMX_EXTRA_LIBRARIES} libgromacs ${GMX_EXE_LINKER_FLAGS})
 +set_target_properties(g_x2top PROPERTIES OUTPUT_NAME "g_x2top${GMX_BINARY_SUFFIX}")
 +install(TARGETS g_x2top DESTINATION ${BIN_INSTALL_DIR} COMPONENT runtime)
Simple merge
index aa2342e945d04d73e115532f585cdfaf203d8380,0000000000000000000000000000000000000000..321b867cbfda414f5ef634552d820e0d0b6896a9
mode 100644,000000..100644
--- /dev/null
@@@ -1,7 -1,0 +1,7 @@@
- file(GLOB GMXCHECK_SOURCES gmxcheck.c tpbcmp.c)
++file(GLOB GMXCHECK_SOURCES gmxcheck.c tpbcmp.c ../main.cpp)
 +
 +add_executable(gmxcheck ${GMXCHECK_SOURCES})
 +gmx_add_man_page(gmxcheck)
 +target_link_libraries(gmxcheck ${GMX_EXTRA_LIBRARIES} libgromacs ${GMX_EXE_LINKER_FLAGS})
 +set_target_properties(gmxcheck PROPERTIES OUTPUT_NAME "gmxcheck${GMX_BINARY_SUFFIX}")
 +install(TARGETS gmxcheck DESTINATION ${BIN_INSTALL_DIR} COMPONENT runtime)
Simple merge
Simple merge
index 821a04135c874e77e19f90c5a0d2ec49c9aa1a12,0000000000000000000000000000000000000000..de472135aa0fab0abf69841b4e45689f26812488
mode 100644,000000..100644
--- /dev/null
@@@ -1,7 -1,0 +1,7 @@@
- file(GLOB GMXDUMP_SOURCES gmxdump.c)
++file(GLOB GMXDUMP_SOURCES gmxdump.c ../main.cpp)
 +
 +add_executable(gmxdump ${GMXDUMP_SOURCES})
 +gmx_add_man_page(gmxdump)
 +target_link_libraries(gmxdump ${GMX_EXTRA_LIBRARIES} libgromacs ${GMX_EXE_LINKER_FLAGS})
 +set_target_properties(gmxdump PROPERTIES OUTPUT_NAME "gmxdump${GMX_BINARY_SUFFIX}")
 +install(TARGETS gmxdump DESTINATION ${BIN_INSTALL_DIR} COMPONENT runtime)
index abfaa6712be587ad12a5df356623734148af27fb,0000000000000000000000000000000000000000..f580688ed8105d0e0a0af163b7ea02e9e98ca3fa
mode 100644,000000..100644
--- /dev/null
@@@ -1,489 -1,0 +1,489 @@@
- int main(int argc,char *argv[])
 +/*
 + * 
 + *                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 <stdio.h>
 +#include <string.h>
 +#include <math.h>
 +#include <assert.h>
 +#include "main.h"
 +#include "macros.h"
 +#include "futil.h"
 +#include "statutil.h"
 +#include "copyrite.h"
 +#include "sysstuff.h"
 +#include "txtdump.h"
 +#include "gmx_fatal.h"
 +#include "xtcio.h"
 +#include "enxio.h"
 +#include "smalloc.h"
 +#include "names.h"
 +#include "gmxfio.h"
 +#include "tpxio.h"
 +#include "trnio.h"
 +#include "txtdump.h"
 +#include "gmxcpp.h"
 +#include "checkpoint.h"
 +#include "mtop_util.h"
 +
 +#include "gromacs/linearalgebra/mtxio.h"
 +#include "gromacs/linearalgebra/sparsematrix.h"
 +
 +
 +static void list_tpx(const char *fn, gmx_bool bShowNumbers,const char *mdpfn,
 +                     gmx_bool bSysTop)
 +{
 +  FILE *gp;
 +  int         fp,indent,i,j,**gcount,atot;
 +  t_state     state;
 +  rvec        *f=NULL;
 +  t_inputrec  ir;
 +  t_tpxheader tpx;
 +  gmx_mtop_t  mtop;
 +  gmx_groups_t *groups;
 +  t_topology  top;
 +
 +  read_tpxheader(fn,&tpx,TRUE,NULL,NULL);
 +
 +  read_tpx_state(fn,
 +               tpx.bIr  ? &ir : NULL,
 +               &state,tpx.bF ? f : NULL,
 +               tpx.bTop ? &mtop: NULL);
 +  
 +  if (mdpfn && tpx.bIr) {
 +    gp = gmx_fio_fopen(mdpfn,"w");
 +    pr_inputrec(gp,0,NULL,&(ir),TRUE);
 +    gmx_fio_fclose(gp);
 +  }
 +
 +  if (!mdpfn) {  
 +    if (bSysTop)
 +      top = gmx_mtop_t_to_t_topology(&mtop);
 +
 +    if (available(stdout,&tpx,0,fn)) {
 +      indent=0;
 +      indent=pr_title(stdout,indent,fn);
 +      pr_inputrec(stdout,0,"inputrec",tpx.bIr ? &(ir) : NULL,FALSE);
 +      
 +      indent = 0;
 +      pr_header(stdout,indent,"header",&(tpx));
 +      
 +      if (!bSysTop)
 +      pr_mtop(stdout,indent,"topology",&(mtop),bShowNumbers);
 +      else
 +      pr_top(stdout,indent,"topology",&(top),bShowNumbers);
 +
 +      pr_rvecs(stdout,indent,"box",tpx.bBox ? state.box : NULL,DIM);
 +      pr_rvecs(stdout,indent,"box_rel",tpx.bBox ? state.box_rel : NULL,DIM);
 +      pr_rvecs(stdout,indent,"boxv",tpx.bBox ? state.boxv : NULL,DIM);
 +      pr_rvecs(stdout,indent,"pres_prev",tpx.bBox ? state.pres_prev : NULL,DIM);
 +      pr_rvecs(stdout,indent,"svir_prev",tpx.bBox ? state.svir_prev : NULL,DIM);
 +      pr_rvecs(stdout,indent,"fvir_prev",tpx.bBox ? state.fvir_prev : NULL,DIM);
 +      /* leave nosehoover_xi in for now to match the tpr version */
 +      pr_doubles(stdout,indent,"nosehoover_xi",state.nosehoover_xi,state.ngtc);
 +      /*pr_doubles(stdout,indent,"nosehoover_vxi",state.nosehoover_vxi,state.ngtc);*/
 +      /*pr_doubles(stdout,indent,"therm_integral",state.therm_integral,state.ngtc);*/
 +      pr_rvecs(stdout,indent,"x",tpx.bX ? state.x : NULL,state.natoms);
 +      pr_rvecs(stdout,indent,"v",tpx.bV ? state.v : NULL,state.natoms);
 +      if (tpx.bF) {
 +      pr_rvecs(stdout,indent,"f",f,state.natoms);
 +      }
 +    }
 +    
 +    groups = &mtop.groups;
 +
 +    snew(gcount,egcNR);
 +    for(i=0; (i<egcNR); i++) 
 +      snew(gcount[i],groups->grps[i].nr);
 +    
 +    for(i=0; (i<mtop.natoms); i++) {
 +      for(j=0; (j<egcNR); j++) 
 +      gcount[j][ggrpnr(groups,j,i)]++;
 +    }
 +    printf("Group statistics\n");
 +    for(i=0; (i<egcNR); i++) {
 +      atot=0;
 +      printf("%-12s: ",gtypes[i]);
 +      for(j=0; (j<groups->grps[i].nr); j++) {
 +      printf("  %5d",gcount[i][j]);
 +      atot+=gcount[i][j];
 +      }
 +      printf("  (total %d atoms)\n",atot);
 +      sfree(gcount[i]);
 +    }
 +    sfree(gcount);
 +  }
 +  done_state(&state);
 +  sfree(f);
 +}
 +
 +static void list_top(const char *fn)
 +{
 +  int status,done;
 +#define BUFLEN 256
 +  char buf[BUFLEN];
 +  gmx_cpp_t handle;
 +  char *cppopts[] = { NULL };
 +
 +  status = cpp_open_file(fn,&handle,cppopts);
 +  if (status != 0) 
 +    gmx_fatal(FARGS,cpp_error(&handle,status));
 +  do {
 +    status = cpp_read_line(&handle,BUFLEN,buf);
 +    done = (status == eCPP_EOF);
 +    if (!done) {
 +      if (status != eCPP_OK)
 +      gmx_fatal(FARGS,cpp_error(&handle,status));
 +      else 
 +      printf("%s\n",buf);
 +    }
 +  } while (!done);
 +  status = cpp_close_file(&handle);
 +  if (status != eCPP_OK) 
 +    gmx_fatal(FARGS,cpp_error(&handle,status));
 +}
 +
 +static void list_trn(const char *fn)
 +{
 +  t_fileio    *fpread, *fpwrite;
 +  int         nframe,indent;
 +  char        buf[256];
 +  rvec        *x,*v,*f;
 +  matrix      box;
 +  t_trnheader trn;
 +  gmx_bool        bOK;
 +
 +  fpread  = open_trn(fn,"r"); 
 +  fpwrite = open_tpx(NULL,"w");
 +  gmx_fio_setdebug(fpwrite,TRUE);
 +  
 +  nframe = 0;
 +  while (fread_trnheader(fpread,&trn,&bOK)) {
 +    snew(x,trn.natoms);
 +    snew(v,trn.natoms);
 +    snew(f,trn.natoms);
 +    if (fread_htrn(fpread,&trn,
 +                 trn.box_size ? box : NULL,
 +                 trn.x_size   ? x : NULL,
 +                 trn.v_size   ? v : NULL,
 +                 trn.f_size   ? f : NULL)) {
 +      sprintf(buf,"%s frame %d",fn,nframe);
 +      indent=0;
 +      indent=pr_title(stdout,indent,buf);
 +      pr_indent(stdout,indent);
 +      fprintf(stdout,"natoms=%10d  step=%10d  time=%12.7e  lambda=%10g\n",
 +            trn.natoms,trn.step,trn.t,trn.lambda);
 +      if (trn.box_size)
 +      pr_rvecs(stdout,indent,"box",box,DIM);
 +      if (trn.x_size)
 +      pr_rvecs(stdout,indent,"x",x,trn.natoms);
 +      if (trn.v_size)
 +      pr_rvecs(stdout,indent,"v",v,trn.natoms);
 +      if (trn.f_size)
 +      pr_rvecs(stdout,indent,"f",f,trn.natoms);
 +    } 
 +    else
 +      fprintf(stderr,"\nWARNING: Incomplete frame: nr %d, t=%g\n",
 +            nframe,trn.t);
 +    
 +    sfree(x);
 +    sfree(v);
 +    sfree(f);
 +    nframe++;
 +  }
 +  if (!bOK)
 +    fprintf(stderr,"\nWARNING: Incomplete frame header: nr %d, t=%g\n",
 +          nframe,trn.t);
 +  close_tpx(fpwrite);
 +  close_trn(fpread);
 +}
 +
 +void list_xtc(const char *fn, gmx_bool bXVG)
 +{
 +  t_fileio *xd;
 +  int    indent;
 +  char   buf[256];
 +  rvec   *x;
 +  matrix box;
 +  int    nframe,natoms,step;
 +  real   prec,time;
 +  gmx_bool   bOK;
 +  
 +  xd = open_xtc(fn,"r");
 +  read_first_xtc(xd,&natoms,&step,&time,box,&x,&prec,&bOK);
 +              
 +  nframe=0;
 +  do {
 +    if (bXVG) {
 +      int i,d;
 +      
 +      fprintf(stdout,"%g",time);
 +      for(i=0; i<natoms; i++)
 +      for(d=0; d<DIM; d++)
 +        fprintf(stdout," %g",x[i][d]);
 +      fprintf(stdout,"\n");
 +    } else {
 +      sprintf(buf,"%s frame %d",fn,nframe);
 +      indent=0;
 +      indent=pr_title(stdout,indent,buf);
 +      pr_indent(stdout,indent);
 +      fprintf(stdout,"natoms=%10d  step=%10d  time=%12.7e  prec=%10g\n",
 +          natoms,step,time,prec);
 +      pr_rvecs(stdout,indent,"box",box,DIM);
 +      pr_rvecs(stdout,indent,"x",x,natoms);
 +    }
 +    nframe++;
 +  } while (read_next_xtc(xd,natoms,&step,&time,box,x,&prec,&bOK));
 +  if (!bOK)
 +    fprintf(stderr,"\nWARNING: Incomplete frame at time %g\n",time);
 +  close_xtc(xd);
 +}
 +
 +void list_trx(const char *fn,gmx_bool bXVG)
 +{
 +  int ftp;
 +  
 +  ftp = fn2ftp(fn);
 +  if (ftp == efXTC)
 +    list_xtc(fn,bXVG);
 +  else if ((ftp == efTRR) || (ftp == efTRJ))
 +    list_trn(fn);
 +  else
 +    fprintf(stderr,"File %s is of an unsupported type. Try using the command\n 'less %s'\n",
 +          fn,fn);
 +}
 +
 +void list_ene(const char *fn)
 +{
 +    int        ndr;
 +    ener_file_t in;
 +    gmx_bool       bCont;
 +    gmx_enxnm_t *enm=NULL;
 +    t_enxframe *fr;
 +    int        i,j,nre,b;
 +    real       rav,minthird;
 +    char       buf[22];
 +
 +    printf("gmxdump: %s\n",fn);
 +    in = open_enx(fn,"r");
 +    do_enxnms(in,&nre,&enm);
 +    assert(enm);
 +
 +    printf("energy components:\n");
 +    for(i=0; (i<nre); i++) 
 +        printf("%5d  %-24s (%s)\n",i,enm[i].name,enm[i].unit);
 +
 +    minthird=-1.0/3.0;
 +    snew(fr,1);
 +    do {
 +        bCont=do_enx(in,fr);
 +
 +        if (bCont) 
 +        {
 +            printf("\n%24s  %12.5e  %12s  %12s\n","time:",
 +                   fr->t,"step:",gmx_step_str(fr->step,buf));
 +            printf("%24s  %12s  %12s  %12s\n",
 +                   "","","nsteps:",gmx_step_str(fr->nsteps,buf));
 +            printf("%24s  %12.5e  %12s  %12s\n",
 +                   "delta_t:",fr->dt,"sum steps:",gmx_step_str(fr->nsum,buf));
 +            if (fr->nre == nre) {
 +                printf("%24s  %12s  %12s  %12s\n",
 +                       "Component","Energy","Av. Energy","Sum Energy");
 +                if (fr->nsum > 0) {
 +                    for(i=0; (i<nre); i++) 
 +                        printf("%24s  %12.5e  %12.5e  %12.5e\n",
 +                               enm[i].name,fr->ener[i].e,fr->ener[i].eav,
 +                               fr->ener[i].esum);
 +                } else {
 +                    for(i=0; (i<nre); i++) 
 +                        printf("%24s  %12.5e\n",
 +                               enm[i].name,fr->ener[i].e);
 +                }
 +            }
 +            for(b=0; b<fr->nblock; b++)
 +            {
 +                const char *typestr="";
 +
 +                t_enxblock *eb=&(fr->block[b]);
 +                printf("Block data %2d (%3d subblocks, id=%d)\n",
 +                     b, eb->nsub, eb->id);
 +
 +                if (eb->id < enxNR)
 +                    typestr=enx_block_id_name[eb->id];
 +                printf("  id='%s'\n", typestr);
 +                for(i=0;i<eb->nsub;i++)
 +                {
 +                    t_enxsubblock *sb=&(eb->sub[i]);
 +                    printf("  Sub block %3d (%5d elems, type=%s) values:\n", 
 +                           i, sb->nr, xdr_datatype_names[sb->type]);
 +
 +                    switch(sb->type)
 +                    {
 +                        case xdr_datatype_float:
 +                            for(j=0;j<sb->nr;j++)
 +                                printf("%14d   %8.4f\n",j, sb->fval[j]);
 +                            break;
 +                        case xdr_datatype_double:
 +                            for(j=0;j<sb->nr;j++)
 +                                printf("%14d   %10.6f\n",j, sb->dval[j]);
 +                            break;
 +                        case xdr_datatype_int:
 +                            for(j=0;j<sb->nr;j++)
 +                                printf("%14d %10d\n",j, sb->ival[j]);
 +                            break;
 +                        case xdr_datatype_large_int:
 +                            for(j=0;j<sb->nr;j++)
 +                                printf("%14d %s\n",
 +                                     j, gmx_step_str(sb->lval[j],buf));
 +                            break;
 +                        case xdr_datatype_char:
 +                            for(j=0;j<sb->nr;j++)
 +                                printf("%14d %1c\n",j, sb->cval[j]);
 +                            break;
 +                        case xdr_datatype_string:
 +                            for(j=0;j<sb->nr;j++)
 +                                printf("%14d %80s\n",j, sb->sval[j]);
 +                            break;
 +                        default:
 +                            gmx_incons("Unknown subblock type");
 +                    }
 +                }
 +            }
 +        }
 +    } while (bCont);
 +
 +    close_enx(in);
 +
 +    free_enxframe(fr);
 +    sfree(fr);
 +    sfree(enm);
 +}
 +
 +static void list_mtx(const char *fn)
 +{
 +  int  nrow,ncol,i,j,k;
 +  real *full=NULL,value;
 +  gmx_sparsematrix_t * sparse=NULL;
 +
 +  gmx_mtxio_read(fn,&nrow,&ncol,&full,&sparse);
 +
 +  if (full == NULL) {
 +    snew(full,nrow*ncol);
 +    for(i=0;i<nrow*ncol;i++) {
 +      full[i] = 0;
 +    }
 +    
 +    for(i=0;i<sparse->nrow;i++) {
 +      for(j=0;j<sparse->ndata[i];j++) {
 +        k     = sparse->data[i][j].col;
 +        value = sparse->data[i][j].value;
 +        full[i*ncol+k] = value;
 +        full[k*ncol+i] = value;
 +      }
 +    }
 +    gmx_sparsematrix_destroy(sparse);
 +  }
 +
 +  printf("%d %d\n",nrow,ncol);
 +  for(i=0; i<nrow; i++) {
 +    for(j=0; j<ncol; j++) {
 +      printf(" %g",full[i*ncol+j]);
 +    }
 +    printf("\n");
 +  }
 +
 +  sfree(full);
 +}
 +
++int cmain(int argc,char *argv[])
 +{
 +  const char *desc[] = {
 +    "[TT]gmxdump[tt] reads a run input file ([TT].tpa[tt]/[TT].tpr[tt]/[TT].tpb[tt]),",
 +    "a trajectory ([TT].trj[tt]/[TT].trr[tt]/[TT].xtc[tt]), an energy",
 +    "file ([TT].ene[tt]/[TT].edr[tt]), or a checkpoint file ([TT].cpt[tt])",
 +    "and prints that to standard output in a readable format.",
 +    "This program is essential for checking your run input file in case of",
 +    "problems.[PAR]",
 +    "The program can also preprocess a topology to help finding problems.",
 +    "Note that currently setting [TT]GMXLIB[tt] is the only way to customize",
 +    "directories used for searching include files.",
 +  };
 +  t_filenm fnm[] = {
 +    { efTPX, "-s", NULL, ffOPTRD },
 +    { efTRX, "-f", NULL, ffOPTRD },
 +    { efEDR, "-e", NULL, ffOPTRD },
 +    { efCPT, NULL, NULL, ffOPTRD },
 +    { efTOP, "-p", NULL, ffOPTRD },
 +    { efMTX, "-mtx", "hessian", ffOPTRD }, 
 +    { efMDP, "-om", NULL, ffOPTWR }
 +  };
 +#define NFILE asize(fnm)
 +
 +  output_env_t oenv;
 +  /* Command line options */
 +  static gmx_bool bXVG=FALSE;
 +  static gmx_bool bShowNumbers=TRUE;
 +  static gmx_bool bSysTop=FALSE;
 +  t_pargs pa[] = {
 +    { "-xvg", FALSE, etBOOL, {&bXVG}, "HIDDENXVG layout for xtc" },
 +    { "-nr",FALSE, etBOOL, {&bShowNumbers},"Show index numbers in output (leaving them out makes comparison easier, but creates a useless topology)" },
 +    { "-sys", FALSE, etBOOL, {&bSysTop}, "List the atoms and bonded interactions for the whole system instead of for each molecule type" }
 +  };
 +  
 +  CopyRight(stderr,argv[0]);
 +  parse_common_args(&argc,argv,0,NFILE,fnm,asize(pa),pa,
 +                  asize(desc),desc,0,NULL,&oenv);
 +
 +
 +  if (ftp2bSet(efTPX,NFILE,fnm))
 +    list_tpx(ftp2fn(efTPX,NFILE,fnm),bShowNumbers,
 +           ftp2fn_null(efMDP,NFILE,fnm),bSysTop);
 +  else if (ftp2bSet(efTRX,NFILE,fnm)) 
 +    list_trx(ftp2fn(efTRX,NFILE,fnm),bXVG);
 +  else if (ftp2bSet(efEDR,NFILE,fnm))
 +    list_ene(ftp2fn(efEDR,NFILE,fnm));
 +  else if (ftp2bSet(efCPT,NFILE,fnm))
 +    list_checkpoint(ftp2fn(efCPT,NFILE,fnm),stdout);
 +  else if (ftp2bSet(efTOP,NFILE,fnm))
 +    list_top(ftp2fn(efTOP,NFILE,fnm));
 +  else if (ftp2bSet(efMTX,NFILE,fnm))
 +    list_mtx(ftp2fn(efMTX,NFILE,fnm));
 +    
 +  thanx(stderr);
 +
 +  return 0;
 +}
index 5d1eaadf313890507967c65e71cff2b792b22b50,0000000000000000000000000000000000000000..5b01e8e13fe9bf9f2a60b4cfeda795ef95dc686e
mode 100644,000000..100644
--- /dev/null
@@@ -1,9 -1,0 +1,9 @@@
- file(GLOB GROMPP_SOURCES *.c)
 +include_directories(${CMAKE_SOURCE_DIR}/src/gromacs/gmxpreprocess)
 +
++file(GLOB GROMPP_SOURCES *.c  ../main.cpp)
 +
 +add_executable(grompp ${GROMPP_SOURCES})
 +gmx_add_man_page(grompp)
 +target_link_libraries(grompp ${GMX_EXTRA_LIBRARIES} libgromacs ${GMX_EXE_LINKER_FLAGS})
 +set_target_properties(grompp PROPERTIES OUTPUT_NAME "grompp${GMX_BINARY_SUFFIX}")
 +install(TARGETS grompp DESTINATION ${BIN_INSTALL_DIR} COMPONENT runtime)
index 1be9796a3c2c24f5a4b4f895cbccd0a877b12e2e,0000000000000000000000000000000000000000..a14c52231a7451208404f77473b4793f6af47a7a
mode 100644,000000..100644
--- /dev/null
@@@ -1,1773 -1,0 +1,1773 @@@
- int main (int argc, char *argv[])
 +/*  -*- 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.03
 + * 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 <sys/types.h>
 +#include <math.h>
 +#include <string.h>
 +#include <errno.h>
 +#include <limits.h>
 +
 +#include "sysstuff.h"
 +#include "smalloc.h"
 +#include "macros.h"
 +#include "string2.h"
 +#include "readir.h"
 +#include "toputil.h"
 +#include "topio.h"
 +#include "confio.h"
 +#include "copyrite.h"
 +#include "readir.h"
 +#include "symtab.h"
 +#include "names.h"
 +#include "grompp.h"
 +#include "random.h"
 +#include "vec.h"
 +#include "futil.h"
 +#include "statutil.h"
 +#include "splitter.h"
 +#include "sortwater.h"
 +#include "convparm.h"
 +#include "gmx_fatal.h"
 +#include "warninp.h"
 +#include "index.h"
 +#include "gmxfio.h"
 +#include "trnio.h"
 +#include "tpxio.h"
 +#include "vsite_parm.h"
 +#include "txtdump.h"
 +#include "calcgrid.h"
 +#include "add_par.h"
 +#include "enxio.h"
 +#include "perf_est.h"
 +#include "compute_io.h"
 +#include "gpp_atomtype.h"
 +#include "gpp_tomorse.h"
 +#include "mtop_util.h"
 +#include "genborn.h"
 +#include "calc_verletbuf.h"
 +
 +static int rm_interactions(int ifunc,int nrmols,t_molinfo mols[])
 +{
 +  int  i,n;
 +  
 +  n=0;
 +  /* For all the molecule types */
 +  for(i=0; i<nrmols; i++) {
 +    n += mols[i].plist[ifunc].nr;
 +    mols[i].plist[ifunc].nr=0;
 +  }
 +  return n;
 +}
 +
 +static int check_atom_names(const char *fn1, const char *fn2, 
 +                          gmx_mtop_t *mtop, t_atoms *at)
 +{
 +  int mb,m,i,j,nmismatch;
 +  t_atoms *tat;
 +#define MAXMISMATCH 20
 +
 +  if (mtop->natoms != at->nr)
 +    gmx_incons("comparing atom names");
 +  
 +  nmismatch=0;
 +  i = 0;
 +  for(mb=0; mb<mtop->nmolblock; mb++) {
 +    tat = &mtop->moltype[mtop->molblock[mb].type].atoms;
 +    for(m=0; m<mtop->molblock[mb].nmol; m++) {
 +      for(j=0; j < tat->nr; j++) {
 +      if (strcmp( *(tat->atomname[j]) , *(at->atomname[i]) ) != 0) {
 +        if (nmismatch < MAXMISMATCH) {
 +          fprintf(stderr,
 +                  "Warning: atom name %d in %s and %s does not match (%s - %s)\n",
 +                  i+1, fn1, fn2, *(tat->atomname[j]), *(at->atomname[i]));
 +        } else if (nmismatch == MAXMISMATCH) {
 +          fprintf(stderr,"(more than %d non-matching atom names)\n",MAXMISMATCH);
 +        }
 +        nmismatch++;
 +      }
 +      i++;
 +      }
 +    }
 +  }
 +
 +  return nmismatch;
 +}
 +
 +static void check_eg_vs_cg(gmx_mtop_t *mtop)
 +{
 +  int astart,mb,m,cg,j,firstj;
 +  unsigned char firsteg,eg;
 +  gmx_moltype_t *molt;
 +  
 +  /* Go through all the charge groups and make sure all their
 +   * atoms are in the same energy group.
 +   */
 +  
 +  astart = 0;
 +  for(mb=0; mb<mtop->nmolblock; mb++) {
 +    molt = &mtop->moltype[mtop->molblock[mb].type];
 +    for(m=0; m<mtop->molblock[mb].nmol; m++) {
 +      for(cg=0; cg<molt->cgs.nr;cg++) {
 +      /* Get the energy group of the first atom in this charge group */
 +      firstj = astart + molt->cgs.index[cg];
 +      firsteg = ggrpnr(&mtop->groups,egcENER,firstj);
 +      for(j=molt->cgs.index[cg]+1;j<molt->cgs.index[cg+1];j++) {
 +        eg = ggrpnr(&mtop->groups,egcENER,astart+j);
 +        if(eg != firsteg) {
 +          gmx_fatal(FARGS,"atoms %d and %d in charge group %d of molecule type '%s' are in different energy groups",
 +                    firstj+1,astart+j+1,cg+1,*molt->name);
 +        }
 +      }
 +      }
 +      astart += molt->atoms.nr;
 +    }
 +  }  
 +}
 +
 +static void check_cg_sizes(const char *topfn,t_block *cgs,warninp_t wi)
 +{
 +    int  maxsize,cg;
 +    char warn_buf[STRLEN];
 +
 +    maxsize = 0;
 +    for(cg=0; cg<cgs->nr; cg++)
 +    {
 +        maxsize = max(maxsize,cgs->index[cg+1]-cgs->index[cg]);
 +    }
 +    
 +    if (maxsize > MAX_CHARGEGROUP_SIZE)
 +    {
 +        gmx_fatal(FARGS,"The largest charge group contains %d atoms. The maximum is %d.",maxsize,MAX_CHARGEGROUP_SIZE);
 +    }
 +    else if (maxsize > 10)
 +    {
 +        set_warning_line(wi,topfn,-1);
 +        sprintf(warn_buf,
 +                "The largest charge group contains %d atoms.\n"
 +                "Since atoms only see each other when the centers of geometry of the charge groups they belong to are within the cut-off distance, too large charge groups can lead to serious cut-off artifacts.\n"
 +                "For efficiency and accuracy, charge group should consist of a few atoms.\n"
 +                "For all-atom force fields use: CH3, CH2, CH, NH2, NH, OH, CO2, CO, etc.",
 +                maxsize);
 +        warning_note(wi,warn_buf);
 +    }
 +}
 +
 +static void check_bonds_timestep(gmx_mtop_t *mtop,double dt,warninp_t wi)
 +{
 +    /* This check is not intended to ensure accurate integration,
 +     * rather it is to signal mistakes in the mdp settings.
 +     * A common mistake is to forget to turn on constraints
 +     * for MD after energy minimization with flexible bonds.
 +     * This check can also detect too large time steps for flexible water
 +     * models, but such errors will often be masked by the constraints
 +     * mdp options, which turns flexible water into water with bond constraints,
 +     * but without an angle constraint. Unfortunately such incorrect use
 +     * of water models can not easily be detected without checking
 +     * for specific model names.
 +     *
 +     * The stability limit of leap-frog or velocity verlet is 4.44 steps
 +     * per oscillational period.
 +     * But accurate bonds distributions are lost far before that limit.
 +     * To allow relatively common schemes (although not common with Gromacs)
 +     * of dt=1 fs without constraints and dt=2 fs with only H-bond constraints
 +     * we set the note limit to 10.
 +     */
 +    int       min_steps_warn=5;
 +    int       min_steps_note=10;
 +    t_iparams *ip;
 +    int       molt;
 +    gmx_moltype_t *moltype,*w_moltype;
 +    t_atom    *atom;
 +    t_ilist   *ilist,*ilb,*ilc,*ils;
 +    int       ftype;
 +    int       i,a1,a2,w_a1,w_a2,j;
 +    real      twopi2,limit2,fc,re,m1,m2,period2,w_period2;
 +    gmx_bool  bFound,bWater,bWarn;
 +    char      warn_buf[STRLEN];
 +
 +    ip = mtop->ffparams.iparams;
 +
 +    twopi2 = sqr(2*M_PI);
 +
 +    limit2 = sqr(min_steps_note*dt);
 +
 +    w_a1 = w_a2 = -1;
 +    w_period2 = -1.0;
 +    
 +    w_moltype = NULL;
 +    for(molt=0; molt<mtop->nmoltype; molt++)
 +    {
 +        moltype = &mtop->moltype[molt];
 +        atom  = moltype->atoms.atom;
 +        ilist = moltype->ilist;
 +        ilc = &ilist[F_CONSTR];
 +        ils = &ilist[F_SETTLE];
 +        for(ftype=0; ftype<F_NRE; ftype++)
 +        {
 +            if (!(ftype == F_BONDS || ftype == F_G96BONDS || ftype == F_HARMONIC))
 +            {
 +                continue;
 +            }
 +            
 +            ilb = &ilist[ftype];
 +            for(i=0; i<ilb->nr; i+=3)
 +            {
 +                fc = ip[ilb->iatoms[i]].harmonic.krA;
 +                re = ip[ilb->iatoms[i]].harmonic.rA;
 +                if (ftype == F_G96BONDS)
 +                {
 +                    /* Convert squared sqaure fc to harmonic fc */
 +                    fc = 2*fc*re;
 +                }
 +                a1 = ilb->iatoms[i+1];
 +                a2 = ilb->iatoms[i+2];
 +                m1 = atom[a1].m;
 +                m2 = atom[a2].m;
 +                if (fc > 0 && m1 > 0 && m2 > 0)
 +                {
 +                    period2 = twopi2*m1*m2/((m1 + m2)*fc);
 +                }
 +                else
 +                {
 +                    period2 = GMX_FLOAT_MAX;
 +                }
 +                if (debug)
 +                {
 +                    fprintf(debug,"fc %g m1 %g m2 %g period %g\n",
 +                            fc,m1,m2,sqrt(period2));
 +                }
 +                if (period2 < limit2)
 +                {
 +                    bFound = FALSE;
 +                    for(j=0; j<ilc->nr; j+=3)
 +                    {
 +                        if ((ilc->iatoms[j+1] == a1 && ilc->iatoms[j+2] == a2) ||
 +                            (ilc->iatoms[j+1] == a2 && ilc->iatoms[j+2] == a1))
 +                            {
 +                                bFound = TRUE;
 +                            }
 +                        }
 +                    for(j=0; j<ils->nr; j+=4)
 +                    {
 +                        if ((a1 == ils->iatoms[j+1] || a1 == ils->iatoms[j+2] || a1 == ils->iatoms[j+3]) &&
 +                            (a2 == ils->iatoms[j+1] || a2 == ils->iatoms[j+2] || a2 == ils->iatoms[j+3]))
 +                        {
 +                            bFound = TRUE;
 +                        }
 +                    }
 +                    if (!bFound &&
 +                        (w_moltype == NULL || period2 < w_period2))
 +                    {
 +                        w_moltype = moltype;
 +                        w_a1      = a1;
 +                        w_a2      = a2;
 +                        w_period2 = period2;
 +                    }
 +                }
 +            }
 +        }
 +    }
 +    
 +    if (w_moltype != NULL)
 +    {
 +        bWarn = (w_period2 < sqr(min_steps_warn*dt));
 +        /* A check that would recognize most water models */
 +        bWater = ((*w_moltype->atoms.atomname[0])[0] == 'O' &&
 +                  w_moltype->atoms.nr <= 5);
 +        sprintf(warn_buf,"The bond in molecule-type %s between atoms %d %s and %d %s has an estimated oscillational period of %.1e ps, which is less than %d times the time step of %.1e ps.\n"
 +                "%s",
 +                *w_moltype->name,
 +                w_a1+1,*w_moltype->atoms.atomname[w_a1],
 +                w_a2+1,*w_moltype->atoms.atomname[w_a2],
 +                sqrt(w_period2),bWarn ? min_steps_warn : min_steps_note,dt,
 +                bWater ?
 +                "Maybe you asked for fexible water." :
 +                "Maybe you forgot to change the constraints mdp option.");
 +        if (bWarn)
 +        {
 +            warning(wi,warn_buf);
 +        }
 +        else
 +        {
 +            warning_note(wi,warn_buf);
 +        }
 +    }
 +}
 +
 +static void check_vel(gmx_mtop_t *mtop,rvec v[])
 +{
 +  gmx_mtop_atomloop_all_t aloop;
 +  t_atom *atom;
 +  int a;
 +
 +  aloop = gmx_mtop_atomloop_all_init(mtop);
 +  while (gmx_mtop_atomloop_all_next(aloop,&a,&atom)) {
 +    if (atom->ptype == eptShell ||
 +      atom->ptype == eptBond  ||
 +      atom->ptype == eptVSite) {
 +      clear_rvec(v[a]);
 +    }
 +  }
 +}
 +
 +static gmx_bool nint_ftype(gmx_mtop_t *mtop,t_molinfo *mi,int ftype)
 +{
 +  int nint,mb;
 +
 +  nint = 0;
 +  for(mb=0; mb<mtop->nmolblock; mb++) {
 +    nint += mtop->molblock[mb].nmol*mi[mtop->molblock[mb].type].plist[ftype].nr;
 +  }
 +
 +  return nint;
 +}
 +
 +/* This routine reorders the molecule type array
 + * in the order of use in the molblocks,
 + * unused molecule types are deleted.
 + */
 +static void renumber_moltypes(gmx_mtop_t *sys,
 +                            int *nmolinfo,t_molinfo **molinfo)
 +{
 +  int *order,norder,i;
 +  int mb,mi;
 +  t_molinfo *minew;
 +
 +  snew(order,*nmolinfo);
 +  norder = 0;
 +  for(mb=0; mb<sys->nmolblock; mb++) {
 +    for(i=0; i<norder; i++) {
 +      if (order[i] == sys->molblock[mb].type) {
 +      break;
 +      }
 +    }
 +    if (i == norder) {
 +      /* This type did not occur yet, add it */
 +      order[norder] = sys->molblock[mb].type;
 +      /* Renumber the moltype in the topology */
 +      norder++;
 +    }
 +    sys->molblock[mb].type = i;
 +  }
 +  
 +  /* We still need to reorder the molinfo structs */
 +  snew(minew,norder);
 +  for(mi=0; mi<*nmolinfo; mi++) {
 +    for(i=0; i<norder; i++) {
 +      if (order[i] == mi) {
 +      break;
 +      }
 +    }
 +    if (i == norder) {
 +      done_mi(&(*molinfo)[mi]);
 +    } else {
 +      minew[i] = (*molinfo)[mi];
 +    }
 +  }
 +  sfree(*molinfo);
 +
 +  *nmolinfo = norder;
 +  *molinfo  = minew;
 +}
 +
 +static void molinfo2mtop(int nmi,t_molinfo *mi,gmx_mtop_t *mtop)
 +{
 +  int m;
 +  gmx_moltype_t *molt;
 +
 +  mtop->nmoltype = nmi;
 +  snew(mtop->moltype,nmi);
 +  for(m=0; m<nmi; m++) {
 +    molt = &mtop->moltype[m];
 +    molt->name  = mi[m].name;
 +    molt->atoms = mi[m].atoms;
 +    /* ilists are copied later */
 +    molt->cgs   = mi[m].cgs;
 +    molt->excls = mi[m].excls;
 +  }
 +}
 +
 +static void
 +new_status(const char *topfile,const char *topppfile,const char *confin,
 +           t_gromppopts *opts,t_inputrec *ir,gmx_bool bZero,
 +           gmx_bool bGenVel,gmx_bool bVerbose,t_state *state,
 +           gpp_atomtype_t atype,gmx_mtop_t *sys,
 +           int *nmi,t_molinfo **mi,t_params plist[],
 +           int *comb,double *reppow,real *fudgeQQ,
 +           gmx_bool bMorse,
 +           warninp_t wi)
 +{
 +  t_molinfo   *molinfo=NULL;
 +  int         nmolblock;
 +  gmx_molblock_t *molblock,*molbs;
 +  t_atoms     *confat;
 +  int         mb,i,nrmols,nmismatch;
 +  char        buf[STRLEN];
 +  gmx_bool        bGB=FALSE;
 +  char        warn_buf[STRLEN];
 +
 +  init_mtop(sys);
 +
 +  /* Set gmx_boolean for GB */
 +  if(ir->implicit_solvent)
 +    bGB=TRUE;
 +  
 +  /* TOPOLOGY processing */
 +  sys->name = do_top(bVerbose,topfile,topppfile,opts,bZero,&(sys->symtab),
 +                     plist,comb,reppow,fudgeQQ,
 +                     atype,&nrmols,&molinfo,ir,
 +                     &nmolblock,&molblock,bGB,
 +                     wi);
 +  
 +  sys->nmolblock = 0;
 +  snew(sys->molblock,nmolblock);
 +  
 +  sys->natoms = 0;
 +  for(mb=0; mb<nmolblock; mb++) {
 +    if (sys->nmolblock > 0 &&
 +      molblock[mb].type == sys->molblock[sys->nmolblock-1].type) {
 +      /* Merge consecutive blocks with the same molecule type */
 +      sys->molblock[sys->nmolblock-1].nmol += molblock[mb].nmol;
 +      sys->natoms += molblock[mb].nmol*sys->molblock[sys->nmolblock-1].natoms_mol;
 +    } else if (molblock[mb].nmol > 0) {
 +      /* Add a new molblock to the topology */
 +      molbs = &sys->molblock[sys->nmolblock];
 +      *molbs = molblock[mb];
 +      molbs->natoms_mol = molinfo[molbs->type].atoms.nr;
 +      molbs->nposres_xA = 0;
 +      molbs->nposres_xB = 0;
 +      sys->natoms += molbs->nmol*molbs->natoms_mol;
 +      sys->nmolblock++;
 +    }
 +  }
 +  if (sys->nmolblock == 0) {
 +    gmx_fatal(FARGS,"No molecules were defined in the system");
 +  }
 +
 +  renumber_moltypes(sys,&nrmols,&molinfo);
 +
 +  if (bMorse)
 +    convert_harmonics(nrmols,molinfo,atype);
 +
 +  if (ir->eDisre == edrNone) {
 +    i = rm_interactions(F_DISRES,nrmols,molinfo);
 +    if (i > 0) {
 +      set_warning_line(wi,"unknown",-1);
 +      sprintf(warn_buf,"disre = no, removed %d distance restraints",i);
 +      warning_note(wi,warn_buf);
 +    }
 +  }
 +  if (opts->bOrire == FALSE) {
 +    i = rm_interactions(F_ORIRES,nrmols,molinfo);
 +    if (i > 0) {
 +      set_warning_line(wi,"unknown",-1);
 +      sprintf(warn_buf,"orire = no, removed %d orientation restraints",i);
 +      warning_note(wi,warn_buf);
 +    }
 +  }
 +  
 +  /* Copy structures from msys to sys */
 +  molinfo2mtop(nrmols,molinfo,sys);
 +
 +  gmx_mtop_finalize(sys);
 + 
 +  /* COORDINATE file processing */
 +  if (bVerbose) 
 +    fprintf(stderr,"processing coordinates...\n");
 +
 +  get_stx_coordnum(confin,&state->natoms);
 +  if (state->natoms != sys->natoms)
 +    gmx_fatal(FARGS,"number of coordinates in coordinate file (%s, %d)\n"
 +              "             does not match topology (%s, %d)",
 +            confin,state->natoms,topfile,sys->natoms);
 +  else {
 +    /* make space for coordinates and velocities */
 +    char title[STRLEN];
 +    snew(confat,1);
 +    init_t_atoms(confat,state->natoms,FALSE);
 +    init_state(state,state->natoms,0,0,0,0);
 +    read_stx_conf(confin,title,confat,state->x,state->v,NULL,state->box);
 +    /* This call fixes the box shape for runs with pressure scaling */
 +    set_box_rel(ir,state);
 +
 +    nmismatch = check_atom_names(topfile, confin, sys, confat);
 +    free_t_atoms(confat,TRUE);
 +    sfree(confat);
 +    
 +    if (nmismatch) {
 +      sprintf(buf,"%d non-matching atom name%s\n"
 +            "atom names from %s will be used\n"
 +            "atom names from %s will be ignored\n",
 +            nmismatch,(nmismatch == 1) ? "" : "s",topfile,confin);
 +      warning(wi,buf);
 +    }    
 +    if (bVerbose) 
 +      fprintf(stderr,"double-checking input for internal consistency...\n");
 +    double_check(ir,state->box,nint_ftype(sys,molinfo,F_CONSTR),wi);
 +  }
 +
 +  if (bGenVel) {
 +    real *mass;
 +    gmx_mtop_atomloop_all_t aloop;
 +    t_atom *atom;
 +
 +    snew(mass,state->natoms);
 +    aloop = gmx_mtop_atomloop_all_init(sys);
 +    while (gmx_mtop_atomloop_all_next(aloop,&i,&atom)) {
 +      mass[i] = atom->m;
 +    }
 +
 +    if (opts->seed == -1) {
 +      opts->seed = make_seed();
 +      fprintf(stderr,"Setting gen_seed to %d\n",opts->seed);
 +    }
 +    maxwell_speed(opts->tempi,opts->seed,sys,state->v);
 +
 +    stop_cm(stdout,state->natoms,mass,state->x,state->v);
 +    sfree(mass);
 +  }
 +
 +  *nmi = nrmols;
 +  *mi  = molinfo;
 +}
 +
 +static void copy_state(const char *slog,t_trxframe *fr,
 +                       gmx_bool bReadVel,t_state *state,
 +                       double *use_time)
 +{
 +    int i;
 +
 +    if (fr->not_ok & FRAME_NOT_OK)
 +    {
 +        gmx_fatal(FARGS,"Can not start from an incomplete frame");
 +    }
 +    if (!fr->bX)
 +    {
 +        gmx_fatal(FARGS,"Did not find a frame with coordinates in file %s",
 +                  slog);
 +    }
 +
 +    for(i=0; i<state->natoms; i++)
 +    {
 +        copy_rvec(fr->x[i],state->x[i]);
 +    }
 +    if (bReadVel)
 +    {
 +        if (!fr->bV)
 +        {
 +            gmx_incons("Trajecory frame unexpectedly does not contain velocities");
 +        }
 +        for(i=0; i<state->natoms; i++)
 +        {
 +            copy_rvec(fr->v[i],state->v[i]);
 +        }
 +    }
 +    if (fr->bBox)
 +    {
 +        copy_mat(fr->box,state->box);
 +    }
 +
 +    *use_time = fr->time;
 +}
 +
 +static void cont_status(const char *slog,const char *ener,
 +                      gmx_bool bNeedVel,gmx_bool bGenVel, real fr_time,
 +                      t_inputrec *ir,t_state *state,
 +                      gmx_mtop_t *sys,
 +                        const output_env_t oenv)
 +     /* If fr_time == -1 read the last frame available which is complete */
 +{
 +    gmx_bool bReadVel;
 +    t_trxframe  fr;
 +    t_trxstatus *fp;
 +    int i;
 +    double use_time;
 +
 +    bReadVel = (bNeedVel && !bGenVel);
 +
 +    fprintf(stderr,
 +            "Reading Coordinates%s and Box size from old trajectory\n",
 +            bReadVel ? ", Velocities" : "");
 +    if (fr_time == -1)
 +    {
 +        fprintf(stderr,"Will read whole trajectory\n");
 +    }
 +    else
 +    {
 +        fprintf(stderr,"Will read till time %g\n",fr_time);
 +    }
 +    if (!bReadVel)
 +    {
 +        if (bGenVel)
 +        {
 +            fprintf(stderr,"Velocities generated: "
 +                    "ignoring velocities in input trajectory\n");
 +        }
 +        read_first_frame(oenv,&fp,slog,&fr,TRX_NEED_X);
 +    }
 +    else
 +    {
 +        read_first_frame(oenv,&fp,slog,&fr,TRX_NEED_X | TRX_NEED_V);
 +        
 +        if (!fr.bV)
 +        {
 +            fprintf(stderr,
 +                    "\n"
 +                    "WARNING: Did not find a frame with velocities in file %s,\n"
 +                    "         all velocities will be set to zero!\n\n",slog);
 +            for(i=0; i<sys->natoms; i++)
 +            {
 +                clear_rvec(state->v[i]);
 +            }
 +            close_trj(fp);
 +            /* Search for a frame without velocities */
 +            bReadVel = FALSE;
 +            read_first_frame(oenv,&fp,slog,&fr,TRX_NEED_X);
 +        }
 +    }
 +
 +    state->natoms = fr.natoms;
 +
 +    if (sys->natoms != state->natoms)
 +    {
 +        gmx_fatal(FARGS,"Number of atoms in Topology "
 +                  "is not the same as in Trajectory");
 +    }
 +    copy_state(slog,&fr,bReadVel,state,&use_time);
 +
 +    /* Find the appropriate frame */
 +    while ((fr_time == -1 || fr.time < fr_time) &&
 +           read_next_frame(oenv,fp,&fr))
 +    {
 +        copy_state(slog,&fr,bReadVel,state,&use_time);
 +    }
 +  
 +    close_trj(fp);
 +
 +    /* Set the relative box lengths for preserving the box shape.
 +     * Note that this call can lead to differences in the last bit
 +     * with respect to using tpbconv to create a [TT].tpx[tt] file.
 +     */
 +    set_box_rel(ir,state);
 +
 +    fprintf(stderr,"Using frame at t = %g ps\n",use_time);
 +    fprintf(stderr,"Starting time for run is %g ps\n",ir->init_t); 
 +  
 +    if ((ir->epc != epcNO  || ir->etc ==etcNOSEHOOVER) && ener)
 +    {
 +        get_enx_state(ener,use_time,&sys->groups,ir,state);
 +        preserve_box_shape(ir,state->box_rel,state->boxv);
 +    }
 +}
 +
 +static void read_posres(gmx_mtop_t *mtop,t_molinfo *molinfo,gmx_bool bTopB,
 +                        char *fn,
 +                        int rc_scaling, int ePBC, 
 +                        rvec com,
 +                        warninp_t wi)
 +{
 +  gmx_bool   bFirst = TRUE, *hadAtom;
 +  rvec   *x,*v,*xp;
 +  dvec   sum;
 +  double totmass;
 +  t_atoms dumat;
 +  matrix box,invbox;
 +  int    natoms,npbcdim=0;
 +  char   warn_buf[STRLEN],title[STRLEN];
 +  int    a,i,ai,j,k,mb,nat_molb;
 +  gmx_molblock_t *molb;
 +  t_params *pr,*prfb;
 +  t_atom *atom;
 +
 +  get_stx_coordnum(fn,&natoms);
 +  if (natoms != mtop->natoms) {
 +    sprintf(warn_buf,"The number of atoms in %s (%d) does not match the number of atoms in the topology (%d). Will assume that the first %d atoms in the topology and %s match.",fn,natoms,mtop->natoms,min(mtop->natoms,natoms),fn);
 +    warning(wi,warn_buf);
 +  }
 +  snew(x,natoms);
 +  snew(v,natoms);
 +  init_t_atoms(&dumat,natoms,FALSE);
 +  read_stx_conf(fn,title,&dumat,x,v,NULL,box);
 +  
 +  npbcdim = ePBC2npbcdim(ePBC);
 +  clear_rvec(com);
 +  if (rc_scaling != erscNO) {
 +    copy_mat(box,invbox);
 +    for(j=npbcdim; j<DIM; j++) {
 +      clear_rvec(invbox[j]);
 +      invbox[j][j] = 1;
 +    }
 +    m_inv_ur0(invbox,invbox);
 +  }
 +
 +  /* Copy the reference coordinates to mtop */
 +  clear_dvec(sum);
 +  totmass = 0;
 +  a = 0;
 +  snew(hadAtom,natoms);
 +  for(mb=0; mb<mtop->nmolblock; mb++) {
 +    molb = &mtop->molblock[mb];
 +    nat_molb = molb->nmol*mtop->moltype[molb->type].atoms.nr;
 +    pr = &(molinfo[molb->type].plist[F_POSRES]);
 +    prfb = &(molinfo[molb->type].plist[F_FBPOSRES]);
 +    if (pr->nr > 0 || prfb->nr > 0) {
 +      atom = mtop->moltype[molb->type].atoms.atom;
 +      for(i=0; (i<pr->nr); i++) {
 +      ai=pr->param[i].AI;
 +      if (ai >= natoms) {
 +        gmx_fatal(FARGS,"Position restraint atom index (%d) in moltype '%s' is larger than number of atoms in %s (%d).\n",
 +                  ai+1,*molinfo[molb->type].name,fn,natoms);
 +      }
 +    hadAtom[ai]=TRUE;
 +      if (rc_scaling == erscCOM) {
 +        /* Determine the center of mass of the posres reference coordinates */
 +        for(j=0; j<npbcdim; j++) {
 +          sum[j] += atom[ai].m*x[a+ai][j];
 +        }
 +        totmass  += atom[ai].m;
 +      }
 +      }
 +      /* Same for flat-bottomed posres, but do not count an atom twice for COM */
 +      for(i=0; (i<prfb->nr); i++) {
 +          ai=prfb->param[i].AI;
 +          if (ai >= natoms) {
 +              gmx_fatal(FARGS,"Position restraint atom index (%d) in moltype '%s' is larger than number of atoms in %s (%d).\n",
 +                        ai+1,*molinfo[molb->type].name,fn,natoms);
 +          }
 +          if (rc_scaling == erscCOM && hadAtom[ai] == FALSE) {
 +              /* Determine the center of mass of the posres reference coordinates */
 +              for(j=0; j<npbcdim; j++) {
 +                  sum[j] += atom[ai].m*x[a+ai][j];
 +              }
 +              totmass  += atom[ai].m;
 +          }
 +      }
 +      if (!bTopB) {
 +      molb->nposres_xA = nat_molb;
 +      snew(molb->posres_xA,molb->nposres_xA);
 +      for(i=0; i<nat_molb; i++) {
 +        copy_rvec(x[a+i],molb->posres_xA[i]);
 +      }
 +      } else {
 +      molb->nposres_xB = nat_molb;
 +      snew(molb->posres_xB,molb->nposres_xB);
 +      for(i=0; i<nat_molb; i++) {
 +        copy_rvec(x[a+i],molb->posres_xB[i]);
 +      }
 +      }
 +    }
 +    a += nat_molb;
 +  }
 +  if (rc_scaling == erscCOM) {
 +    if (totmass == 0)
 +      gmx_fatal(FARGS,"The total mass of the position restraint atoms is 0");
 +    for(j=0; j<npbcdim; j++)
 +      com[j] = sum[j]/totmass;
 +    fprintf(stderr,"The center of mass of the position restraint coord's is %6.3f %6.3f %6.3f\n",com[XX],com[YY],com[ZZ]);
 +  }
 +
 +  if (rc_scaling != erscNO) {
 +    for(mb=0; mb<mtop->nmolblock; mb++) {
 +      molb = &mtop->molblock[mb];
 +      nat_molb = molb->nmol*mtop->moltype[molb->type].atoms.nr;
 +      if (molb->nposres_xA > 0 || molb->nposres_xB > 0) {
 +      xp = (!bTopB ? molb->posres_xA : molb->posres_xB);
 +      for(i=0; i<nat_molb; i++) {
 +        for(j=0; j<npbcdim; j++) {
 +          if (rc_scaling == erscALL) {
 +            /* Convert from Cartesian to crystal coordinates */
 +            xp[i][j] *= invbox[j][j];
 +            for(k=j+1; k<npbcdim; k++) {
 +              xp[i][j] += invbox[k][j]*xp[i][k];
 +            }
 +          } else if (rc_scaling == erscCOM) {
 +            /* Subtract the center of mass */
 +            xp[i][j] -= com[j];
 +          }
 +        }
 +      }
 +      }
 +    }
 +
 +    if (rc_scaling == erscCOM) {
 +      /* Convert the COM from Cartesian to crystal coordinates */
 +      for(j=0; j<npbcdim; j++) {
 +      com[j] *= invbox[j][j];
 +      for(k=j+1; k<npbcdim; k++) {
 +        com[j] += invbox[k][j]*com[k];
 +      }
 +      }
 +    }
 +  }
 +  
 +  free_t_atoms(&dumat,TRUE);
 +  sfree(x);
 +  sfree(v);
 +  sfree(hadAtom);
 +}
 +
 +static void gen_posres(gmx_mtop_t *mtop,t_molinfo *mi,
 +                       char *fnA, char *fnB,
 +                       int rc_scaling, int ePBC,
 +                       rvec com, rvec comB,
 +                       warninp_t wi)
 +{
 +  int i,j;
 +
 +  read_posres  (mtop,mi,FALSE,fnA,rc_scaling,ePBC,com,wi);
 +  if (strcmp(fnA,fnB) != 0) {
 +      read_posres(mtop,mi,TRUE ,fnB,rc_scaling,ePBC,comB,wi);
 +  }
 +}
 +
 +static void set_wall_atomtype(gpp_atomtype_t at,t_gromppopts *opts,
 +                              t_inputrec *ir,warninp_t wi)
 +{
 +  int i;
 +  char warn_buf[STRLEN];
 +
 +  if (ir->nwall > 0)
 +  {
 +      fprintf(stderr,"Searching the wall atom type(s)\n");
 +  }
 +  for(i=0; i<ir->nwall; i++)
 +  {
 +      ir->wall_atomtype[i] = get_atomtype_type(opts->wall_atomtype[i],at);
 +      if (ir->wall_atomtype[i] == NOTSET)
 +      {
 +          sprintf(warn_buf,"Specified wall atom type %s is not defined",opts->wall_atomtype[i]);
 +          warning_error(wi,warn_buf);
 +      }
 +  }
 +}
 +
 +static int nrdf_internal(t_atoms *atoms)
 +{
 +  int i,nmass,nrdf;
 +
 +  nmass = 0;
 +  for(i=0; i<atoms->nr; i++) {
 +    /* Vsite ptype might not be set here yet, so also check the mass */
 +    if ((atoms->atom[i].ptype == eptAtom ||
 +       atoms->atom[i].ptype == eptNucleus)
 +      && atoms->atom[i].m > 0) {
 +      nmass++;
 +    }
 +  }
 +  switch (nmass) {
 +  case 0:  nrdf = 0; break;
 +  case 1:  nrdf = 0; break;
 +  case 2:  nrdf = 1; break;
 +  default: nrdf = nmass*3 - 6; break;
 +  }
 +  
 +  return nrdf;
 +}
 +
 +void
 +spline1d( double        dx,
 +               double *      y,
 +               int           n,
 +               double *      u,
 +               double *      y2 )
 +{
 +    int i;
 +    double p,q;
 +      
 +    y2[0] = 0.0;
 +    u[0]  = 0.0;
 +      
 +    for(i=1;i<n-1;i++)
 +    {
 +              p = 0.5*y2[i-1]+2.0;
 +        y2[i] = -0.5/p;
 +        q = (y[i+1]-2.0*y[i]+y[i-1])/dx;
 +              u[i] = (3.0*q/dx-0.5*u[i-1])/p;
 +    }
 +      
 +    y2[n-1] = 0.0;
 +      
 +    for(i=n-2;i>=0;i--)
 +    {
 +        y2[i] = y2[i]*y2[i+1]+u[i];
 +    }
 +}
 +
 +
 +void
 +interpolate1d( double     xmin,
 +                        double     dx,
 +                        double *   ya,
 +                        double *   y2a,
 +                        double     x,
 +                        double *   y,
 +                        double *   y1)
 +{
 +    int ix;
 +    double a,b;
 +      
 +    ix = (x-xmin)/dx;
 +      
 +    a = (xmin+(ix+1)*dx-x)/dx;
 +    b = (x-xmin-ix*dx)/dx;
 +      
 +    *y  = a*ya[ix]+b*ya[ix+1]+((a*a*a-a)*y2a[ix]+(b*b*b-b)*y2a[ix+1])*(dx*dx)/6.0;
 +    *y1 = (ya[ix+1]-ya[ix])/dx-(3.0*a*a-1.0)/6.0*dx*y2a[ix]+(3.0*b*b-1.0)/6.0*dx*y2a[ix+1];
 +}
 +
 +
 +void
 +setup_cmap (int              grid_spacing,
 +                      int              nc,
 +                      real *           grid ,
 +                      gmx_cmap_t *     cmap_grid)
 +{
 +      double *tmp_u,*tmp_u2,*tmp_yy,*tmp_y1,*tmp_t2,*tmp_grid;
 +      
 +    int    i,j,k,ii,jj,kk,idx;
 +      int    offset;
 +    double dx,xmin,v,v1,v2,v12;
 +    double phi,psi;
 +      
 +      snew(tmp_u,2*grid_spacing);
 +      snew(tmp_u2,2*grid_spacing);
 +      snew(tmp_yy,2*grid_spacing);
 +      snew(tmp_y1,2*grid_spacing);
 +      snew(tmp_t2,2*grid_spacing*2*grid_spacing);
 +      snew(tmp_grid,2*grid_spacing*2*grid_spacing);
 +      
 +    dx = 360.0/grid_spacing;
 +    xmin = -180.0-dx*grid_spacing/2;
 +      
 +      for(kk=0;kk<nc;kk++)
 +      {
 +              /* Compute an offset depending on which cmap we are using 
 +               * Offset will be the map number multiplied with the 
 +                 * grid_spacing * grid_spacing * 2
 +               */
 +              offset = kk * grid_spacing * grid_spacing * 2;
 +              
 +              for(i=0;i<2*grid_spacing;i++)
 +              {
 +                      ii=(i+grid_spacing-grid_spacing/2)%grid_spacing;
 +                      
 +                      for(j=0;j<2*grid_spacing;j++)
 +                      {
 +                              jj=(j+grid_spacing-grid_spacing/2)%grid_spacing;
 +                              tmp_grid[i*grid_spacing*2+j] = grid[offset+ii*grid_spacing+jj];
 +                      }
 +              }
 +              
 +              for(i=0;i<2*grid_spacing;i++)
 +              {
 +                      spline1d(dx,&(tmp_grid[2*grid_spacing*i]),2*grid_spacing,tmp_u,&(tmp_t2[2*grid_spacing*i]));
 +              }
 +              
 +              for(i=grid_spacing/2;i<grid_spacing+grid_spacing/2;i++)
 +              {
 +                      ii = i-grid_spacing/2;
 +                      phi = ii*dx-180.0;
 +                      
 +                      for(j=grid_spacing/2;j<grid_spacing+grid_spacing/2;j++)
 +                      {
 +                              jj = j-grid_spacing/2;
 +                              psi = jj*dx-180.0;
 +                              
 +                              for(k=0;k<2*grid_spacing;k++)
 +                              {
 +                                      interpolate1d(xmin,dx,&(tmp_grid[2*grid_spacing*k]),
 +                                                                &(tmp_t2[2*grid_spacing*k]),psi,&tmp_yy[k],&tmp_y1[k]);
 +                              }
 +                              
 +                              spline1d(dx,tmp_yy,2*grid_spacing,tmp_u,tmp_u2);
 +                              interpolate1d(xmin,dx,tmp_yy,tmp_u2,phi,&v,&v1);
 +                              spline1d(dx,tmp_y1,2*grid_spacing,tmp_u,tmp_u2);
 +                              interpolate1d(xmin,dx,tmp_y1,tmp_u2,phi,&v2,&v12);
 +                              
 +                              idx = ii*grid_spacing+jj;
 +                              cmap_grid->cmapdata[kk].cmap[idx*4] = grid[offset+ii*grid_spacing+jj];
 +                              cmap_grid->cmapdata[kk].cmap[idx*4+1] = v1;
 +                              cmap_grid->cmapdata[kk].cmap[idx*4+2] = v2;
 +                              cmap_grid->cmapdata[kk].cmap[idx*4+3] = v12;
 +                      }
 +              }
 +      }
 +}                             
 +                              
 +void init_cmap_grid(gmx_cmap_t *cmap_grid, int ngrid, int grid_spacing)
 +{
 +      int i,k,nelem;
 +      
 +      cmap_grid->ngrid        = ngrid;
 +      cmap_grid->grid_spacing = grid_spacing;
 +      nelem                   = cmap_grid->grid_spacing*cmap_grid->grid_spacing;
 +      
 +      snew(cmap_grid->cmapdata,ngrid);
 +      
 +      for(i=0;i<cmap_grid->ngrid;i++)
 +      {
 +              snew(cmap_grid->cmapdata[i].cmap,4*nelem);
 +      }
 +}
 +
 +
 +static int count_constraints(gmx_mtop_t *mtop,t_molinfo *mi,warninp_t wi)
 +{
 +  int count,count_mol,i,mb;
 +  gmx_molblock_t *molb;
 +  t_params *plist;
 +  char buf[STRLEN];
 +
 +  count = 0;
 +  for(mb=0; mb<mtop->nmolblock; mb++) {
 +    count_mol = 0;
 +    molb  = &mtop->molblock[mb];
 +    plist = mi[molb->type].plist;
 +      
 +    for(i=0; i<F_NRE; i++) {
 +      if (i == F_SETTLE)
 +      count_mol += 3*plist[i].nr;
 +      else if (interaction_function[i].flags & IF_CONSTRAINT)
 +      count_mol += plist[i].nr;
 +    }
 +      
 +    if (count_mol > nrdf_internal(&mi[molb->type].atoms)) {
 +      sprintf(buf,
 +            "Molecule type '%s' has %d constraints.\n"
 +            "For stability and efficiency there should not be more constraints than internal number of degrees of freedom: %d.\n",
 +            *mi[molb->type].name,count_mol,
 +            nrdf_internal(&mi[molb->type].atoms));
 +      warning(wi,buf);
 +    }
 +    count += molb->nmol*count_mol;
 +  }
 +
 +  return count;
 +}
 +
 +static void check_gbsa_params_charged(gmx_mtop_t *sys, gpp_atomtype_t atype)
 +{
 +    int i,nmiss,natoms,mt;
 +    real q;
 +    const t_atoms *atoms;
 +  
 +    nmiss = 0;
 +    for(mt=0;mt<sys->nmoltype;mt++)
 +    {
 +        atoms  = &sys->moltype[mt].atoms;
 +        natoms = atoms->nr;
 +
 +        for(i=0;i<natoms;i++)
 +        {
 +            q = atoms->atom[i].q;
 +            if ((get_atomtype_radius(atoms->atom[i].type,atype)    == 0  ||
 +                 get_atomtype_vol(atoms->atom[i].type,atype)       == 0  ||
 +                 get_atomtype_surftens(atoms->atom[i].type,atype)  == 0  ||
 +                 get_atomtype_gb_radius(atoms->atom[i].type,atype) == 0  ||
 +                 get_atomtype_S_hct(atoms->atom[i].type,atype)     == 0) &&
 +                q != 0)
 +            {
 +                fprintf(stderr,"\nGB parameter(s) zero for atom type '%s' while charge is %g\n",
 +                        get_atomtype_name(atoms->atom[i].type,atype),q);
 +                nmiss++;
 +            }
 +        }
 +    }
 +
 +    if (nmiss > 0)
 +    {
 +        gmx_fatal(FARGS,"Can't do GB electrostatics; the implicit_genborn_params section of the forcefield has parameters with value zero for %d atomtypes that occur as charged atoms.",nmiss);
 +    }
 +}
 +
 +
 +static void check_gbsa_params(t_inputrec *ir,gpp_atomtype_t atype)
 +{
 +    int  nmiss,i;
 +
 +    /* If we are doing GBSA, check that we got the parameters we need
 +     * This checking is to see if there are GBSA paratmeters for all
 +     * atoms in the force field. To go around this for testing purposes
 +     * comment out the nerror++ counter temporarily
 +     */
 +    nmiss = 0;
 +    for(i=0;i<get_atomtype_ntypes(atype);i++)
 +    {
 +        if (get_atomtype_radius(i,atype)    < 0 ||
 +            get_atomtype_vol(i,atype)       < 0 ||
 +            get_atomtype_surftens(i,atype)  < 0 ||
 +            get_atomtype_gb_radius(i,atype) < 0 ||
 +            get_atomtype_S_hct(i,atype)     < 0)
 +        {
 +            fprintf(stderr,"\nGB parameter(s) missing or negative for atom type '%s'\n",
 +                    get_atomtype_name(i,atype));
 +            nmiss++;
 +        }
 +    }
 +    
 +    if (nmiss > 0)
 +    {
 +        gmx_fatal(FARGS,"Can't do GB electrostatics; the implicit_genborn_params section of the forcefield is missing parameters for %d atomtypes or they might be negative.",nmiss);
 +    }
 +  
 +}
 +
 +static void set_verlet_buffer(const gmx_mtop_t *mtop,
 +                              t_inputrec *ir,
 +                              matrix box,
 +                              real verletbuf_drift,
 +                              warninp_t wi)
 +{
 +    real ref_T;
 +    int i;
 +    verletbuf_list_setup_t ls;
 +    real rlist_1x1;
 +    int n_nonlin_vsite;
 +    char warn_buf[STRLEN];
 +
 +    ref_T = 0;
 +    for(i=0; i<ir->opts.ngtc; i++)
 +    {
 +        if (ir->opts.ref_t[i] < 0)
 +        {
 +            warning(wi,"Some atom groups do not use temperature coupling. This cannot be accounted for in the energy drift estimation for the Verlet buffer size. The energy drift and the Verlet buffer might be underestimated.");
 +        }
 +        else
 +        {
 +            ref_T = max(ref_T,ir->opts.ref_t[i]);
 +        }
 +    }
 +
 +    printf("Determining Verlet buffer for an energy drift of %g kJ/mol/ps at %g K\n",verletbuf_drift,ref_T);
 +
 +    for(i=0; i<ir->opts.ngtc; i++)
 +    {
 +        if (ir->opts.ref_t[i] >= 0 && ir->opts.ref_t[i] != ref_T)
 +        {
 +            sprintf(warn_buf,"ref_T for group of %.1f DOFs is %g K, which is smaller than the maximum of %g K used for the buffer size calculation. The buffer size might be on the conservative (large) side.",
 +                    ir->opts.nrdf[i],ir->opts.ref_t[i],ref_T);
 +            warning_note(wi,warn_buf);
 +        }
 +    }
 +
 +    /* Calculate the buffer size for simple atom vs atoms list */
 +    ls.cluster_size_i = 1;
 +    ls.cluster_size_j = 1;
 +    calc_verlet_buffer_size(mtop,det(box),ir,verletbuf_drift,
 +                            &ls,&n_nonlin_vsite,&rlist_1x1);
 +
 +    /* Set the pair-list buffer size in ir */
 +    verletbuf_get_list_setup(FALSE,&ls);
 +    calc_verlet_buffer_size(mtop,det(box),ir,verletbuf_drift,
 +                            &ls,&n_nonlin_vsite,&ir->rlist);
 +
 +    if (n_nonlin_vsite > 0)
 +    {
 +        sprintf(warn_buf,"There are %d non-linear virtual site constructions. Their contribution to the energy drift is approximated. In most cases this does not affect the energy drift significantly.",n_nonlin_vsite);
 +        warning_note(wi,warn_buf);
 +    }
 +
 +    printf("Calculated rlist for %dx%d atom pair-list as %.3f nm, buffer size %.3f nm\n",
 +           1,1,rlist_1x1,rlist_1x1-max(ir->rvdw,ir->rcoulomb));
 +
 +    ir->rlistlong = ir->rlist;
 +    printf("Set rlist, assuming %dx%d atom pair-list, to %.3f nm, buffer size %.3f nm\n",
 +           ls.cluster_size_i,ls.cluster_size_j,
 +           ir->rlist,ir->rlist-max(ir->rvdw,ir->rcoulomb));
 +            
 +    if (sqr(ir->rlistlong) >= max_cutoff2(ir->ePBC,box))
 +    {
 +        gmx_fatal(FARGS,"The pair-list cut-off (%g nm) is longer than half the shortest box vector or longer than the smallest box diagonal element (%g nm). Increase the box size or decrease nstlist or increase verlet-buffer-drift.",ir->rlistlong,sqrt(max_cutoff2(ir->ePBC,box)));
 +    }
 +}
 +
++int cmain (int argc, char *argv[])
 +{
 +  static const char *desc[] = {
 +    "The gromacs preprocessor",
 +    "reads a molecular topology file, checks the validity of the",
 +    "file, expands the topology from a molecular description to an atomic",
 +    "description. The topology file contains information about",
 +    "molecule types and the number of molecules, the preprocessor",
 +    "copies each molecule as needed. ",
 +    "There is no limitation on the number of molecule types. ",
 +    "Bonds and bond-angles can be converted into constraints, separately",
 +    "for hydrogens and heavy atoms.",
 +    "Then a coordinate file is read and velocities can be generated",
 +    "from a Maxwellian distribution if requested.",
 +    "[TT]grompp[tt] also reads parameters for the [TT]mdrun[tt] ",
 +    "(eg. number of MD steps, time step, cut-off), and others such as",
 +    "NEMD parameters, which are corrected so that the net acceleration",
 +    "is zero.",
 +    "Eventually a binary file is produced that can serve as the sole input",
 +    "file for the MD program.[PAR]",
 +    
 +    "[TT]grompp[tt] uses the atom names from the topology file. The atom names",
 +    "in the coordinate file (option [TT]-c[tt]) are only read to generate",
 +    "warnings when they do not match the atom names in the topology.",
 +    "Note that the atom names are irrelevant for the simulation as",
 +    "only the atom types are used for generating interaction parameters.[PAR]",
 +
 +    "[TT]grompp[tt] uses a built-in preprocessor to resolve includes, macros, ",
 +    "etc. The preprocessor supports the following keywords:[PAR]",
 +    "#ifdef VARIABLE[BR]",
 +    "#ifndef VARIABLE[BR]",
 +    "#else[BR]",
 +    "#endif[BR]",
 +    "#define VARIABLE[BR]",
 +    "#undef VARIABLE[BR]"
 +    "#include \"filename\"[BR]",
 +    "#include <filename>[PAR]",
 +    "The functioning of these statements in your topology may be modulated by",
 +    "using the following two flags in your [TT].mdp[tt] file:[PAR]",
 +    "[TT]define = -DVARIABLE1 -DVARIABLE2[BR]",
 +    "include = -I/home/john/doe[tt][BR]",
 +    "For further information a C-programming textbook may help you out.",
 +    "Specifying the [TT]-pp[tt] flag will get the pre-processed",
 +    "topology file written out so that you can verify its contents.[PAR]",
 +   
 +    /* cpp has been unnecessary for some time, hasn't it?
 +        "If your system does not have a C-preprocessor, you can still",
 +        "use [TT]grompp[tt], but you do not have access to the features ",
 +        "from the cpp. Command line options to the C-preprocessor can be given",
 +        "in the [TT].mdp[tt] file. See your local manual (man cpp).[PAR]",
 +    */
 +    
 +    "When using position restraints a file with restraint coordinates",
 +    "can be supplied with [TT]-r[tt], otherwise restraining will be done",
 +    "with respect to the conformation from the [TT]-c[tt] option.",
 +    "For free energy calculation the the coordinates for the B topology",
 +    "can be supplied with [TT]-rb[tt], otherwise they will be equal to",
 +    "those of the A topology.[PAR]",
 +    
 +    "Starting coordinates can be read from trajectory with [TT]-t[tt].",
 +    "The last frame with coordinates and velocities will be read,",
 +    "unless the [TT]-time[tt] option is used. Only if this information",
 +    "is absent will the coordinates in the [TT]-c[tt] file be used.",
 +    "Note that these velocities will not be used when [TT]gen_vel = yes[tt]",
 +    "in your [TT].mdp[tt] file. An energy file can be supplied with",
 +    "[TT]-e[tt] to read Nose-Hoover and/or Parrinello-Rahman coupling",
 +    "variables.[PAR]",
 +
 +    "[TT]grompp[tt] can be used to restart simulations (preserving",
 +    "continuity) by supplying just a checkpoint file with [TT]-t[tt].",
 +    "However, for simply changing the number of run steps to extend",
 +    "a run, using [TT]tpbconv[tt] is more convenient than [TT]grompp[tt].",
 +    "You then supply the old checkpoint file directly to [TT]mdrun[tt]",
 +    "with [TT]-cpi[tt]. If you wish to change the ensemble or things",
 +    "like output frequency, then supplying the checkpoint file to",
 +    "[TT]grompp[tt] with [TT]-t[tt] along with a new [TT].mdp[tt] file",
 +    "with [TT]-f[tt] is the recommended procedure.[PAR]",
 +
 +    "By default, all bonded interactions which have constant energy due to",
 +    "virtual site constructions will be removed. If this constant energy is",
 +    "not zero, this will result in a shift in the total energy. All bonded",
 +    "interactions can be kept by turning off [TT]-rmvsbds[tt]. Additionally,",
 +    "all constraints for distances which will be constant anyway because",
 +    "of virtual site constructions will be removed. If any constraints remain",
 +    "which involve virtual sites, a fatal error will result.[PAR]"
 +    
 +    "To verify your run input file, please take note of all warnings",
 +    "on the screen, and correct where necessary. Do also look at the contents",
 +    "of the [TT]mdout.mdp[tt] file; this contains comment lines, as well as",
 +    "the input that [TT]grompp[tt] has read. If in doubt, you can start [TT]grompp[tt]",
 +    "with the [TT]-debug[tt] option which will give you more information",
 +    "in a file called [TT]grompp.log[tt] (along with real debug info). You",
 +    "can see the contents of the run input file with the [TT]gmxdump[tt]",
 +    "program. [TT]gmxcheck[tt] can be used to compare the contents of two",
 +    "run input files.[PAR]"
 +
 +    "The [TT]-maxwarn[tt] option can be used to override warnings printed",
 +    "by [TT]grompp[tt] that otherwise halt output. In some cases, warnings are",
 +    "harmless, but usually they are not. The user is advised to carefully",
 +    "interpret the output messages before attempting to bypass them with",
 +    "this option."
 +  };
 +  t_gromppopts *opts;
 +  gmx_mtop_t   *sys;
 +  int          nmi;
 +  t_molinfo    *mi;
 +  gpp_atomtype_t atype;
 +  t_inputrec   *ir;
 +  int          natoms,nvsite,comb,mt;
 +  t_params     *plist;
 +  t_state      state;
 +  matrix       box;
 +  real         max_spacing,fudgeQQ;
 +  double       reppow;
 +  char         fn[STRLEN],fnB[STRLEN];
 +  const char   *mdparin;
 +  int          ntype;
 +  gmx_bool         bNeedVel,bGenVel;
 +  gmx_bool         have_atomnumber;
 +  int            n12,n13,n14;
 +  t_params     *gb_plist = NULL;
 +  gmx_genborn_t *born = NULL;
 +  output_env_t oenv;
 +  gmx_bool         bVerbose = FALSE;
 +  warninp_t    wi;
 +  char         warn_buf[STRLEN];
 +
 +  t_filenm fnm[] = {
 +    { efMDP, NULL,  NULL,        ffREAD  },
 +    { efMDP, "-po", "mdout",     ffWRITE },
 +    { efSTX, "-c",  NULL,        ffREAD  },
 +    { efSTX, "-r",  NULL,        ffOPTRD },
 +    { efSTX, "-rb", NULL,        ffOPTRD },
 +    { efNDX, NULL,  NULL,        ffOPTRD },
 +    { efTOP, NULL,  NULL,        ffREAD  },
 +    { efTOP, "-pp", "processed", ffOPTWR },
 +    { efTPX, "-o",  NULL,        ffWRITE },
 +    { efTRN, "-t",  NULL,        ffOPTRD },
 +    { efEDR, "-e",  NULL,        ffOPTRD },
 +    { efTRN, "-ref","rotref",    ffOPTRW }
 +  };
 +#define NFILE asize(fnm)
 +
 +  /* Command line options */
 +  static gmx_bool bRenum=TRUE;
 +  static gmx_bool bRmVSBds=TRUE,bZero=FALSE;
 +  static int  i,maxwarn=0;
 +  static real fr_time=-1;
 +  t_pargs pa[] = {
 +    { "-v",       FALSE, etBOOL,{&bVerbose},  
 +      "Be loud and noisy" },
 +    { "-time",    FALSE, etREAL, {&fr_time},
 +      "Take frame at or first after this time." },
 +    { "-rmvsbds",FALSE, etBOOL, {&bRmVSBds},
 +      "Remove constant bonded interactions with virtual sites" },
 +    { "-maxwarn", FALSE, etINT,  {&maxwarn},
 +      "Number of allowed warnings during input processing. Not for normal use and may generate unstable systems" },
 +    { "-zero",    FALSE, etBOOL, {&bZero},
 +      "Set parameters for bonded interactions without defaults to zero instead of generating an error" },
 +    { "-renum",   FALSE, etBOOL, {&bRenum},
 +      "Renumber atomtypes and minimize number of atomtypes" }
 +  };
 +  
 +  CopyRight(stderr,argv[0]);
 +  
 +  /* Initiate some variables */
 +  snew(ir,1);
 +  snew(opts,1);
 +  init_ir(ir,opts);
 +  
 +  /* Parse the command line */
 +  parse_common_args(&argc,argv,0,NFILE,fnm,asize(pa),pa,
 +                    asize(desc),desc,0,NULL,&oenv);
 +  
 +  wi = init_warning(TRUE,maxwarn);
 +  
 +  /* PARAMETER file processing */
 +  mdparin = opt2fn("-f",NFILE,fnm);
 +  set_warning_line(wi,mdparin,-1);    
 +  get_ir(mdparin,opt2fn("-po",NFILE,fnm),ir,opts,wi);
 +  
 +  if (bVerbose) 
 +    fprintf(stderr,"checking input for internal consistency...\n");
 +  check_ir(mdparin,ir,opts,wi);
 +
 +  if (ir->ld_seed == -1) {
 +    ir->ld_seed = make_seed();
 +    fprintf(stderr,"Setting the LD random seed to %d\n",ir->ld_seed);
 +  }
 +
 +  if (ir->expandedvals->lmc_seed == -1) {
 +    ir->expandedvals->lmc_seed = make_seed();
 +    fprintf(stderr,"Setting the lambda MC random seed to %d\n",ir->expandedvals->lmc_seed);
 +  }
 +
 +  bNeedVel = EI_STATE_VELOCITY(ir->eI);
 +  bGenVel  = (bNeedVel && opts->bGenVel);
 +  if (bGenVel && ir->bContinuation)
 +  {
 +      sprintf(warn_buf,
 +              "Generating velocities is inconsistent with attempting "
 +              "to continue a previous run. Choose only one of "
 +              "gen-vel = yes and continuation = yes.");
 +      warning_error(wi, warn_buf);
 +  }
 +
 +  snew(plist,F_NRE);
 +  init_plist(plist);
 +  snew(sys,1);
 +  atype = init_atomtype();
 +  if (debug)
 +    pr_symtab(debug,0,"Just opened",&sys->symtab);
 +    
 +  strcpy(fn,ftp2fn(efTOP,NFILE,fnm));
 +  if (!gmx_fexist(fn)) 
 +    gmx_fatal(FARGS,"%s does not exist",fn);
 +  new_status(fn,opt2fn_null("-pp",NFILE,fnm),opt2fn("-c",NFILE,fnm),
 +           opts,ir,bZero,bGenVel,bVerbose,&state,
 +           atype,sys,&nmi,&mi,plist,&comb,&reppow,&fudgeQQ,
 +           opts->bMorse,
 +           wi);
 +  
 +  if (debug)
 +    pr_symtab(debug,0,"After new_status",&sys->symtab);
 +
 +    if (ir->cutoff_scheme == ecutsVERLET)
 +    {
 +        fprintf(stderr,"Removing all charge groups because cutoff-scheme=%s\n",
 +                ecutscheme_names[ir->cutoff_scheme]);
 +
 +        /* Remove all charge groups */
 +        gmx_mtop_remove_chargegroups(sys);
 +    }
 +  
 +  if (count_constraints(sys,mi,wi) && (ir->eConstrAlg == econtSHAKE)) {
 +    if (ir->eI == eiCG || ir->eI == eiLBFGS) {
 +        sprintf(warn_buf,"Can not do %s with %s, use %s",
 +                EI(ir->eI),econstr_names[econtSHAKE],econstr_names[econtLINCS]);
 +        warning_error(wi,warn_buf);
 +    }
 +    if (ir->bPeriodicMols) {
 +        sprintf(warn_buf,"Can not do periodic molecules with %s, use %s",
 +                econstr_names[econtSHAKE],econstr_names[econtLINCS]);
 +        warning_error(wi,warn_buf);
 +    }
 +  }
 +
 +  if ( EI_SD (ir->eI) &&  ir->etc != etcNO ) {
 +      warning_note(wi,"Temperature coupling is ignored with SD integrators.");
 +  }
 +
 +  /* If we are doing QM/MM, check that we got the atom numbers */
 +  have_atomnumber = TRUE;
 +  for (i=0; i<get_atomtype_ntypes(atype); i++) {
 +    have_atomnumber = have_atomnumber && (get_atomtype_atomnumber(i,atype) >= 0);
 +  }
 +  if (!have_atomnumber && ir->bQMMM)
 +  {
 +      warning_error(wi,
 +                    "\n"
 +                    "It appears as if you are trying to run a QM/MM calculation, but the force\n"
 +                    "field you are using does not contain atom numbers fields. This is an\n"
 +                    "optional field (introduced in Gromacs 3.3) for general runs, but mandatory\n"
 +                    "for QM/MM. The good news is that it is easy to add - put the atom number as\n"
 +                    "an integer just before the mass column in ffXXXnb.itp.\n"
 +                    "NB: United atoms have the same atom numbers as normal ones.\n\n"); 
 +  }
 +
 +  if (ir->bAdress) {
 +    if ((ir->adress->const_wf>1) || (ir->adress->const_wf<0)) {
 +      warning_error(wi,"AdResS contant weighting function should be between 0 and 1\n\n");
 +    }
 +    /** \TODO check size of ex+hy width against box size */
 +  }
 + 
 +  /* Check for errors in the input now, since they might cause problems
 +   * during processing further down.
 +   */
 +  check_warning_error(wi,FARGS);
 +
 +  if (opt2bSet("-r",NFILE,fnm))
 +    sprintf(fn,"%s",opt2fn("-r",NFILE,fnm));
 +  else
 +    sprintf(fn,"%s",opt2fn("-c",NFILE,fnm));
 +  if (opt2bSet("-rb",NFILE,fnm))
 +    sprintf(fnB,"%s",opt2fn("-rb",NFILE,fnm));
 +  else
 +    strcpy(fnB,fn);
 +
 +    if (nint_ftype(sys,mi,F_POSRES) > 0 || nint_ftype(sys,mi,F_FBPOSRES) > 0)
 +    {
 +        if (bVerbose)
 +        {
 +            fprintf(stderr,"Reading position restraint coords from %s",fn);
 +            if (strcmp(fn,fnB) == 0)
 +            {
 +                fprintf(stderr,"\n");
 +            }
 +            else
 +            {
 +                fprintf(stderr," and %s\n",fnB);
 +            }
 +        }
 +        gen_posres(sys,mi,fn,fnB,
 +                   ir->refcoord_scaling,ir->ePBC,
 +                   ir->posres_com,ir->posres_comB,
 +                   wi);
 +    }
 +              
 +  nvsite = 0;
 +  /* set parameters for virtual site construction (not for vsiten) */
 +  for(mt=0; mt<sys->nmoltype; mt++) {
 +    nvsite +=
 +      set_vsites(bVerbose, &sys->moltype[mt].atoms, atype, mi[mt].plist);
 +  }
 +  /* now throw away all obsolete bonds, angles and dihedrals: */
 +  /* note: constraints are ALWAYS removed */
 +  if (nvsite) {
 +    for(mt=0; mt<sys->nmoltype; mt++) {
 +      clean_vsite_bondeds(mi[mt].plist,sys->moltype[mt].atoms.nr,bRmVSBds);
 +    }
 +  }
 +  
 +      /* If we are using CMAP, setup the pre-interpolation grid */
 +      if(plist->ncmap>0)
 +      {
 +              init_cmap_grid(&sys->ffparams.cmap_grid, plist->nc, plist->grid_spacing);
 +              setup_cmap(plist->grid_spacing, plist->nc, plist->cmap,&sys->ffparams.cmap_grid);
 +      }
 +      
 +    set_wall_atomtype(atype,opts,ir,wi);
 +  if (bRenum) {
 +    renum_atype(plist, sys, ir->wall_atomtype, atype, bVerbose);
 +    ntype = get_atomtype_ntypes(atype);
 +  }
 +
 +    if (ir->implicit_solvent != eisNO)
 +    {
 +        /* Now we have renumbered the atom types, we can check the GBSA params */
 +        check_gbsa_params(ir,atype);
 +      
 +      /* Check that all atoms that have charge and/or LJ-parameters also have 
 +       * sensible GB-parameters
 +       */
 +      check_gbsa_params_charged(sys,atype);
 +    }
 +
 +      /* PELA: Copy the atomtype data to the topology atomtype list */
 +      copy_atomtype_atomtypes(atype,&(sys->atomtypes));
 +
 +      if (debug)
 +    pr_symtab(debug,0,"After renum_atype",&sys->symtab);
 +
 +  if (bVerbose) 
 +    fprintf(stderr,"converting bonded parameters...\n");
 +      
 +  ntype = get_atomtype_ntypes(atype);
 +  convert_params(ntype, plist, mi, comb, reppow, fudgeQQ, sys);
 +      
 +  if (debug)
 +    pr_symtab(debug,0,"After convert_params",&sys->symtab);
 +
 +  /* set ptype to VSite for virtual sites */
 +  for(mt=0; mt<sys->nmoltype; mt++) {
 +    set_vsites_ptype(FALSE,&sys->moltype[mt]);
 +  }
 +  if (debug) {
 +    pr_symtab(debug,0,"After virtual sites",&sys->symtab);
 +  }
 +  /* Check velocity for virtual sites and shells */
 +  if (bGenVel) {
 +    check_vel(sys,state.v);
 +  }
 +    
 +  /* check masses */
 +  check_mol(sys,wi);
 +  
 +  for(i=0; i<sys->nmoltype; i++) {
 +      check_cg_sizes(ftp2fn(efTOP,NFILE,fnm),&sys->moltype[i].cgs,wi);
 +  }
 +
 +  if (EI_DYNAMICS(ir->eI) && ir->eI != eiBD)
 +  {
 +      check_bonds_timestep(sys,ir->delta_t,wi);
 +  }
 +
 +  if (EI_ENERGY_MINIMIZATION(ir->eI) && 0 == ir->nsteps)
 +  {
 +      warning_note(wi,"Zero-step energy minimization will alter the coordinates before calculating the energy. If you just want the energy of a single point, try zero-step MD (with unconstrained_start = yes). To do multiple single-point energy evaluations of different configurations of the same topology, use mdrun -rerun.");
 +  }
 +
 +  check_warning_error(wi,FARGS);
 +      
 +  if (bVerbose) 
 +    fprintf(stderr,"initialising group options...\n");
 +  do_index(mdparin,ftp2fn_null(efNDX,NFILE,fnm),
 +           sys,bVerbose,ir,
 +           bGenVel ? state.v : NULL,
 +           wi);
 +  
 +    if (ir->cutoff_scheme == ecutsVERLET && ir->verletbuf_drift > 0 &&
 +        ir->nstlist > 1)
 +    {
 +        if (EI_DYNAMICS(ir->eI) &&
 +            !(EI_MD(ir->eI) && ir->etc==etcNO) &&
 +            inputrec2nboundeddim(ir) == 3)
 +        {
 +            set_verlet_buffer(sys,ir,state.box,ir->verletbuf_drift,wi);
 +        }
 +    }
 +
 +  /* Init the temperature coupling state */
 +  init_gtc_state(&state,ir->opts.ngtc,0,ir->opts.nhchainlength); /* need to add nnhpres here? */
 +
 +  if (bVerbose)
 +    fprintf(stderr,"Checking consistency between energy and charge groups...\n");
 +  check_eg_vs_cg(sys);
 +  
 +  if (debug)
 +    pr_symtab(debug,0,"After index",&sys->symtab);
 +  triple_check(mdparin,ir,sys,wi);
 +  close_symtab(&sys->symtab);
 +  if (debug)
 +    pr_symtab(debug,0,"After close",&sys->symtab);
 +
 +  /* make exclusions between QM atoms */
 +  if (ir->bQMMM) {
 +    if (ir->QMMMscheme==eQMMMschemenormal && ir->ns_type == ensSIMPLE ){
 +      gmx_fatal(FARGS,"electrostatic embedding only works with grid neighboursearching, use ns-type=grid instead\n");
 +    }
 +    else {
 +     generate_qmexcl(sys,ir,wi);
 +    }
 +  }
 +
 +  if (ftp2bSet(efTRN,NFILE,fnm)) {
 +    if (bVerbose)
 +      fprintf(stderr,"getting data from old trajectory ...\n");
 +    cont_status(ftp2fn(efTRN,NFILE,fnm),ftp2fn_null(efEDR,NFILE,fnm),
 +              bNeedVel,bGenVel,fr_time,ir,&state,sys,oenv);
 +  }
 +
 +    if (ir->ePBC==epbcXY && ir->nwall!=2)
 +    {
 +        clear_rvec(state.box[ZZ]);
 +    }
 +  
 +    if (ir->cutoff_scheme != ecutsVERLET && ir->rlist > 0)
 +    {
 +        set_warning_line(wi,mdparin,-1);
 +        check_chargegroup_radii(sys,ir,state.x,wi);
 +    }
 +
 +  if (EEL_FULL(ir->coulombtype)) {
 +    /* Calculate the optimal grid dimensions */
 +    copy_mat(state.box,box);
 +    if (ir->ePBC==epbcXY && ir->nwall==2)
 +      svmul(ir->wall_ewald_zfac,box[ZZ],box[ZZ]);
 +    if (ir->nkx > 0 && ir->nky > 0 && ir->nkz > 0)
 +    {
 +        /* Mark fourier_spacing as not used */
 +        ir->fourier_spacing = 0;
 +    }
 +    else if (ir->nkx != 0 && ir->nky != 0 && ir->nkz != 0)
 +    {
 +        set_warning_line(wi,mdparin,-1);
 +        warning_error(wi,"Some of the Fourier grid sizes are set, but all of them need to be set.");
 +    }
 +    max_spacing = calc_grid(stdout,box,ir->fourier_spacing,
 +                            &(ir->nkx),&(ir->nky),&(ir->nkz));
 +  }
 +
 +  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); */
 +  
 +  if (EEL_PME(ir->coulombtype)) {
 +      float ratio = pme_load_estimate(sys,ir,state.box);
 +      fprintf(stderr,"Estimate for the relative computational load of the PME mesh part: %.2f\n",ratio);
 +      /* With free energy we might need to do PME both for the A and B state
 +       * charges. This will double the cost, but the optimal performance will
 +       * then probably be at a slightly larger cut-off and grid spacing.
 +       */
 +      if ((ir->efep == efepNO && ratio > 1.0/2.0) ||
 +          (ir->efep != efepNO && ratio > 2.0/3.0)) {
 +          warning_note(wi,
 +                       "The optimal PME mesh load for parallel simulations is below 0.5\n"
 +                       "and for highly parallel simulations between 0.25 and 0.33,\n"
 +                       "for higher performance, increase the cut-off and the PME grid spacing.\n");
 +          if (ir->efep != efepNO) {
 +              warning_note(wi,
 +                           "For free energy simulations, the optimal load limit increases from 0.5 to 0.667\n");
 +          }
 +      }
 +  }
 +  
 +  {
 +        char warn_buf[STRLEN];
 +        double cio = compute_io(ir,sys->natoms,&sys->groups,F_NRE,1);
 +        sprintf(warn_buf,"This run will generate roughly %.0f Mb of data",cio);
 +        if (cio > 2000) {
 +            set_warning_line(wi,mdparin,-1);
 +            warning_note(wi,warn_buf);
 +        } else {
 +            printf("%s\n",warn_buf);
 +        }
 +    }
 +      
 +  /* MRS: eventually figure out better logic for initializing the fep
 +   values that makes declaring the lambda and declaring the state not
 +   potentially conflict if not handled correctly. */
 +  if (ir->efep != efepNO)
 +  {
 +      state.fep_state = ir->fepvals->init_fep_state;
 +      for (i=0;i<efptNR;i++)
 +      {
 +          /* init_lambda trumps state definitions*/
 +          if (ir->fepvals->init_lambda >= 0)
 +          {
 +              state.lambda[i] = ir->fepvals->init_lambda;
 +          }
 +          else
 +          {
 +              if (ir->fepvals->all_lambda[i] == NULL)
 +              {
 +                  gmx_fatal(FARGS,"Values of lambda not set for a free energy calculation!");
 +              }
 +              else
 +              {
 +                  state.lambda[i] = ir->fepvals->all_lambda[i][state.fep_state];
 +              }
 +          }
 +      }
 +  }
 +
 +  if (bVerbose) 
 +    fprintf(stderr,"writing run input file...\n");
 +
 +  done_warning(wi,FARGS);
 +
 +  write_tpx_state(ftp2fn(efTPX,NFILE,fnm),ir,&state,sys);
 +  
 +  thanx(stderr);
 +  
 +  return 0;
 +}
index 0000000000000000000000000000000000000000,70752a4e13bbaf573395b71b606ef97077c32fc7..70752a4e13bbaf573395b71b606ef97077c32fc7
mode 000000,100644..100644
--- /dev/null
index 7a4118251cb5fb21a7b8a2d2ef720c87fbce09a5,0000000000000000000000000000000000000000..d7d0eec6e1c4bd2d06ee91f79d6e67dc22165541
mode 100644,000000..100644
--- /dev/null
@@@ -1,52 -1,0 +1,53 @@@
-     pme_loadbal.c repl_ex.c     runner.c    xutils.c)
 +include_directories(${CMAKE_SOURCE_DIR}/src/gromacs/gmxpreprocess)
 +
 +set(MDRUN_SOURCES
 +    do_gct.c      gctio.c       genalg.c    ionize.c
 +    md.c          md_openmm.c   mdrun.c     membed.c
++    pme_loadbal.c repl_ex.c     runner.c    xutils.c
++    ../main.cpp)
 +
 +if(GMX_OPENMM) 
 +    include_directories(./gmx_gpu_utils ${OpenMM_INCLUDE_DIR})
 +    link_directories(${OpenMM_LIBRARY_DIR}) 
 +    # with this define no evn.var. is needed with OPENMM_PLUGIN_DIR
 +    # if the same OpenMM installation is used for running and building 
 +    add_definitions( -DOPENMM_PLUGIN_DIR="${OpenMM_PLUGIN_DIR}" ) 
 +    file(TO_CMAKE_PATH ${OpenMM_PLUGIN_DIR} _path)
 +    add_library(openmm_api_wrapper STATIC openmm_wrapper.cpp)
 +    target_link_libraries(openmm_api_wrapper gmx_gpu_utils ${OpenMM_LIBRARIES})
 +    set(GMX_OPENMM_LIBRARIES openmm_api_wrapper gmx_gpu_utils ${OpenMM_LIBRARIES})   
 +endif(GMX_OPENMM)
 +
 +if(GMX_FAHCORE)
 +    add_library(fahcore ${MDRUN_SOURCES})
 +else(GMX_FAHCORE)
 +    add_executable(mdrun ${MDRUN_SOURCES})
 +    gmx_add_man_page(mdrun)
 +    target_link_libraries(mdrun ${GMX_EXTRA_LIBRARIES} libgromacs ${GMX_OPENMM_LIBRARIES}
 +        ${GMX_EXE_LINKER_FLAGS})
 +    set_target_properties(mdrun PROPERTIES OUTPUT_NAME "mdrun${GMX_BINARY_SUFFIX}"
 +        COMPILE_FLAGS "${OpenMP_C_FLAGS}")
 +    install(TARGETS mdrun DESTINATION ${BIN_INSTALL_DIR} COMPONENT mdrun)
 +
 +    if(GMX_OPENMM AND MSVC)
 +        set_target_properties(mdrun PROPERTIES LINK_FLAGS "/NODEFAULTLIB:LIBCMT")
 +    endif()
 +
 +    # Create the custom install-mdrun target
 +    if (BUILD_SHARED_LIBS)
 +        # If shared libraries are used, we need to install the libraries in
 +        # addition to the mdrun binary.
 +        add_custom_target(install-mdrun
 +            COMMAND ${CMAKE_COMMAND} -DCOMPONENT=libraries
 +                    -P ${CMAKE_BINARY_DIR}/cmake_install.cmake
 +            COMMAND ${CMAKE_COMMAND} -DCOMPONENT=mdrun
 +                    -P ${CMAKE_BINARY_DIR}/cmake_install.cmake
 +            COMMENT "Installing mdrun")
 +    else (BUILD_SHARED_LIBS)
 +        add_custom_target(install-mdrun
 +            COMMAND ${CMAKE_COMMAND} -DCOMPONENT=mdrun
 +                    -P ${CMAKE_BINARY_DIR}/cmake_install.cmake
 +            COMMENT "Installing mdrun")
 +    endif (BUILD_SHARED_LIBS)
 +    add_dependencies(install-mdrun mdrun)
 +endif(GMX_FAHCORE)
index 0c8a77d6104f836ee74c24bdec19c7b23fa859ea,0000000000000000000000000000000000000000..386b897e322ff58a7c38adb53ed2bcb644c979b3
mode 100644,000000..100644
--- /dev/null
@@@ -1,2146 -1,0 +1,2147 @@@
 +/* -*- 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:
 + * Gallium Rubidium Oxygen Manganese Argon Carbon Silicon
 + */
 +#ifdef HAVE_CONFIG_H
 +#include <config.h>
 +#endif
 +
 +#include "typedefs.h"
 +#include "smalloc.h"
 +#include "sysstuff.h"
 +#include "vec.h"
 +#include "statutil.h"
 +#include "vcm.h"
 +#include "mdebin.h"
 +#include "nrnb.h"
 +#include "calcmu.h"
 +#include "index.h"
 +#include "vsite.h"
 +#include "update.h"
 +#include "ns.h"
 +#include "trnio.h"
 +#include "xtcio.h"
 +#include "mdrun.h"
 +#include "md_support.h"
++#include "md_logging.h"
 +#include "confio.h"
 +#include "network.h"
 +#include "pull.h"
 +#include "xvgr.h"
 +#include "physics.h"
 +#include "names.h"
 +#include "xmdrun.h"
 +#include "ionize.h"
 +#include "disre.h"
 +#include "orires.h"
 +#include "pme.h"
 +#include "mdatoms.h"
 +#include "repl_ex.h"
 +#include "qmmm.h"
 +#include "domdec.h"
 +#include "domdec_network.h"
 +#include "partdec.h"
 +#include "topsort.h"
 +#include "coulomb.h"
 +#include "constr.h"
 +#include "shellfc.h"
 +#include "compute_io.h"
 +#include "mvdata.h"
 +#include "checkpoint.h"
 +#include "mtop_util.h"
 +#include "sighandler.h"
 +#include "txtdump.h"
 +#include "string2.h"
 +#include "pme_loadbal.h"
 +#include "bondf.h"
 +#include "membed.h"
 +#include "types/nlistheuristics.h"
 +#include "types/iteratedconstraints.h"
 +#include "nbnxn_cuda_data_mgmt.h"
 +
 +#ifdef GMX_LIB_MPI
 +#include <mpi.h>
 +#endif
 +#ifdef GMX_THREAD_MPI
 +#include "tmpi.h"
 +#endif
 +
 +#ifdef GMX_FAHCORE
 +#include "corewrap.h"
 +#endif
 +
 +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,
 +                               nbnxn_cuda_ptr_t cu_nbv)
 +{
 +    char sbuf[STEPSTRSIZE];
 +
 +    /* Reset all the counters related to performance over the run */
 +    md_print_warn(cr,fplog,"step %s: resetting all time and cycle counters\n",
 +                  gmx_step_str(step,sbuf));
 +
 +    if (cu_nbv)
 +    {
 +        nbnxn_cuda_reset_timings(cu_nbv);
 +    }
 +
 +    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);
 +}
 +
 +double do_md(FILE *fplog,t_commrec *cr,int nfile,const t_filenm fnm[],
 +             const output_env_t oenv, gmx_bool bVerbose,gmx_bool bCompact,
 +             int nstglobalcomm,
 +             gmx_vsite_t *vsite,gmx_constr_t constr,
 +             int stepout,t_inputrec *ir,
 +             gmx_mtop_t *top_global,
 +             t_fcdata *fcd,
 +             t_state *state_global,
 +             t_mdatoms *mdatoms,
 +             t_nrnb *nrnb,gmx_wallcycle_t wcycle,
 +             gmx_edsam_t ed,t_forcerec *fr,
 +             int repl_ex_nst,int repl_ex_nex,int repl_ex_seed,gmx_membed_t membed,
 +             real cpt_period,real max_hours,
 +             const char *deviceOptions,
 +             unsigned long Flags,
 +             gmx_runtime_t *runtime)
 +{
 +    gmx_mdoutf_t *outf;
 +    gmx_large_int_t step,step_rel;
 +    double     run_time;
 +    double     t,t0,lam0[efptNR];
 +    gmx_bool       bGStatEveryStep,bGStat,bCalcVir,bCalcEner;
 +    gmx_bool       bNS,bNStList,bSimAnn,bStopCM,bRerunMD,bNotLastFrame=FALSE,
 +               bFirstStep,bStateFromCP,bStateFromTPX,bInitStep,bLastStep,
 +               bBornRadii,bStartingFromCpt;
 +    gmx_bool   bDoDHDL=FALSE,bDoFEP=FALSE,bDoExpanded=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;
 +    df_history_t df_history;
 +    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_rng_t mcrng=NULL;
 +    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,bFirstIterate,bTemp,bPres,bTrotter;
 +    gmx_bool        bUpdateDoLR;
 +    real        mu_aver=0,dvdl;
 +    int         a0,a1,gnx=0,ii;
 +    atom_id     *grpindex=NULL;
 +    char        *grpname;
 +    t_coupl_rec *tcr=NULL;
 +    rvec        *xcopy=NULL,*vcopy=NULL,*cbuf=NULL;
 +    matrix      boxcopy={{0}},lastbox;
 +      tensor      tmpvir;
 +      real        fom,oldfom,veta_save,pcurr,scalevir,tracevir;
 +      real        vetanew = 0;
 +    int         lamnew=0;
 +    /* for FEP */
 +    int         fep_state=0;
 +    int         nstfep;
 +    real        rate;
 +    double      cycles;
 +      real        saved_conserved_quantity = 0;
 +    real        last_ekin = 0;
 +      int         iter_i;
 +      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;
 +    gmx_large_int_t multisim_nsteps=-1; /* number of steps to do  before first multisim 
 +                                          simulation stops. If equal to zero, don't
 +                                          communicate any more between multisims.*/
 +    /* PME load balancing data for GPU kernels */
 +    pme_load_balancing_t pme_loadbal=NULL;
 +    double          cycles_pmes;
 +    gmx_bool        bPMETuneTry=FALSE,bPMETuneRunning=FALSE;
 +
 +#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);
 +    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_NPH_TROTTER(ir) || IR_NPT_TROTTER(ir)) && (constr) && (!bRerunMD));
 +    bTrotter = (bVV && (IR_NPT_TROTTER(ir) || IR_NPH_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);
 +
 +    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,
 +            &(state_global->fep_state),lam0,
 +            nrnb,top_global,&upd,
 +            nfile,fnm,&outf,&mdebin,
 +            force_vir,shake_vir,mu_tot,&bSimAnn,&vcm,state_global,Flags);
 +
 +    clear_mat(total_vir);
 +    clear_mat(pres);
 +    /* Energy terms and groups */
 +    snew(enerd,1);
 +    init_enerdata(top_global->groups.grps[egcENER].nr,ir->fepvals->n_lambda,
 +                  enerd);
 +    if (DOMAINDECOMP(cr))
 +    {
 +        f = NULL;
 +    }
 +    else
 +    {
 +        snew(f,top_global->natoms);
 +    }
 +
 +    /* lambda Monte carlo random number generator  */
 +    if (ir->bExpanded)
 +    {
 +        mcrng = gmx_rng_init(ir->expandedvals->lmc_seed);
 +    }
 +    /* copy the state into df_history */
 +    copy_df_history(&df_history,&state_global->dfhist);
 +
 +    /* 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_THREAD_MPI
 +        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_THREAD_MPI
 +        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;
 +        }
 +
 +        forcerec_set_excl_load(fr,top,cr);
 +
 +        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 && !fr->bMolPBC) {
 +            graph = mk_graph(fplog,&(top->idef),0,top_global->natoms,FALSE,FALSE);
 +        }
 +
 +        if (shellfc) {
 +            make_local_shells(cr,mdatoms,shellfc);
 +        }
 +
 +        init_bonded_thread_force_reduction(fr,&top->idef);
 +
 +        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[efptMASS]);
 +
 +    if (opt2bSet("-cpi",nfile,fnm))
 +    {
 +        bStateFromCP = gmx_fexist_master(opt2fn_master("-cpi",nfile,fnm,cr),cr);
 +    }
 +    else
 +    {
 +        bStateFromCP = FALSE;
 +    }
 +
 +    if (MASTER(cr))
 +    {
 +        if (bStateFromCP)
 +        {
 +            /* 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);
 +    }
 +
 +    if (state->flags & (1<<estMC_RNG))
 +    {
 +        set_mc_state(mcrng,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)
 +    {
 +        /* We need to be sure replica exchange can only occur
 +         * when the energies are current */
 +        check_nst_param(fplog,cr,"nstcalcenergy",ir->nstcalcenergy,
 +                        "repl_ex_nst",&repl_ex_nst);
 +        /* This check needs to happen before inter-simulation
 +         * signals are initialized, too */
 +    }
 +    if (repl_ex_nst > 0 && MASTER(cr))
 +    {
 +        repl_ex = init_replica_exchange(fplog,cr->ms,state_global,ir,
 +                                        repl_ex_nst,repl_ex_nex,repl_ex_seed);
 +    }
 +
 +    /* PME tuning is only supported with GPUs or PME nodes and not with rerun */
 +    if ((Flags & MD_TUNEPME) &&
 +        EEL_PME(fr->eeltype) &&
 +        ( (fr->cutoff_scheme == ecutsVERLET && fr->nbv->bUseGPU) || !(cr->duty & DUTY_PME)) &&
 +        !bRerunMD)
 +    {
 +        pme_loadbal_init(&pme_loadbal,ir,state->box,fr->ic,fr->pmedata);
 +        cycles_pmes = 0;
 +        if (cr->duty & DUTY_PME)
 +        {
 +            /* Start tuning right away, as we can't measure the load */
 +            bPMETuneRunning = TRUE;
 +        }
 +        else
 +        {
 +            /* Separate PME nodes, we can measure the PP/PME load balance */
 +            bPMETuneTry = TRUE;
 +        }
 +    }
 +
 +    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();
 +  
 +    /* set free energy calculation frequency as the minimum of nstdhdl, nstexpanded, and nstrepl_ex_nst*/
 +    nstfep = ir->fepvals->nstdhdl;
 +    if (ir->bExpanded && (nstfep > ir->expandedvals->nstexpanded))
 +    {
 +        nstfep = ir->expandedvals->nstexpanded;
 +    }
 +    if (repl_ex_nst > 0 && repl_ex_nst > nstfep)
 +    {
 +        nstfep = repl_ex_nst;
 +    }
 +
 +    /* I'm assuming we need global communication the first time! MRS */
 +    cglo_flags = (CGLO_TEMPERATURE | CGLO_GSTAT
 +                  | ((ir->comm_mode != ecmNO) ? CGLO_STOPCM:0)
 +                  | (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,
 +                    NULL,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 to 
 +           compute_globals, 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,
 +                        NULL,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_STOPCM | 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 */
 +    }
 +    
 +    /* 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));
 +        }
 +        if (EI_STATE_VELOCITY(ir->eI))
 +        {
 +            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;
 +        }
 +
 +        rerun_fr.natoms = 0;
 +        if (MASTER(cr))
 +        {
 +            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);
 +                }
 +            }
 +        }
 +
 +        if (PAR(cr))
 +        {
 +            rerun_parallel_comm(cr,&rerun_fr,&bNotLastFrame);
 +        }
 +
 +        if (ir->ePBC != epbcNONE)
 +        {
 +            /* 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 = !bStateFromCP;
 +    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);
 +    }
 +
 +    if (MULTISIM(cr) && (repl_ex_nst <=0 ))
 +    {
 +        /* check how many steps are left in other sims */
 +        multisim_nsteps=get_multisim_nsteps(cr, ir->nsteps);
 +    }
 +
 +
 +    /* and stop now if we should */
 +    bLastStep = (bRerunMD || (ir->nsteps >= 0 && step_rel > ir->nsteps) ||
 +                 ((multisim_nsteps >= 0) && (step_rel >= multisim_nsteps )));
 +    while (!bLastStep || (bRerunMD && bNotLastFrame)) {
 +
 +        wallcycle_start(wcycle,ewcSTEP);
 +
 +        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 || ir->bSimTemp)
 +            {
 +            /* find and set the current lambdas.  If rerunning, we either read in a state, or a lambda value,
 +               requiring different logic. */
 +            
 +            set_current_lambdas(step,ir->fepvals,bRerunMD,&rerun_fr,state_global,state,lam0);
 +            bDoDHDL = do_per_step(step,ir->fepvals->nstdhdl);
 +            bDoFEP  = (do_per_step(step,nstfep) && (ir->efep != efepNO));
 +            bDoExpanded  = (do_per_step(step,ir->expandedvals->nstexpanded) && (ir->bExpanded) && (step > 0));
 +        }
 +
 +        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 || bDoFEP ||
 +                   (ir->nstlist == -1 && nlh.nabnsb > 0));
 +
 +            if (bNS && ir->nstlist == -1)
 +            {
 +                set_nlistheuristics(&nlh,bFirstStep || bExchanged || bDoFEP, step);
 +            }
 +        } 
 +
 +        /* check whether we should stop because another simulation has 
 +           stopped. */
 +        if (MULTISIM(cr))
 +        {
 +            if ( (multisim_nsteps >= 0) &&  (step_rel >= multisim_nsteps)  &&  
 +                 (multisim_nsteps != ir->nsteps) )  
 +            {
 +                if (bNS)
 +                {
 +                    if (MASTER(cr))
 +                    {
 +                        fprintf(stderr, 
 +                                "Stopping simulation %d because another one has finished\n",
 +                                cr->ms->sim);
 +                    }
 +                    bLastStep=TRUE;
 +                    gs.sig[eglsCHKPT] = 1;
 +                }
 +            }
 +        }
 +
 +        /* < 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 && !bPMETuneRunning);
 +                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[efptFEP]); /* can we improve the information printed here? */
 +        }
 +
 +        if (ir->efep != efepNO)
 +        {
 +            update_mdatoms(mdatoms,state->lambda[efptMASS]);
 +        }
 +
 +        if ((bRerunMD && rerun_fr.bV) || bExchanged)
 +        {
 +            
 +            /* 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))
 +            {
 +                gmx_finalize_par();
 +
 +                exit(0);
 +            }
 +        }
 +
 +        /* 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 || ir->nstlist == 0)) ||
 +                 (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).
 +         */
 +        if (EI_VV(ir->eI) && (!bInitStep))
 +        {
 +            /* for vv, the first half actually corresponds to the last step */
 +            bCalcEner = do_per_step(step-1,ir->nstcalcenergy);
 +        }
 +        else
 +        {
 +            bCalcEner = do_per_step(step,ir->nstcalcenergy);
 +        }
 +        bCalcVir = bCalcEner ||
 +            (ir->epc != epcNO && do_per_step(step,ir->nstpcouple));
 +
 +        /* Do we need global communication ? */
 +        bGStat = (bCalcVir || bCalcEner || bStopCM ||
 +                  do_per_step(step,nstglobalcomm) ||
 +                  (ir->nstlist == -1 && !bRerunMD && step >= nlh.step_nscheck));
 +
 +        do_ene = (do_per_step(step,ir->nstenergy) || bLastStep);
 +
 +        if (do_ene || do_log)
 +        {
 +            bCalcVir  = TRUE;
 +            bCalcEner = TRUE;
 +            bGStat    = TRUE;
 +        }
 +        
 +        /* these CGLO_ options remain the same throughout the iteration */
 +        cglo_flags = ((bRerunMD ? CGLO_RERUNMD : 0) |
 +                      (bGStat ? CGLO_GSTAT : 0)
 +            );
 +        
 +        force_flags = (GMX_FORCE_STATECHANGED |
 +                       ((DYNAMIC_BOX(*ir) || bRerunMD) ? GMX_FORCE_DYNAMICBOX : 0) |
 +                       GMX_FORCE_ALLFORCES |
 +                       GMX_FORCE_SEPLRF |
 +                       (bCalcVir ? GMX_FORCE_VIRIAL : 0) |
 +                       (bCalcEner ? GMX_FORCE_ENERGY : 0) |
 +                       (bDoFEP ? GMX_FORCE_DHDL : 0)
 +            );
 +
 +        if(fr->bTwinRange)
 +        {
 +            if(do_per_step(step,ir->nstcalclr))
 +            {
 +                force_flags |= GMX_FORCE_DO_LR;
 +            }
 +        }
 +        
 +        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);
 +        }
 +        
 +        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);
 +        }
 +        
 +        if (bVV && !bStartingFromCpt && !bRerunMD)
 +        /*  ############### START FIRST UPDATE HALF-STEP FOR VV METHODS############### */
 +        {
 +            if (ir->eI==eiVV && 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? */
 +            } else {
 +                /* this is for NHC in the Ekin(t+dt/2) version of vv */
 +                trotter_update(ir,step,ekind,enerd,state,total_vir,mdatoms,&MassQ,trotter_seq,ettTSEQ1);            
 +            }
 +
 +            /* If we are using twin-range interactions where the long-range component
 +             * is only evaluated every nstcalclr>1 steps, we should do a special update
 +             * step to combine the long-range forces on these steps.
 +             * For nstcalclr=1 this is not done, since the forces would have been added
 +             * directly to the short-range forces already.
 +             */
 +            bUpdateDoLR = (fr->bTwinRange && do_per_step(step,ir->nstcalclr));
 +            
 +            update_coords(fplog,step,ir,mdatoms,state,fr->bMolPBC,
 +                          f,bUpdateDoLR,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,fr->bMolPBC,graph,f,
 +                                       &top->idef,shake_vir,NULL,
 +                                       cr,nrnb,wcycle,upd,constr,
 +                                       bInitStep,TRUE,bCalcVir,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 VV, compute the pressure and constraints */
 +                /* For VV2, we strictly only need this if using pressure
 +                 * control, but we really would like to have accurate pressures
 +                 * printed out.
 +                 * Think about ways around this in the future?
 +                 * For now, keep this choice in comments.
 +                 */
 +                /*bPres = (ir->eI==eiVV || IR_NPT_TROTTER(ir)); */
 +                    /*bTemp = ((ir->eI==eiVV &&(!bInitStep)) || (ir->eI==eiVVAK && IR_NPT_TROTTER(ir)));*/
 +                bPres = TRUE;
 +                bTemp = ((ir->eI==eiVV &&(!bInitStep)) || (ir->eI==eiVVAK));
 +                if (bCalcEner && ir->eI==eiVVAK)  /*MRS:  7/9/2010 -- this still doesn't fix it?*/
 +                {
 +                    bSumEkinhOld = TRUE;
 +                }
 +                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 
 +                                | (bStopCM ? CGLO_STOPCM : 0)
 +                                | (bTemp ? CGLO_TEMPERATURE:0) 
 +                                | (bPres ? CGLO_PRESSURE : 0) 
 +                                | (bPres ? CGLO_CONSTRAINT : 0)
 +                                | ((bIterations && 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 (always true now, since we want accurate statistics).
 +                   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 (!bInitStep) 
 +                {
 +                    if (bTrotter)
 +                    {
 +                        trotter_update(ir,step,ekind,enerd,state,total_vir,mdatoms,&MassQ,trotter_seq,ettTSEQ2);
 +                    } 
 +                    else 
 +                    {
 +                        if (bExchanged)
 +                        {
 +            
 +                            /* 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);
 +                        }
 +
 +
 +                        update_tcouple(fplog,step,ir,state,ekind,wcycle,upd,&MassQ,mdatoms);
 +                    }
 +                }
 +                
 +                if (bIterations &&
 +                    done_iterating(cr,fplog,step,&iterate,bFirstIterate,
 +                                   state->veta,&vetanew)) 
 +                {
 +                    break;
 +                }
 +                bFirstIterate = FALSE;
 +            }
 +
 +            if (bTrotter && !bInitStep) {
 +                enerd->term[F_DVDL_BONDED] += dvdl;        /* only add after iterations */
 +                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_DVDL_BONDED] += dvdl;
 +        }
 +    
 +        /* MRS -- now done iterating -- compute the conserved quantity */
 +        if (bVV) {
 +            saved_conserved_quantity = compute_conserved_from_auxiliary(ir,state,&MassQ);
 +            if (ir->eI==eiVV) 
 +            {
 +                last_ekin = enerd->term[F_EKIN];
 +            }
 +            if ((ir->eDispCorr != edispcEnerPres) && (ir->eDispCorr != edispcAllEnerPres)) 
 +            {
 +                saved_conserved_quantity -= enerd->term[F_DISPCORR];
 +            }
 +            /* sum up the foreign energy and dhdl terms for vv.  currently done every step so that dhdl is correct in the .edr */
 +            sum_dhdl(enerd,state->lambda,ir->fepvals);
 +        }
 +        
 +        /* ########  END FIRST UPDATE STEP  ############## */
 +        /* ########  If doing VV, we now have v(dt) ###### */
 +        if (bDoExpanded) {
 +            /* perform extended ensemble sampling in lambda - we don't
 +               actually move to the new state before outputting
 +               statistics, but if performing simulated tempering, we
 +               do update the velocities and the tau_t. */
 +        
 +            lamnew = ExpandedEnsembleDynamics(fplog,ir,enerd,state,&MassQ,&df_history,step,mcrng,state->v,mdatoms);
 +        }
 +        /* ################## 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
 +         */
 +        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; };
 +
 +#if defined(GMX_FAHCORE) || defined(GMX_WRITELASTSTEP)
 +        if (bLastStep)
 +        {
 +            /* Enforce writing positions and velocities at end of run */
 +            mdof_flags |= (MDOF_X | MDOF_V);
 +        }
 +#endif
 +#ifdef GMX_FAHCORE
 +        if (MASTER(cr))
 +            fcReportProgress( ir->nsteps, step );
 +
 +        /* 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 (state->flags  & (1<<estMC_RNG))
 +                {
 +                    get_mc_state(mcrng,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);
 +                    if (ir->efep!=efepNO || ir->bSimTemp) 
 +                    {
 +                        state_global->fep_state = state->fep_state; /* MRS: seems kludgy. The code should be
 +                                                                       structured so this isn't necessary.
 +                                                                       Note this reassignment is only necessary
 +                                                                       for single threads.*/
 +                        copy_df_history(&state_global->dfhist,&df_history);
 +                    }
 +                }
 +            }
 +            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 (fr->bMolPBC)
 +                {
 +                    /* 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);
 +        }
 +        
 +        /* 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 wallclock run time up till now */
 +        run_time = gmx_gettime() - (double)runtime->real;
 +
 +        /* Check whether everything is still allright */    
 +        if (((int)gmx_get_stop_condition() > handled_stop_condition)
 +#ifdef GMX_THREAD_MPI
 +            && MASTER(cr)
 +#endif
 +            )
 +        {
 +            /* this is just make gs.sig compatible with the hack 
 +               of sending signals around by MPI_Reduce with together with
 +               other floats */
 +            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;
 +        }
 +  
 +
 +        /* at the start of step, randomize the velocities */
 +        if (ETC_ANDERSEN(ir->etc) && EI_VV(ir->eI))
 +        {
 +            gmx_bool bDoAndersenConstr;
 +            bDoAndersenConstr = (constr && update_randomize_velocities(ir,step,mdatoms,state,upd,&top->idef,constr));
 +            /* if we have constraints, we have to remove the kinetic energy parallel to the bonds */
 +            if (bDoAndersenConstr)
 +            {
 +                update_constraints(fplog,step,&dvdl,ir,ekind,mdatoms,
 +                                   state,fr->bMolPBC,graph,f,
 +                                   &top->idef,tmp_vir,NULL,
 +                                   cr,nrnb,wcycle,upd,constr,
 +                                   bInitStep,TRUE,bCalcVir,vetanew);
 +            }
 +        }
 +
 +        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 ################# */
 +            /* 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);
 +
 +            bOK = TRUE;
 +            if (!(bRerunMD && !rerun_fr.bV && !bForceUpdate))
 +            {
 +                wallcycle_start(wcycle,ewcUPDATE);
 +                dvdl = 0;
 +                /* 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.
 +                 */
 +                }
 +                else 
 +                {
 +                    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)
 +                {
 +                    bUpdateDoLR = (fr->bTwinRange && do_per_step(step,ir->nstcalclr));
 +
 +                    /* velocity half-step update */
 +                    update_coords(fplog,step,ir,mdatoms,state,fr->bMolPBC,f,
 +                                  bUpdateDoLR,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);
 +                }
 +                bUpdateDoLR = (fr->bTwinRange && do_per_step(step,ir->nstcalclr));
 +
 +                update_coords(fplog,step,ir,mdatoms,state,fr->bMolPBC,f,
 +                              bUpdateDoLR,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,
 +                                   fr->bMolPBC,graph,f,
 +                                   &top->idef,shake_vir,force_vir,
 +                                   cr,nrnb,wcycle,upd,constr,
 +                                   bInitStep,FALSE,bCalcVir,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    
 +                        );
 +                    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);
 +
 +                    bUpdateDoLR = (fr->bTwinRange && do_per_step(step,ir->nstcalclr));
 +
 +                    update_coords(fplog,step,ir,mdatoms,state,fr->bMolPBC,f,
 +                                  bUpdateDoLR,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,fr->bMolPBC,graph,f,
 +                                       &top->idef,tmp_vir,force_vir,
 +                                       cr,nrnb,wcycle,upd,NULL,
 +                                       bInitStep,FALSE,bCalcVir,
 +                                       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 dV/dl",0.0,dvdl);
 +                }
 +                enerd->term[F_DVDL_BONDED] += dvdl;
 +            } 
 +            else if (graph) 
 +            {
 +                /* Need to unshift here */
 +                unshift_self(graph,state->box,state->x);
 +            }
 +
 +            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 ############ */
 +            /* With Leap-Frog we can skip compute_globals at
 +             * non-communication steps, but we need to calculate
 +             * the kinetic energy one step before communication.
 +             */
 +            if (bGStat || do_per_step(step+1,nstglobalcomm) ||
 +                EI_VV(ir->eI))
 +            {
 +                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_rel % gs.nstms == 0) && 
 +                                (multisim_nsteps<0 || (step_rel<multisim_nsteps)),
 +                                lastbox,
 +                                top_global,&pcurr,top_global->natoms,&bSumEkinhOld,
 +                                cglo_flags 
 +                                | (!EI_VV(ir->eI) ? CGLO_ENERGY : 0)
 +                                | (!EI_VV(ir->eI) && bStopCM ? CGLO_STOPCM : 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;
 +        }
 +
 +        /* only add constraint dvdl after constraints */
 +        enerd->term[F_DVDL_BONDED] += dvdl;
 +        if (!bVV)
 +        {
 +            /* sum up the foreign energy and dhdl terms for md and sd. currently done every step so that dhdl is correct in the .edr */
 +            sum_dhdl(enerd,state->lambda,ir->fepvals);
 +        }
 +        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))
 +            {
 +                gmx_finalize_par();
 +
 +                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  ###########  */
 +        
 +        /* 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];
 +        
 +        if (bVV)
 +        {
 +            enerd->term[F_ECONSERVED] = enerd->term[F_ETOT] + saved_conserved_quantity;
 +        }
 +        else 
 +        {
 +            enerd->term[F_ECONSERVED] = enerd->term[F_ETOT] + compute_conserved_from_auxiliary(ir,state,&MassQ);
 +        }
 +        /* 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 (fplog && do_log && bDoExpanded)
 +            {
 +                /* only needed if doing expanded ensemble */
 +                PrintFreeEnergyInfoToFile(fplog,ir->fepvals,ir->expandedvals,ir->bSimTemp?ir->simtempvals:NULL,
 +                                          &df_history,state->fep_state,ir->nstlog,step);
 +            }
 +            if (!(bStartingFromCpt && (EI_VV(ir->eI)))) 
 +            {
 +                if (bCalcEner)
 +                {
 +                    upd_mdebin(mdebin,bDoDHDL, TRUE,
 +                               t,mdatoms->tmass,enerd,state,
 +                               ir->fepvals,ir->expandedvals,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 disk space?");
 +                }
 +            }
 +        }
 +        if (bDoExpanded)
 +        {
 +            /* Have to do this part after outputting the logfile and the edr file */
 +            state->fep_state = lamnew;
 +            for (i=0;i<efptNR;i++)
 +            {
 +                state->lambda[i] = ir->fepvals->all_lambda[i][lamnew];
 +            }
 +        }
 +        /* Remaining runtime */
 +        if (MULTIMASTER(cr) && (do_verbose || gmx_got_usr_signal()) && !bPMETuneRunning)
 +        {
 +            if (shellfc) 
 +            {
 +                fprintf(stderr,"\n");
 +            }
 +            print_time(stderr,runtime,step,ir,cr);
 +        }
 +
 +        /* 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,
 +                                          state,step,t);
 +
 +            if (bExchanged && 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);
 +            }
 +        }
 +        
 +        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 ( (membed!=NULL) && (!bLastStep) )
 +        {
 +            rescale_membed(step_rel,membed,state_global->x);
 +        }
 +
 +        if (bRerunMD) 
 +        {
 +            if (MASTER(cr))
 +            {
 +                /* read next frame from input trajectory */
 +                bNotLastFrame = read_next_frame(oenv,status,&rerun_fr);
 +            }
 +
 +            if (PAR(cr))
 +            {
 +                rerun_parallel_comm(cr,&rerun_fr,&bNotLastFrame);
 +            }
 +        }
 +        
 +        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 (bPMETuneRunning || bPMETuneTry)
 +        {
 +            /* PME grid + cut-off optimization with GPUs or PME nodes */
 +
 +            /* Count the total cycles over the last steps */
 +            cycles_pmes += cycles;
 +
 +            /* We can only switch cut-off at NS steps */
 +            if (step % ir->nstlist == 0)
 +            {
 +                /* PME grid + cut-off optimization with GPUs or PME nodes */
 +                if (bPMETuneTry)
 +                {
 +                    if (DDMASTER(cr->dd))
 +                    {
 +                        /* PME node load is too high, start tuning */
 +                        bPMETuneRunning = (dd_pme_f_ratio(cr->dd) >= 1.05);
 +                    }
 +                    dd_bcast(cr->dd,sizeof(gmx_bool),&bPMETuneRunning);
 +
 +                    if (bPMETuneRunning || step_rel > ir->nstlist*50)
 +                    {
 +                        bPMETuneTry     = FALSE;
 +                    }
 +                }
 +                if (bPMETuneRunning)
 +                {
 +                    /* init_step might not be a multiple of nstlist,
 +                     * but the first cycle is always skipped anyhow.
 +                     */
 +                    bPMETuneRunning =
 +                        pme_load_balance(pme_loadbal,cr,
 +                                         (bVerbose && MASTER(cr)) ? stderr : NULL,
 +                                         fplog,
 +                                         ir,state,cycles_pmes,
 +                                         fr->ic,fr->nbv,&fr->pmedata,
 +                                         step);
 +
 +                    /* Update constants in forcerec/inputrec to keep them in sync with fr->ic */
 +                    fr->ewaldcoeff = fr->ic->ewaldcoeff;
 +                    fr->rlist      = fr->ic->rlist;
 +                    fr->rlistlong  = fr->ic->rlistlong;
 +                    fr->rcoulomb   = fr->ic->rcoulomb;
 +                    fr->rvdw       = fr->ic->rvdw;
 +                }
 +                cycles_pmes = 0;
 +            }
 +        }
 +
 +        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,
 +                               fr->nbv != NULL && fr->nbv->bUseGPU ? fr->nbv->cu_nbv : NULL);
 +            wcycle_set_reset_counters(wcycle,-1);
 +            /* Correct max_hours for the elapsed time */
 +            max_hours -= run_time/(60.0*60.0);
 +            bResetCountersHalfMaxH = FALSE;
 +            gs.set[eglsRESETCOUNTERS] = 0;
 +        }
 +
 +    }
 +    /* End of main MD loop */
 +    debug_gmx();
 +    
 +    /* Stop the time */
 +    runtime_end(runtime);
 +    
 +    if (bRerunMD && MASTER(cr))
 +    {
 +        close_trj(status);
 +    }
 +    
 +    if (!(cr->duty & DUTY_PME))
 +    {
 +        /* Tell the PME only node to finish */
 +        gmx_pme_send_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 (pme_loadbal != NULL)
 +    {
 +        pme_loadbal_done(pme_loadbal,fplog);
 +    }
 +
 +    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;
 +}
Simple merge
index efd88719ca78791c8f1e9a92b1e7f840c55a7457,0000000000000000000000000000000000000000..a041450903586b279f6ee995826c61b56fbc60e3
mode 100644,000000..100644
--- /dev/null
@@@ -1,9 -1,0 +1,9 @@@
- file(GLOB PDB2GMX_SOURCES *.c)
 +include_directories(${CMAKE_SOURCE_DIR}/src/gromacs/gmxpreprocess)
 +
++file(GLOB PDB2GMX_SOURCES *.c ../main.cpp)
 +
 +add_executable(pdb2gmx ${PDB2GMX_SOURCES})
 +gmx_add_man_page(pdb2gmx)
 +target_link_libraries(pdb2gmx ${GMX_EXTRA_LIBRARIES} libgromacs ${GMX_EXE_LINKER_FLAGS})
 +set_target_properties(pdb2gmx PROPERTIES OUTPUT_NAME "pdb2gmx${GMX_BINARY_SUFFIX}")
 +install(TARGETS pdb2gmx DESTINATION ${BIN_INSTALL_DIR} COMPONENT runtime)
index 94315bc6491226cd9d162d1c5c6c74040c91ad09,0000000000000000000000000000000000000000..9bdf3666a1de51bfb05665b88875e101e7fe3265
mode 100644,000000..100644
--- /dev/null
@@@ -1,2030 -1,0 +1,2030 @@@
- int main(int argc, char *argv[])
 +/* -*- 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:
 + * Gallium Rubidium Oxygen Manganese Argon Carbon Silicon
 + */
 +#ifdef HAVE_CONFIG_H
 +#include <config.h>
 +#endif
 +
 +#include <time.h>
 +#include <ctype.h>
 +#include "sysstuff.h"
 +#include "typedefs.h"
 +#include "gmxfio.h"
 +#include "smalloc.h"
 +#include "copyrite.h"
 +#include "string2.h"
 +#include "confio.h"
 +#include "symtab.h"
 +#include "vec.h"
 +#include "statutil.h"
 +#include "futil.h"
 +#include "gmx_fatal.h"
 +#include "pdbio.h"
 +#include "toputil.h"
 +#include "h_db.h"
 +#include "physics.h"
 +#include "pgutil.h"
 +#include "calch.h"
 +#include "resall.h"
 +#include "pdb2top.h"
 +#include "ter_db.h"
 +#include "strdb.h"
 +#include "gbutil.h"
 +#include "genhydro.h"
 +#include "readinp.h"
 +#include "atomprop.h"
 +#include "xlate.h"
 +#include "specbond.h"
 +#include "index.h"
 +#include "hizzie.h"
 +#include "fflibutil.h"
 +#include "macros.h"
 +
 +
 +typedef struct {
 +  char gmx[6];
 +  char main[6];
 +  char nter[6];
 +  char cter[6];
 +  char bter[6];
 +} rtprename_t;
 +
 +
 +static const char *res2bb_notermini(const char *name,
 +                                  int nrr,const rtprename_t *rr)
 +{
 +  /* NOTE: This function returns the main building block name,
 +   *       it does not take terminal renaming into account.
 +   */
 +  int i;
 +
 +  i = 0;
 +  while (i < nrr && gmx_strcasecmp(name,rr[i].gmx) != 0) {
 +    i++;
 +  }
 +
 +  return (i < nrr ? rr[i].main : name);
 +}
 +
 +static const char *select_res(int nr,int resnr,
 +                            const char *name[],const char *expl[],
 +                            const char *title,
 +                            int nrr,const rtprename_t *rr)
 +{
 +  int sel=0;
 +
 +  printf("Which %s type do you want for residue %d\n",title,resnr+1);
 +  for(sel=0; (sel < nr); sel++) {
 +    printf("%d. %s (%s)\n",
 +         sel,expl[sel],res2bb_notermini(name[sel],nrr,rr));
 +  }
 +  printf("\nType a number:"); fflush(stdout);
 +
 +  if (scanf("%d",&sel) != 1)
 +    gmx_fatal(FARGS,"Answer me for res %s %d!",title,resnr+1);
 +  
 +  return name[sel];
 +}
 +
 +static const char *get_asptp(int resnr,int nrr,const rtprename_t *rr)
 +{
 +  enum { easp, easpH, easpNR };
 +  const char *lh[easpNR] = { "ASP", "ASPH" };
 +  const char *expl[easpNR] = {
 +    "Not protonated (charge -1)",
 +    "Protonated (charge 0)"
 +  };
 +
 +  return select_res(easpNR,resnr,lh,expl,"ASPARTIC ACID",nrr,rr);
 +}
 +
 +static const char *get_glutp(int resnr,int nrr,const rtprename_t *rr)
 +{
 +  enum { eglu, egluH, egluNR };
 +  const char *lh[egluNR] = { "GLU", "GLUH" };
 +  const char *expl[egluNR] = {
 +    "Not protonated (charge -1)",
 +    "Protonated (charge 0)"
 +  };
 +
 +  return select_res(egluNR,resnr,lh,expl,"GLUTAMIC ACID",nrr,rr);
 +}
 +
 +static const char *get_glntp(int resnr,int nrr,const rtprename_t *rr)
 +{
 +  enum { egln, eglnH, eglnNR };
 +  const char *lh[eglnNR] = { "GLN", "QLN" };
 +  const char *expl[eglnNR] = {
 +    "Not protonated (charge 0)",
 +    "Protonated (charge +1)"
 +  };
 +
 +  return select_res(eglnNR,resnr,lh,expl,"GLUTAMINE",nrr,rr);
 +}
 +
 +static const char *get_lystp(int resnr,int nrr,const rtprename_t *rr)
 +{
 +  enum { elys, elysH, elysNR };
 +  const  char *lh[elysNR] = { "LYSN", "LYS" };
 +  const char *expl[elysNR] = {
 +    "Not protonated (charge 0)",
 +    "Protonated (charge +1)"
 +  };
 +
 +  return select_res(elysNR,resnr,lh,expl,"LYSINE",nrr,rr);
 +}
 +
 +static const char *get_argtp(int resnr,int nrr,const rtprename_t *rr)
 +{
 +  enum { earg, eargH, eargNR };
 +  const  char *lh[eargNR] = { "ARGN", "ARG" };
 +  const char *expl[eargNR] = {
 +    "Not protonated (charge 0)",
 +    "Protonated (charge +1)"
 +  };
 +
 +  return select_res(eargNR,resnr,lh,expl,"ARGININE",nrr,rr);
 +}
 +
 +static const char *get_histp(int resnr,int nrr,const rtprename_t *rr)
 +{
 +  const char *expl[ehisNR] = {
 +    "H on ND1 only",
 +    "H on NE2 only",
 +    "H on ND1 and NE2",
 +    "Coupled to Heme"
 +  };
 +  
 +  return select_res(ehisNR,resnr,hh,expl,"HISTIDINE",nrr,rr);
 +}
 +
 +static void read_rtprename(const char *fname,FILE *fp,
 +                         int *nrtprename,rtprename_t **rtprename)
 +{
 +  char line[STRLEN],buf[STRLEN];
 +  int  n;
 +  rtprename_t *rr;
 +  int  ncol,nc;
 +
 +  n  = *nrtprename;
 +  rr = *rtprename;
 +
 +  ncol = 0;
 +  while(get_a_line(fp,line,STRLEN)) {
 +    srenew(rr,n+1);
 +    nc = sscanf(line,"%s %s %s %s %s %s",
 +              rr[n].gmx,rr[n].main,rr[n].nter,rr[n].cter,rr[n].bter,buf);
 +    if (ncol == 0) {
 +      if (nc != 2 && nc != 5) {
 +      gmx_fatal(FARGS,"Residue renaming database '%s' has %d columns instead of %d, %d or %d",fname,ncol,2,5);
 +      }
 +      ncol = nc;
 +    } else if (nc != ncol) {
 +      gmx_fatal(FARGS,"A line in residue renaming database '%s' has %d columns, while previous lines have %d columns",fname,nc,ncol);
 +    }
 +    
 +    if (nc == 2) {
 +      /* This file does not have special termini names, copy them from main */
 +      strcpy(rr[n].nter,rr[n].main);
 +      strcpy(rr[n].cter,rr[n].main);
 +      strcpy(rr[n].bter,rr[n].main);
 +    }
 +
 +    n++;
 +  }
 +
 +  *nrtprename = n;
 +  *rtprename  = rr;
 +}
 +
 +static char *search_resrename(int nrr,rtprename_t *rr,
 +                              const char *name,
 +                              gmx_bool bStart,gmx_bool bEnd,
 +                              gmx_bool bCompareFFRTPname)
 +{
 +    char *nn;
 +    int i;
 +
 +    nn = NULL;
 +
 +    i = 0;
 +    while (i<nrr && ((!bCompareFFRTPname && strcmp(name,rr[i].gmx)  != 0) ||
 +                     ( bCompareFFRTPname && strcmp(name,rr[i].main) != 0)))
 +    {
 +        i++;
 +    }
 +
 +    /* If found in the database, rename this residue's rtp building block,
 +     * otherwise keep the old name.
 +     */
 +    if (i < nrr)
 +    {
 +        if (bStart && bEnd)
 +        {
 +            nn = rr[i].bter;
 +        }
 +        else if (bStart)
 +        {
 +            nn = rr[i].nter;
 +        }
 +        else if (bEnd)
 +        {
 +            nn = rr[i].cter;
 +        }
 +        else
 +        {
 +            nn = rr[i].main;
 +        }
 +        if (nn[0] == '-')
 +        {
 +            gmx_fatal(FARGS,"In the chosen force field there is no residue type for '%s'%s",name,bStart ? " as a starting terminus" : (bEnd ? " as an ending terminus" : ""));
 +        }
 +    }
 +
 +    return nn;
 +}
 +      
 +
 +static void rename_resrtp(t_atoms *pdba,int nterpairs,int *r_start,int *r_end,
 +                          int nrr,rtprename_t *rr,t_symtab *symtab,
 +                          gmx_bool bVerbose)
 +{
 +    int  r,i,j;
 +    gmx_bool bStart,bEnd;
 +    char *nn;
 +    gmx_bool bFFRTPTERRNM;
 +
 +    bFFRTPTERRNM = (getenv("GMX_NO_FFRTP_TER_RENAME") == NULL);
 +
 +    for(r=0; r<pdba->nres; r++)
 +    {
 +        bStart = FALSE;
 +        bEnd   = FALSE;
 +        for(j=0; j<nterpairs; j++)
 +        {
 +            if (r == r_start[j])
 +            {
 +                bStart = TRUE;
 +            }
 +        }
 +        for(j=0; j<nterpairs; j++)
 +        {
 +            if (r == r_end[j])
 +            {
 +                bEnd = TRUE;
 +            }
 +        }
 +
 +        nn = search_resrename(nrr,rr,*pdba->resinfo[r].rtp,bStart,bEnd,FALSE);
 +
 +        if (bFFRTPTERRNM && nn == NULL && (bStart || bEnd))
 +        {
 +            /* This is a terminal residue, but the residue name,
 +             * currently stored in .rtp, is not a standard residue name,
 +             * but probably a force field specific rtp name.
 +             * Check if we need to rename it because it is terminal.
 +             */
 +            nn = search_resrename(nrr,rr,
 +                                  *pdba->resinfo[r].rtp,bStart,bEnd,TRUE);
 +        }
 +
 +        if (nn != NULL && strcmp(*pdba->resinfo[r].rtp,nn) != 0)
 +        {
 +            if (bVerbose)
 +            {
 +                printf("Changing rtp entry of residue %d %s to '%s'\n",
 +                       pdba->resinfo[r].nr,*pdba->resinfo[r].name,nn);
 +            }
 +            pdba->resinfo[r].rtp = put_symtab(symtab,nn);
 +        }
 +    }
 +}
 +
 +static void pdbres_to_gmxrtp(t_atoms *pdba)
 +{
 +    int i;
 +  
 +    for(i=0; (i<pdba->nres); i++)
 +    {
 +        if (pdba->resinfo[i].rtp == NULL)
 +        {
 +            pdba->resinfo[i].rtp = pdba->resinfo[i].name;
 +        }
 +    }
 +}
 +
 +static void rename_pdbres(t_atoms *pdba,const char *oldnm,const char *newnm,
 +                          gmx_bool bFullCompare,t_symtab *symtab)
 +{
 +    char *resnm;
 +    int i;
 +  
 +    for(i=0; (i<pdba->nres); i++)
 +    {
 +        resnm = *pdba->resinfo[i].name;
 +        if ((bFullCompare && (gmx_strcasecmp(resnm,oldnm) == 0)) ||
 +            (!bFullCompare && strstr(resnm,oldnm) != NULL))
 +        {
 +            /* Rename the residue name (not the rtp name) */
 +            pdba->resinfo[i].name = put_symtab(symtab,newnm);
 +        }
 +    }
 +}
 +
 +static void rename_bb(t_atoms *pdba,const char *oldnm,const char *newnm,
 +                      gmx_bool bFullCompare,t_symtab *symtab)
 +{
 +    char *bbnm;
 +    int i;
 +  
 +    for(i=0; (i<pdba->nres); i++)
 +    {
 +        /* We have not set the rtp name yes, use the residue name */
 +        bbnm = *pdba->resinfo[i].name;
 +        if ((bFullCompare && (gmx_strcasecmp(bbnm,oldnm) == 0)) ||
 +            (!bFullCompare && strstr(bbnm,oldnm) != NULL))
 +        {
 +            /* Change the rtp builing block name */
 +            pdba->resinfo[i].rtp = put_symtab(symtab,newnm);
 +        }
 +    }
 +}
 +
 +static void rename_bbint(t_atoms *pdba,const char *oldnm,
 +                         const char *gettp(int,int,const rtprename_t *),
 +                         gmx_bool bFullCompare,
 +                         t_symtab *symtab,
 +                         int nrr,const rtprename_t *rr)
 +{
 +    int  i;
 +    const char *ptr;
 +    char *bbnm;
 +  
 +    for(i=0; i<pdba->nres; i++)
 +    {
 +        /* We have not set the rtp name yes, use the residue name */
 +        bbnm = *pdba->resinfo[i].name;
 +        if ((bFullCompare && (strcmp(bbnm,oldnm) == 0)) ||
 +            (!bFullCompare && strstr(bbnm,oldnm) != NULL))
 +        {
 +            ptr = gettp(i,nrr,rr);
 +            pdba->resinfo[i].rtp = put_symtab(symtab,ptr);
 +        }
 +    }
 +}
 +
 +static void check_occupancy(t_atoms *atoms,const char *filename,gmx_bool bVerbose)
 +{
 +  int i,ftp;
 +  int nzero=0;
 +  int nnotone=0;
 +  
 +  ftp = fn2ftp(filename);
 +  if (!atoms->pdbinfo || ((ftp != efPDB) && (ftp != efBRK) && (ftp != efENT)))
 +    fprintf(stderr,"No occupancies in %s\n",filename);
 +  else {
 +    for(i=0; (i<atoms->nr); i++) {
 +      if (atoms->pdbinfo[i].occup != 1) {
 +      if (bVerbose)
 +        fprintf(stderr,"Occupancy for atom %s%d-%s is %f rather than 1\n",
 +                *atoms->resinfo[atoms->atom[i].resind].name,
 +                atoms->resinfo[ atoms->atom[i].resind].nr,
 +                *atoms->atomname[i],
 +                atoms->pdbinfo[i].occup);
 +      if (atoms->pdbinfo[i].occup == 0) 
 +        nzero++;
 +      else 
 +        nnotone++;
 +      }
 +    }
 +    if (nzero == atoms->nr) {
 +      fprintf(stderr,"All occupancy fields zero. This is probably not an X-Ray structure\n");
 +    } else if ((nzero > 0) || (nnotone > 0)) {
 +      fprintf(stderr,
 +            "\n"
 +            "WARNING: there were %d atoms with zero occupancy and %d atoms with\n"
 +            "         occupancy unequal to one (out of %d atoms). Check your pdb file.\n"
 +            "\n",
 +            nzero,nnotone,atoms->nr);
 +    } else {
 +      fprintf(stderr,"All occupancies are one\n");
 +    }
 +  }
 +}
 +
 +void write_posres(char *fn,t_atoms *pdba,real fc)
 +{
 +  FILE *fp;
 +  int  i;
 +  
 +  fp=gmx_fio_fopen(fn,"w");
 +  fprintf(fp,
 +        "; In this topology include file, you will find position restraint\n"
 +        "; entries for all the heavy atoms in your original pdb file.\n"
 +        "; This means that all the protons which were added by pdb2gmx are\n"
 +        "; not restrained.\n"
 +        "\n"
 +        "[ position_restraints ]\n"
 +        "; %4s%6s%8s%8s%8s\n","atom","type","fx","fy","fz"
 +        );
 +  for(i=0; (i<pdba->nr); i++) {
 +    if (!is_hydrogen(*pdba->atomname[i]) && !is_dummymass(*pdba->atomname[i]))
 +      fprintf(fp,"%6d%6d  %g  %g  %g\n",i+1,1,fc,fc,fc);
 +  }
 +  gmx_fio_fclose(fp);
 +}
 +
 +static int read_pdball(const char *inf, const char *outf,char *title,
 +                     t_atoms *atoms, rvec **x,
 +                     int *ePBC,matrix box, gmx_bool bRemoveH,
 +                     t_symtab *symtab,gmx_residuetype_t rt,const char *watres,
 +                     gmx_atomprop_t aps,gmx_bool bVerbose)
 +/* Read a pdb file. (containing proteins) */
 +{
 +  int  natom,new_natom,i;
 +  
 +  /* READ IT */
 +  printf("Reading %s...\n",inf);
 +  get_stx_coordnum(inf,&natom);
 +  init_t_atoms(atoms,natom,TRUE);
 +  snew(*x,natom);
 +  read_stx_conf(inf,title,atoms,*x,NULL,ePBC,box);
 +  if (fn2ftp(inf) == efPDB)
 +    get_pdb_atomnumber(atoms,aps);
 +  if (bRemoveH) {
 +    new_natom=0;
 +    for(i=0; i<atoms->nr; i++)
 +      if (!is_hydrogen(*atoms->atomname[i])) {
 +      atoms->atom[new_natom]=atoms->atom[i];
 +      atoms->atomname[new_natom]=atoms->atomname[i];
 +      atoms->pdbinfo[new_natom]=atoms->pdbinfo[i];
 +      copy_rvec((*x)[i],(*x)[new_natom]);
 +      new_natom++;
 +      }
 +    atoms->nr=new_natom;
 +    natom=new_natom;
 +  }
 +    
 +  printf("Read");
 +  if (title && title[0])
 +    printf(" '%s',",title);
 +  printf(" %d atoms\n",natom);
 +  
 +  /* Rename residues */
 +  rename_pdbres(atoms,"HOH",watres,FALSE,symtab);
 +  rename_pdbres(atoms,"SOL",watres,FALSE,symtab);
 +  rename_pdbres(atoms,"WAT",watres,FALSE,symtab);
 +
 +  rename_atoms("xlateat.dat",NULL,
 +             atoms,symtab,NULL,TRUE,rt,TRUE,bVerbose);
 +  
 +  if (natom == 0)
 +    return 0;
 +
 +  if (outf)
 +    write_sto_conf(outf,title,atoms,*x,NULL,*ePBC,box);
 + 
 +  return natom;
 +}
 +
 +void process_chain(t_atoms *pdba, rvec *x, 
 +                 gmx_bool bTrpU,gmx_bool bPheU,gmx_bool bTyrU,
 +                 gmx_bool bLysMan,gmx_bool bAspMan,gmx_bool bGluMan,
 +                 gmx_bool bHisMan,gmx_bool bArgMan,gmx_bool bGlnMan,
 +                 real angle,real distance,t_symtab *symtab,
 +                 int nrr,const rtprename_t *rr)
 +{
 +  /* Rename aromatics, lys, asp and histidine */
 +  if (bTyrU) rename_bb(pdba,"TYR","TYRU",FALSE,symtab);
 +  if (bTrpU) rename_bb(pdba,"TRP","TRPU",FALSE,symtab);
 +  if (bPheU) rename_bb(pdba,"PHE","PHEU",FALSE,symtab);
 +  if (bLysMan) 
 +    rename_bbint(pdba,"LYS",get_lystp,FALSE,symtab,nrr,rr);
 +  if (bArgMan) 
 +    rename_bbint(pdba,"ARG",get_argtp,FALSE,symtab,nrr,rr);
 +  if (bGlnMan) 
 +    rename_bbint(pdba,"GLN",get_glntp,FALSE,symtab,nrr,rr);
 +  if (bAspMan) 
 +    rename_bbint(pdba,"ASP",get_asptp,FALSE,symtab,nrr,rr);
 +  else
 +    rename_bb(pdba,"ASPH","ASP",FALSE,symtab);
 +  if (bGluMan) 
 +    rename_bbint(pdba,"GLU",get_glutp,FALSE,symtab,nrr,rr);
 +  else
 +    rename_bb(pdba,"GLUH","GLU",FALSE,symtab);
 +
 +  if (!bHisMan)
 +    set_histp(pdba,x,angle,distance);
 +  else
 +    rename_bbint(pdba,"HIS",get_histp,TRUE,symtab,nrr,rr);
 +
 +  /* Initialize the rtp builing block names with the residue names
 +   * for the residues that have not been processed above.
 +   */
 +  pdbres_to_gmxrtp(pdba);
 +
 +  /* Now we have all rtp names set.
 +   * The rtp names will conform to Gromacs naming,
 +   * unless the input pdb file contained one or more force field specific
 +   * rtp names as residue names.
 +   */
 +}
 +
 +/* struct for sorting the atoms from the pdb file */
 +typedef struct {
 +  int  resnr;  /* residue number               */
 +  int  j;      /* database order index         */
 +  int  index;  /* original atom number         */
 +  char anm1;   /* second letter of atom name   */
 +  char altloc; /* alternate location indicator */
 +} t_pdbindex;
 +  
 +int pdbicomp(const void *a,const void *b)
 +{
 +  t_pdbindex *pa,*pb;
 +  int d;
 +
 +  pa=(t_pdbindex *)a;
 +  pb=(t_pdbindex *)b;
 +
 +  d = (pa->resnr - pb->resnr);
 +  if (d==0) {
 +    d = (pa->j - pb->j);
 +    if (d==0) {
 +      d = (pa->anm1 - pb->anm1);
 +      if (d==0)
 +      d = (pa->altloc - pb->altloc);
 +    }
 +  }
 +
 +  return d;
 +}
 +
 +static void sort_pdbatoms(int nrtp,t_restp restp[],t_hackblock hb[],
 +                        int natoms,t_atoms **pdbaptr,rvec **x,
 +                        t_blocka *block,char ***gnames)
 +{
 +  t_atoms *pdba,*pdbnew;
 +  rvec **xnew;
 +  int     i,j;
 +  t_restp *rptr;
 +  t_hackblock *hbr;
 +  t_pdbindex *pdbi;
 +  atom_id *a;
 +  char *atomnm;
 +  
 +  pdba=*pdbaptr;
 +  natoms=pdba->nr;
 +  pdbnew=NULL;
 +  snew(xnew,1);
 +  snew(pdbi, natoms);
 +  
 +  for(i=0; i<natoms; i++)
 +  {
 +      atomnm = *pdba->atomname[i];
 +      rptr = &restp[pdba->atom[i].resind];
 +      for(j=0; (j<rptr->natom); j++) 
 +      {
 +          if (gmx_strcasecmp(atomnm,*(rptr->atomname[j])) == 0) 
 +          {
 +              break;
 +          }
 +      }
 +      if (j==rptr->natom) 
 +      {
 +          char buf[STRLEN];
 +          
 +          sprintf(buf,
 +                  "Atom %s in residue %s %d was not found in rtp entry %s with %d atoms\n"
 +                  "while sorting atoms.\n%s",atomnm,
 +                  *pdba->resinfo[pdba->atom[i].resind].name,
 +                  pdba->resinfo[pdba->atom[i].resind].nr,
 +                  rptr->resname,
 +                  rptr->natom,
 +                  is_hydrogen(atomnm) ? 
 +                  "\nFor a hydrogen, this can be a different protonation state, or it\n"
 +                  "might have had a different number in the PDB file and was rebuilt\n"
 +                  "(it might for instance have been H3, and we only expected H1 & H2).\n"
 +                  "Note that hydrogens might have been added to the entry for the N-terminus.\n"
 +                  "Remove this hydrogen or choose a different protonation state to solve it.\n"
 +                  "Option -ignh will ignore all hydrogens in the input." : ".");
 +          gmx_fatal(FARGS,buf);
 +      }
 +      /* make shadow array to be sorted into indexgroup */
 +      pdbi[i].resnr  = pdba->atom[i].resind;
 +      pdbi[i].j      = j;
 +      pdbi[i].index  = i;
 +      pdbi[i].anm1   = atomnm[1];
 +      pdbi[i].altloc = pdba->pdbinfo[i].altloc;
 +  }
 +  qsort(pdbi,natoms,(size_t)sizeof(pdbi[0]),pdbicomp);
 +    
 +  /* pdba is sorted in pdbnew using the pdbi index */ 
 +  snew(a,natoms);
 +  snew(pdbnew,1);
 +  init_t_atoms(pdbnew,natoms,TRUE);
 +  snew(*xnew,natoms);
 +  pdbnew->nr=pdba->nr;
 +  pdbnew->nres=pdba->nres;
 +  sfree(pdbnew->resinfo);
 +  pdbnew->resinfo=pdba->resinfo;
 +  for (i=0; i<natoms; i++) {
 +    pdbnew->atom[i]     = pdba->atom[pdbi[i].index];
 +    pdbnew->atomname[i] = pdba->atomname[pdbi[i].index];
 +    pdbnew->pdbinfo[i]  = pdba->pdbinfo[pdbi[i].index];
 +    copy_rvec((*x)[pdbi[i].index],(*xnew)[i]);
 +     /* make indexgroup in block */
 +    a[i]=pdbi[i].index;
 +  }
 +  /* clean up */
 +  sfree(pdba->atomname);
 +  sfree(pdba->atom);
 +  sfree(pdba->pdbinfo);
 +  sfree(pdba);
 +  sfree(*x);
 +  /* copy the sorted pdbnew back to pdba */
 +  *pdbaptr=pdbnew;
 +  *x=*xnew;
 +  add_grp(block, gnames, natoms, a, "prot_sort");
 +  sfree(xnew);
 +  sfree(a);
 +  sfree(pdbi);
 +}
 +
 +static int remove_duplicate_atoms(t_atoms *pdba,rvec x[],gmx_bool bVerbose)
 +{
 +  int     i,j,oldnatoms,ndel;
 +  t_resinfo *ri;
 +  
 +  printf("Checking for duplicate atoms....\n");
 +  oldnatoms    = pdba->nr;
 +  ndel = 0;
 +  /* NOTE: pdba->nr is modified inside the loop */
 +  for(i=1; (i < pdba->nr); i++) {
 +    /* compare 'i' and 'i-1', throw away 'i' if they are identical 
 +       this is a 'while' because multiple alternate locations can be present */
 +    while ( (i < pdba->nr) &&
 +          (pdba->atom[i-1].resind == pdba->atom[i].resind) &&
 +          (strcmp(*pdba->atomname[i-1],*pdba->atomname[i])==0) ) {
 +      ndel++;
 +      if (bVerbose) {
 +      ri = &pdba->resinfo[pdba->atom[i].resind];
 +      printf("deleting duplicate atom %4s  %s%4d%c",
 +             *pdba->atomname[i],*ri->name,ri->nr,ri->ic);
 +      if (ri->chainid && (ri->chainid != ' '))
 +        printf(" ch %c", ri->chainid);
 +      if (pdba->pdbinfo) {
 +        if (pdba->pdbinfo[i].atomnr)
 +          printf("  pdb nr %4d",pdba->pdbinfo[i].atomnr);
 +        if (pdba->pdbinfo[i].altloc && (pdba->pdbinfo[i].altloc!=' '))
 +          printf("  altloc %c",pdba->pdbinfo[i].altloc);
 +      }
 +      printf("\n");
 +      }
 +      pdba->nr--;
 +      /* We can not free, since it might be in the symtab */
 +      /* sfree(pdba->atomname[i]); */
 +      for (j=i; j < pdba->nr; j++) {
 +      pdba->atom[j]     = pdba->atom[j+1];
 +      pdba->atomname[j] = pdba->atomname[j+1];
 +      pdba->pdbinfo[j]  = pdba->pdbinfo[j+1];
 +      copy_rvec(x[j+1],x[j]);
 +      }
 +      srenew(pdba->atom,     pdba->nr);
 +      /* srenew(pdba->atomname, pdba->nr); */
 +      srenew(pdba->pdbinfo,  pdba->nr);
 +    }
 +  }
 +  if (pdba->nr != oldnatoms)
 +    printf("Now there are %d atoms. Deleted %d duplicates.\n",pdba->nr,ndel);
 +  
 +  return pdba->nr;
 +}
 +
 +void find_nc_ter(t_atoms *pdba,int r0,int r1,int *r_start,int *r_end,gmx_residuetype_t rt)
 +{
 +    int i;
 +    const char *p_startrestype;
 +    const char *p_restype;
 +    int         nstartwarn,nendwarn;
 +    
 +    *r_start = -1;
 +    *r_end   = -1;
 +
 +    nstartwarn = 0;
 +    nendwarn   = 0;
 +    
 +    /* Find the starting terminus (typially N or 5') */
 +    for(i=r0;i<r1 && *r_start==-1;i++)
 +    {
 +        gmx_residuetype_get_type(rt,*pdba->resinfo[i].name,&p_startrestype);
 +        if( !gmx_strcasecmp(p_startrestype,"Protein") || !gmx_strcasecmp(p_startrestype,"DNA") || !gmx_strcasecmp(p_startrestype,"RNA") )
 +        {
 +            printf("Identified residue %s%d as a starting terminus.\n",*pdba->resinfo[i].name,pdba->resinfo[i].nr);
 +            *r_start=i;
 +        }
 +        else 
 +        {            
 +            if(nstartwarn < 5)
 +            {    
 +                printf("Warning: Starting residue %s%d in chain not identified as Protein/RNA/DNA.\n",*pdba->resinfo[i].name,pdba->resinfo[i].nr);
 +            }
 +            if(nstartwarn == 5)
 +            {
 +                printf("More than 5 unidentified residues at start of chain - disabling further warnings.\n");
 +            }
 +            nstartwarn++;
 +        }
 +    }
 +
 +    if(*r_start>=0)
 +    {
 +        /* Go through the rest of the residues, check that they are the same class, and identify the ending terminus. */
 +        for(i=*r_start;i<r1;i++)
 +        {
 +            gmx_residuetype_get_type(rt,*pdba->resinfo[i].name,&p_restype);
 +            if( !gmx_strcasecmp(p_restype,p_startrestype) && nendwarn==0)
 +            {
 +                *r_end=i;
 +            }
 +            else 
 +            {
 +                if(nendwarn < 5)
 +                {    
 +                    printf("Warning: Residue %s%d in chain has different type (%s) from starting residue %s%d (%s).\n",
 +                           *pdba->resinfo[i].name,pdba->resinfo[i].nr,p_restype,
 +                           *pdba->resinfo[*r_start].name,pdba->resinfo[*r_start].nr,p_startrestype);
 +                }
 +                if(nendwarn == 5)
 +                {
 +                    printf("More than 5 unidentified residues at end of chain - disabling further warnings.\n");
 +                }
 +                nendwarn++;                
 +            }
 +        }  
 +    }
 +    
 +    if(*r_end>=0)
 +    {
 +        printf("Identified residue %s%d as a ending terminus.\n",*pdba->resinfo[*r_end].name,pdba->resinfo[*r_end].nr);
 +    }
 +}
 +
 +
 +static void
 +modify_chain_numbers(t_atoms *       pdba,
 +                     const char *    chainsep)
 +{
 +    int   i;
 +    char  old_prev_chainid;
 +    char  old_this_chainid;
 +    int   old_prev_chainnum;
 +    int   old_this_chainnum;
 +    t_resinfo *ri;
 +    char  select[STRLEN];
 +    int   new_chainnum;
 +    int           this_atomnum;
 +    int           prev_atomnum;
 +    const char *  prev_atomname;
 +    const char *  this_atomname;
 +    const char *  prev_resname;
 +    const char *  this_resname;
 +    int           prev_resnum;
 +    int           this_resnum;
 +    char          prev_chainid;
 +    char          this_chainid;
 +    int           prev_chainnumber;
 +    int           this_chainnumber;
 +   
 +    enum 
 +    { 
 +        SPLIT_ID_OR_TER, 
 +        SPLIT_ID_AND_TER,
 +        SPLIT_ID_ONLY,
 +        SPLIT_TER_ONLY,
 +        SPLIT_INTERACTIVE
 +    }
 +    splitting;
 +    
 +    splitting = SPLIT_TER_ONLY; /* keep compiler happy */
 +    
 +    /* Be a bit flexible to catch typos */
 +    if (!strncmp(chainsep,"id_o",4))
 +    {
 +        /* For later interactive splitting we tentatively assign new chain numbers at either changing id or ter records */
 +        splitting = SPLIT_ID_OR_TER;
 +        printf("Splitting chemical chains based on TER records or chain id changing.\n");
 +    }
 +    else if (!strncmp(chainsep,"int",3))
 +    {
 +        /* For later interactive splitting we tentatively assign new chain numbers at either changing id or ter records */
 +        splitting = SPLIT_INTERACTIVE;
 +        printf("Splitting chemical chains interactively.\n");
 +    }
 +    else if (!strncmp(chainsep,"id_a",4))
 +    {
 +        splitting = SPLIT_ID_AND_TER;
 +        printf("Splitting chemical chains based on TER records and chain id changing.\n");
 +    }
 +    else if (strlen(chainsep)==2 && !strncmp(chainsep,"id",4))
 +    {
 +        splitting = SPLIT_ID_ONLY;
 +        printf("Splitting chemical chains based on changing chain id only (ignoring TER records).\n");
 +    }
 +    else if (chainsep[0]=='t')
 +    {
 +        splitting = SPLIT_TER_ONLY;
 +        printf("Splitting chemical chains based on TER records only (ignoring chain id).\n");
 +    }
 +    else
 +    {
 +        gmx_fatal(FARGS,"Unidentified setting for chain separation: %s\n",chainsep);
 +    }                                                                           
 +                                                                                   
 +    /* The default chain enumeration is based on TER records only, which is reflected in chainnum below */
 +    
 +    old_prev_chainid  = '?';
 +    old_prev_chainnum = -1;
 +    new_chainnum  = -1;
 +    
 +    this_atomname       = NULL;
 +    this_atomnum        = -1;
 +    this_resname        = NULL;
 +    this_resnum         = -1;
 +    this_chainid        = '?';
 +    this_chainnumber    = -1;
 +
 +    for(i=0;i<pdba->nres;i++)
 +    {
 +        ri = &pdba->resinfo[i];
 +        old_this_chainid   = ri->chainid;
 +        old_this_chainnum  = ri->chainnum;
 +
 +        prev_atomname      = this_atomname;
 +        prev_atomnum       = this_atomnum;
 +        prev_resname       = this_resname;
 +        prev_resnum        = this_resnum;
 +        prev_chainid       = this_chainid;
 +        prev_chainnumber   = this_chainnumber;
 +
 +        this_atomname      = *(pdba->atomname[i]);
 +        this_atomnum       = (pdba->pdbinfo != NULL) ? pdba->pdbinfo[i].atomnr : i+1;
 +        this_resname       = *ri->name;
 +        this_resnum        = ri->nr;
 +        this_chainid       = ri->chainid;
 +        this_chainnumber   = ri->chainnum;
 +
 +        switch (splitting)
 +        {
 +            case SPLIT_ID_OR_TER:
 +                if(old_this_chainid != old_prev_chainid || old_this_chainnum != old_prev_chainnum)
 +                {
 +                    new_chainnum++;
 +                }
 +                break;
 +                
 +            case SPLIT_ID_AND_TER:
 +                if(old_this_chainid != old_prev_chainid && old_this_chainnum != old_prev_chainnum)
 +                {
 +                    new_chainnum++;
 +                }
 +                break;
 +                
 +            case SPLIT_ID_ONLY:
 +                if(old_this_chainid != old_prev_chainid)
 +                {
 +                    new_chainnum++;
 +                }
 +                break;
 +                
 +            case SPLIT_TER_ONLY:
 +                if(old_this_chainnum != old_prev_chainnum)
 +                {
 +                    new_chainnum++;
 +                }
 +                break;
 +            case SPLIT_INTERACTIVE:
 +                if(old_this_chainid != old_prev_chainid || old_this_chainnum != old_prev_chainnum)
 +                {
 +                    if(i>0)
 +                    {
 +                        printf("Split the chain (and introduce termini) between residue %s%d (chain id '%c', atom %d %s)\n" 
 +                               "and residue %s%d (chain id '%c', atom %d %s) ? [n/y]\n",
 +                               prev_resname,prev_resnum,prev_chainid,prev_atomnum,prev_atomname,
 +                               this_resname,this_resnum,this_chainid,this_atomnum,this_atomname);
 +                        
 +                        if(NULL==fgets(select,STRLEN-1,stdin))
 +                        {
 +                            gmx_fatal(FARGS,"Error reading from stdin");
 +                        }
 +                    }
 +                    if(i==0 || select[0] == 'y')
 +                    {
 +                        new_chainnum++;
 +                    }
 +                }               
 +                break;
 +            default:
 +                gmx_fatal(FARGS,"Internal inconsistency - this shouldn't happen...");
 +                break;
 +        }
 +        old_prev_chainid  = old_this_chainid;
 +        old_prev_chainnum = old_this_chainnum;
 +                                                                                   
 +        ri->chainnum = new_chainnum;        
 +    }
 +}
 +
 +
 +typedef struct {
 +  char chainid;
 +  char chainnum;
 +  int  start;
 +  int  natom;
 +  gmx_bool bAllWat;
 +  int  nterpairs;
 +  int  *chainstart;
 +} t_pdbchain;
 +
 +typedef struct {
 +  char chainid;
 +  int  chainnum;
 +  gmx_bool bAllWat;
 +  int nterpairs;
 +  int *chainstart;
 +  t_hackblock **ntdb;
 +  t_hackblock **ctdb;
 +  int *r_start;
 +  int *r_end;
 +  t_atoms *pdba;
 +  rvec *x;
 +} t_chain;
 +
++int cmain(int argc, char *argv[])
 +{
 +  const char *desc[] = {
 +    "This program reads a [TT].pdb[tt] (or [TT].gro[tt]) file, reads",
 +    "some database files, adds hydrogens to the molecules and generates",
 +    "coordinates in GROMACS (GROMOS), or optionally [TT].pdb[tt], format",
 +    "and a topology in GROMACS format.",
 +    "These files can subsequently be processed to generate a run input file.",
 +    "[PAR]",
 +    "[TT]pdb2gmx[tt] will search for force fields by looking for",
 +    "a [TT]forcefield.itp[tt] file in subdirectories [TT]<forcefield>.ff[tt]",
 +    "of the current working directory and of the GROMACS library directory",
 +    "as inferred from the path of the binary or the [TT]GMXLIB[tt] environment",
 +    "variable.",
 +    "By default the forcefield selection is interactive,",
 +    "but you can use the [TT]-ff[tt] option to specify one of the short names",
 +    "in the list on the command line instead. In that case [TT]pdb2gmx[tt] just looks",
 +    "for the corresponding [TT]<forcefield>.ff[tt] directory.",
 +    "[PAR]",
 +    "After choosing a force field, all files will be read only from",
 +    "the corresponding force field directory.",
 +    "If you want to modify or add a residue types, you can copy the force",
 +    "field directory from the GROMACS library directory to your current",
 +    "working directory. If you want to add new protein residue types,",
 +    "you will need to modify [TT]residuetypes.dat[tt] in the library directory",
 +    "or copy the whole library directory to a local directory and set",
 +    "the environment variable [TT]GMXLIB[tt] to the name of that directory.",
 +    "Check Chapter 5 of the manual for more information about file formats.",
 +    "[PAR]",
 +    
 +    "Note that a [TT].pdb[tt] file is nothing more than a file format, and it",
 +    "need not necessarily contain a protein structure. Every kind of",
 +    "molecule for which there is support in the database can be converted.",
 +    "If there is no support in the database, you can add it yourself.[PAR]",
 +    
 +    "The program has limited intelligence, it reads a number of database",
 +    "files, that allow it to make special bonds (Cys-Cys, Heme-His, etc.),",
 +    "if necessary this can be done manually. The program can prompt the",
 +    "user to select which kind of LYS, ASP, GLU, CYS or HIS residue is",
 +    "desired. For Lys the choice is between neutral (two protons on NZ) or",
 +    "protonated (three protons, default), for Asp and Glu unprotonated",
 +    "(default) or protonated, for His the proton can be either on ND1,",
 +    "on NE2 or on both. By default these selections are done automatically.",
 +    "For His, this is based on an optimal hydrogen bonding",
 +    "conformation. Hydrogen bonds are defined based on a simple geometric",
 +    "criterion, specified by the maximum hydrogen-donor-acceptor angle",
 +    "and donor-acceptor distance, which are set by [TT]-angle[tt] and",
 +    "[TT]-dist[tt] respectively.[PAR]",
 +     
 +    "The protonation state of N- and C-termini can be chosen interactively",
 +    "with the [TT]-ter[tt] flag.  Default termini are ionized (NH3+ and COO-),",
 +    "respectively.  Some force fields support zwitterionic forms for chains of",
 +    "one residue, but for polypeptides these options should NOT be selected.",
 +    "The AMBER force fields have unique forms for the terminal residues,",
 +    "and these are incompatible with the [TT]-ter[tt] mechanism. You need",
 +    "to prefix your N- or C-terminal residue names with \"N\" or \"C\"",
 +    "respectively to use these forms, making sure you preserve the format",
 +    "of the coordinate file. Alternatively, use named terminating residues",
 +    "(e.g. ACE, NME).[PAR]",
 +
 +    "The separation of chains is not entirely trivial since the markup",
 +    "in user-generated PDB files frequently varies and sometimes it",
 +    "is desirable to merge entries across a TER record, for instance",
 +    "if you want a disulfide bridge or distance restraints between",
 +    "two protein chains or if you have a HEME group bound to a protein.",
 +    "In such cases multiple chains should be contained in a single",
 +    "[TT]moleculetype[tt] definition.",
 +    "To handle this, [TT]pdb2gmx[tt] uses two separate options.",
 +    "First, [TT]-chainsep[tt] allows you to choose when a new chemical chain should",
 +    "start, and termini added when applicable. This can be done based on the",
 +    "existence of TER records, when the chain id changes, or combinations of either",
 +    "or both of these. You can also do the selection fully interactively.",
 +    "In addition, there is a [TT]-merge[tt] option that controls how multiple chains",
 +    "are merged into one moleculetype, after adding all the chemical termini (or not).",
 +    "This can be turned off (no merging), all non-water chains can be merged into a",
 +    "single molecule, or the selection can be done interactively.[PAR]",
 +      
 +    "[TT]pdb2gmx[tt] will also check the occupancy field of the [TT].pdb[tt] file.",
 +    "If any of the occupancies are not one, indicating that the atom is",
 +    "not resolved well in the structure, a warning message is issued.",
 +    "When a [TT].pdb[tt] file does not originate from an X-ray structure determination",
 +    "all occupancy fields may be zero. Either way, it is up to the user",
 +    "to verify the correctness of the input data (read the article!).[PAR]", 
 +    
 +    "During processing the atoms will be reordered according to GROMACS",
 +    "conventions. With [TT]-n[tt] an index file can be generated that",
 +    "contains one group reordered in the same way. This allows you to",
 +    "convert a GROMOS trajectory and coordinate file to GROMOS. There is",
 +    "one limitation: reordering is done after the hydrogens are stripped",
 +    "from the input and before new hydrogens are added. This means that",
 +    "you should not use [TT]-ignh[tt].[PAR]",
 +
 +    "The [TT].gro[tt] and [TT].g96[tt] file formats do not support chain",
 +    "identifiers. Therefore it is useful to enter a [TT].pdb[tt] file name at",
 +    "the [TT]-o[tt] option when you want to convert a multi-chain [TT].pdb[tt] file.",
 +    "[PAR]",
 +    
 +    "The option [TT]-vsite[tt] removes hydrogen and fast improper dihedral",
 +    "motions. Angular and out-of-plane motions can be removed by changing",
 +    "hydrogens into virtual sites and fixing angles, which fixes their",
 +    "position relative to neighboring atoms. Additionally, all atoms in the",
 +    "aromatic rings of the standard amino acids (i.e. PHE, TRP, TYR and HIS)",
 +    "can be converted into virtual sites, eliminating the fast improper dihedral",
 +    "fluctuations in these rings. [BB]Note[bb] that in this case all other hydrogen",
 +    "atoms are also converted to virtual sites. The mass of all atoms that are",
 +    "converted into virtual sites, is added to the heavy atoms.[PAR]",
 +    "Also slowing down of dihedral motion can be done with [TT]-heavyh[tt]",
 +    "done by increasing the hydrogen-mass by a factor of 4. This is also",
 +    "done for water hydrogens to slow down the rotational motion of water.",
 +    "The increase in mass of the hydrogens is subtracted from the bonded",
 +    "(heavy) atom so that the total mass of the system remains the same."
 +  };
 +
 +  
 +  FILE       *fp,*top_file,*top_file2,*itp_file=NULL;
 +  int        natom,nres;
 +  t_atoms    pdba_all,*pdba;
 +  t_atoms    *atoms;
 +  t_resinfo  *ri;
 +  t_blocka   *block;
 +  int        chain,nch,maxch,nwaterchain;
 +  t_pdbchain *pdb_ch;
 +  t_chain    *chains,*cc;
 +  char       select[STRLEN];
 +  int        nincl,nmol;
 +  char       **incls;
 +  t_mols     *mols;
 +  char       **gnames;
 +  int        ePBC;
 +  matrix     box;
 +  rvec       box_space;
 +  int        i,j,k,l,nrtp;
 +  int        *swap_index,si;
 +  t_restp    *restp;
 +  t_hackblock *ah;
 +  t_symtab   symtab;
 +  gpp_atomtype_t atype;
 +  gmx_residuetype_t rt;
 +  const char *top_fn;
 +  char       fn[256],itp_fn[STRLEN],posre_fn[STRLEN],buf_fn[STRLEN];
 +  char       molname[STRLEN],title[STRLEN],quote[STRLEN],generator[STRLEN];
 +  char       *c,forcefield[STRLEN],ffdir[STRLEN];
 +  char       ffname[STRLEN],suffix[STRLEN],buf[STRLEN];
 +  char       *watermodel;
 +  const char *watres;
 +  int        nrtpf;
 +  char       **rtpf;
 +  char       rtp[STRLEN];
 +  int        nrrn;
 +  char       **rrn;
 +  int        nrtprename,naa;
 +  rtprename_t *rtprename=NULL;
 +  int        nah,nNtdb,nCtdb,ntdblist;
 +  t_hackblock *ntdb,*ctdb,**tdblist;
 +  int        nssbonds;
 +  t_ssbond   *ssbonds;
 +  rvec       *pdbx,*x;
 +  gmx_bool       bVsites=FALSE,bWat,bPrevWat=FALSE,bITP,bVsiteAromatics=FALSE,bCheckMerge;
 +  real       mHmult=0;
 +  t_hackblock *hb_chain;
 +  t_restp    *restp_chain;
 +  output_env_t oenv;
 +  const char *p_restype;
 +  int        rc;
 +  int           this_atomnum;
 +  int           prev_atomnum;
 +  const char *  prev_atomname;
 +  const char *  this_atomname;
 +  const char *  prev_resname;
 +  const char *  this_resname;
 +  int           prev_resnum;
 +  int           this_resnum;
 +  char          prev_chainid;
 +  char          this_chainid;
 +  int           prev_chainnumber;
 +  int           this_chainnumber;
 +  int           nid_used;
 +  int           this_chainstart;
 +  int           prev_chainstart;
 +  gmx_bool      bMerged;
 +  int           nchainmerges;
 +    
 +  gmx_atomprop_t aps;
 +  
 +  t_filenm   fnm[] = { 
 +    { efSTX, "-f", "eiwit.pdb", ffREAD  },
 +    { efSTO, "-o", "conf",      ffWRITE },
 +    { efTOP, NULL, NULL,        ffWRITE },
 +    { efITP, "-i", "posre",     ffWRITE },
 +    { efNDX, "-n", "clean",     ffOPTWR },
 +    { efSTO, "-q", "clean.pdb", ffOPTWR }
 +  };
 +#define NFILE asize(fnm)
 + 
 +
 +  /* Command line arguments must be static */
 +  static gmx_bool bNewRTP=FALSE;
 +  static gmx_bool bInter=FALSE, bCysMan=FALSE; 
 +  static gmx_bool bLysMan=FALSE, bAspMan=FALSE, bGluMan=FALSE, bHisMan=FALSE;
 +  static gmx_bool bGlnMan=FALSE, bArgMan=FALSE;
 +  static gmx_bool bTerMan=FALSE, bUnA=FALSE, bHeavyH;
 +  static gmx_bool bSort=TRUE, bAllowMissing=FALSE, bRemoveH=FALSE;
 +  static gmx_bool bDeuterate=FALSE,bVerbose=FALSE,bChargeGroups=TRUE,bCmap=TRUE;
 +  static gmx_bool bRenumRes=FALSE,bRTPresname=FALSE;
 +  static real angle=135.0, distance=0.3,posre_fc=1000;
 +  static real long_bond_dist=0.25, short_bond_dist=0.05;
 +  static const char *vsitestr[] = { NULL, "none", "hydrogens", "aromatics", NULL };
 +  static const char *watstr[] = { NULL, "select", "none", "spc", "spce", "tip3p", "tip4p", "tip5p", NULL };
 +  static const char *chainsep[] = { NULL, "id_or_ter", "id_and_ter", "ter", "id", "interactive", NULL };
 +  static const char *merge[] = {NULL, "no", "all", "interactive", NULL };
 +  static const char *ff = "select";
 +
 +  t_pargs pa[] = {
 +    { "-newrtp", FALSE, etBOOL, {&bNewRTP},
 +      "HIDDENWrite the residue database in new format to [TT]new.rtp[tt]"},
 +    { "-lb",     FALSE, etREAL, {&long_bond_dist},
 +      "HIDDENLong bond warning distance" },
 +    { "-sb",     FALSE, etREAL, {&short_bond_dist},
 +      "HIDDENShort bond warning distance" },
 +    { "-chainsep", FALSE, etENUM, {chainsep},
 +      "Condition in PDB files when a new chain should be started (adding termini)" },
 +    { "-merge",  FALSE, etENUM, {&merge},
 +      "Merge multiple chains into a single [moleculetype]" },         
 +    { "-ff",     FALSE, etSTR,  {&ff},
 +      "Force field, interactive by default. Use [TT]-h[tt] for information." },
 +    { "-water",  FALSE, etENUM, {watstr},
 +      "Water model to use" },
 +    { "-inter",  FALSE, etBOOL, {&bInter},
 +      "Set the next 8 options to interactive"},
 +    { "-ss",     FALSE, etBOOL, {&bCysMan}, 
 +      "Interactive SS bridge selection" },
 +    { "-ter",    FALSE, etBOOL, {&bTerMan}, 
 +      "Interactive termini selection, instead of charged (default)" },
 +    { "-lys",    FALSE, etBOOL, {&bLysMan}, 
 +      "Interactive lysine selection, instead of charged" },
 +    { "-arg",    FALSE, etBOOL, {&bArgMan}, 
 +      "Interactive arginine selection, instead of charged" },
 +    { "-asp",    FALSE, etBOOL, {&bAspMan}, 
 +      "Interactive aspartic acid selection, instead of charged" },
 +    { "-glu",    FALSE, etBOOL, {&bGluMan}, 
 +      "Interactive glutamic acid selection, instead of charged" },
 +    { "-gln",    FALSE, etBOOL, {&bGlnMan}, 
 +      "Interactive glutamine selection, instead of neutral" },
 +    { "-his",    FALSE, etBOOL, {&bHisMan},
 +      "Interactive histidine selection, instead of checking H-bonds" },
 +    { "-angle",  FALSE, etREAL, {&angle}, 
 +      "Minimum hydrogen-donor-acceptor angle for a H-bond (degrees)" },
 +    { "-dist",   FALSE, etREAL, {&distance},
 +      "Maximum donor-acceptor distance for a H-bond (nm)" },
 +    { "-una",    FALSE, etBOOL, {&bUnA}, 
 +      "Select aromatic rings with united CH atoms on phenylalanine, "
 +      "tryptophane and tyrosine" },
 +    { "-sort",   FALSE, etBOOL, {&bSort}, 
 +      "HIDDENSort the residues according to database, turning this off is dangerous as charge groups might be broken in parts" },
 +    { "-ignh",   FALSE, etBOOL, {&bRemoveH}, 
 +      "Ignore hydrogen atoms that are in the coordinate file" },
 +    { "-missing",FALSE, etBOOL, {&bAllowMissing}, 
 +      "Continue when atoms are missing, dangerous" },
 +    { "-v",      FALSE, etBOOL, {&bVerbose}, 
 +      "Be slightly more verbose in messages" },
 +    { "-posrefc",FALSE, etREAL, {&posre_fc},
 +      "Force constant for position restraints" },
 +    { "-vsite",  FALSE, etENUM, {vsitestr}, 
 +      "Convert atoms to virtual sites" },
 +    { "-heavyh", FALSE, etBOOL, {&bHeavyH},
 +      "Make hydrogen atoms heavy" },
 +    { "-deuterate", FALSE, etBOOL, {&bDeuterate},
 +      "Change the mass of hydrogens to 2 amu" },
 +    { "-chargegrp", TRUE, etBOOL, {&bChargeGroups},
 +      "Use charge groups in the [TT].rtp[tt] file"  },
 +    { "-cmap", TRUE, etBOOL, {&bCmap},
 +      "Use cmap torsions (if enabled in the [TT].rtp[tt] file)"  },
 +    { "-renum", TRUE, etBOOL, {&bRenumRes},
 +      "Renumber the residues consecutively in the output"  },
 +    { "-rtpres", TRUE, etBOOL, {&bRTPresname},
 +      "Use [TT].rtp[tt] entry names as residue names"  }
 +  };
 +#define NPARGS asize(pa)
 +  
 +  CopyRight(stderr,argv[0]);
 +  parse_common_args(&argc,argv,0,NFILE,fnm,asize(pa),pa,asize(desc),desc,
 +                  0,NULL,&oenv);
 +
 +  /* Force field selection, interactive or direct */
 +  choose_ff(strcmp(ff,"select") == 0 ? NULL : ff,
 +          forcefield,sizeof(forcefield),
 +          ffdir,sizeof(ffdir));
 +
 +  if (strlen(forcefield) > 0) {
 +    strcpy(ffname,forcefield);
 +    ffname[0] = toupper(ffname[0]);
 +  } else {
 +    gmx_fatal(FARGS,"Empty forcefield string");
 +  }
 +  
 +  printf("\nUsing the %s force field in directory %s\n\n",
 +       ffname,ffdir);
 +    
 +  choose_watermodel(watstr[0],ffdir,&watermodel);
 +
 +  if (bInter) {
 +    /* if anything changes here, also change description of -inter */
 +    bCysMan = TRUE;
 +    bTerMan = TRUE;
 +    bLysMan = TRUE;
 +    bArgMan = TRUE;
 +    bAspMan = TRUE;
 +    bGluMan = TRUE;
 +    bGlnMan = TRUE;
 +    bHisMan = TRUE;
 +  }
 +  
 +  if (bHeavyH)
 +    mHmult=4.0;
 +  else if (bDeuterate)
 +    mHmult=2.0;
 +  else
 +    mHmult=1.0;
 +  
 +  switch(vsitestr[0][0]) {
 +  case 'n': /* none */
 +    bVsites=FALSE;
 +    bVsiteAromatics=FALSE;
 +    break;
 +  case 'h': /* hydrogens */
 +    bVsites=TRUE;
 +    bVsiteAromatics=FALSE;
 +    break;
 +  case 'a': /* aromatics */
 +    bVsites=TRUE;
 +    bVsiteAromatics=TRUE;
 +    break;
 +  default:
 +    gmx_fatal(FARGS,"DEATH HORROR in $s (%d): vsitestr[0]='%s'",
 +              __FILE__,__LINE__,vsitestr[0]);
 +  }/* end switch */
 +  
 +  /* Open the symbol table */
 +  open_symtab(&symtab);
 +
 +  /* Residue type database */  
 +  gmx_residuetype_init(&rt);
 +  
 +  /* Read residue renaming database(s), if present */
 +  nrrn = fflib_search_file_end(ffdir,".r2b",FALSE,&rrn);
 +    
 +  nrtprename = 0;
 +  rtprename  = NULL;
 +  for(i=0; i<nrrn; i++) {
 +    fp = fflib_open(rrn[i]);
 +    read_rtprename(rrn[i],fp,&nrtprename,&rtprename);
 +    ffclose(fp);
 +    sfree(rrn[i]);
 +  }
 +  sfree(rrn);
 +
 +  /* Add all alternative names from the residue renaming database to the list of recognized amino/nucleic acids. */
 +  naa=0;
 +  for(i=0;i<nrtprename;i++)
 +  {
 +      rc=gmx_residuetype_get_type(rt,rtprename[i].gmx,&p_restype);
 +
 +      /* Only add names if the 'standard' gromacs/iupac base name was found */
 +      if(rc==0)
 +      {
 +          gmx_residuetype_add(rt,rtprename[i].main,p_restype);
 +          gmx_residuetype_add(rt,rtprename[i].nter,p_restype);
 +          gmx_residuetype_add(rt,rtprename[i].cter,p_restype);
 +          gmx_residuetype_add(rt,rtprename[i].bter,p_restype);
 +      }          
 +  }
 +    
 +  clear_mat(box);
 +  if (watermodel != NULL && (strstr(watermodel,"4p") ||
 +                           strstr(watermodel,"4P"))) {
 +    watres = "HO4";
 +  } else if (watermodel != NULL && (strstr(watermodel,"5p") ||
 +                                  strstr(watermodel,"5P"))) {
 +    watres = "HO5";
 +  } else {
 +    watres = "HOH";
 +  }
 +    
 +  aps = gmx_atomprop_init();
 +  natom = read_pdball(opt2fn("-f",NFILE,fnm),opt2fn_null("-q",NFILE,fnm),title,
 +                    &pdba_all,&pdbx,&ePBC,box,bRemoveH,&symtab,rt,watres,
 +                    aps,bVerbose);
 +  
 +  if (natom==0)
 +    gmx_fatal(FARGS,"No atoms found in pdb file %s\n",opt2fn("-f",NFILE,fnm));
 +
 +  printf("Analyzing pdb file\n");
 +  nch=0;
 +  maxch=0;
 +  nwaterchain=0;
 +    
 +  modify_chain_numbers(&pdba_all,chainsep[0]);
 +
 +  nchainmerges        = 0;
 +    
 +  this_atomname       = NULL;
 +  this_atomnum        = -1;
 +  this_resname        = NULL;
 +  this_resnum         = -1;
 +  this_chainid        = '?';
 +  this_chainnumber    = -1;
 +  this_chainstart     = 0;
 +  /* Keep the compiler happy */
 +  prev_chainstart     = 0;
 +    
 +  pdb_ch=NULL;
 +
 +  bMerged = FALSE;
 +  for (i=0; (i<natom); i++) 
 +  {
 +      ri = &pdba_all.resinfo[pdba_all.atom[i].resind];
 +
 +      prev_atomname      = this_atomname;
 +      prev_atomnum       = this_atomnum;
 +      prev_resname       = this_resname;
 +      prev_resnum        = this_resnum;
 +      prev_chainid       = this_chainid;
 +      prev_chainnumber   = this_chainnumber;
 +      if (!bMerged)
 +      {
 +          prev_chainstart    = this_chainstart;
 +      }
 +      
 +      this_atomname      = *pdba_all.atomname[i];
 +      this_atomnum       = (pdba_all.pdbinfo != NULL) ? pdba_all.pdbinfo[i].atomnr : i+1;
 +      this_resname       = *ri->name;
 +      this_resnum        = ri->nr;
 +      this_chainid       = ri->chainid;
 +      this_chainnumber   = ri->chainnum;
 +      
 +      bWat = gmx_strcasecmp(*ri->name,watres) == 0;
 +      if ((i == 0) || (this_chainnumber != prev_chainnumber) || (bWat != bPrevWat)) 
 +      {
 +          this_chainstart = pdba_all.atom[i].resind;
 +          
 +          bMerged = FALSE;
 +          if (i>0 && !bWat) 
 +          {
 +              if(!strncmp(merge[0],"int",3))
 +              {
 +                  printf("Merge chain ending with residue %s%d (chain id '%c', atom %d %s) and chain starting with\n"
 +                         "residue %s%d (chain id '%c', atom %d %s) into a single moleculetype (keeping termini)? [n/y]\n",
 +                         prev_resname,prev_resnum,prev_chainid,prev_atomnum,prev_atomname,
 +                         this_resname,this_resnum,this_chainid,this_atomnum,this_atomname);
 +                  
 +                  if(NULL==fgets(select,STRLEN-1,stdin))
 +                  {
 +                      gmx_fatal(FARGS,"Error reading from stdin");
 +                  }
 +                  bMerged = (select[0] == 'y');
 +              }
 +              else if(!strncmp(merge[0],"all",3))
 +              {
 +                  bMerged = TRUE;
 +              }
 +          }
 +          
 +          if (bMerged)
 +          { 
 +              pdb_ch[nch-1].chainstart[pdb_ch[nch-1].nterpairs] = 
 +              pdba_all.atom[i].resind - prev_chainstart;
 +              pdb_ch[nch-1].nterpairs++;
 +              srenew(pdb_ch[nch-1].chainstart,pdb_ch[nch-1].nterpairs+1);
 +              nchainmerges++;
 +          }
 +          else 
 +          {
 +              /* set natom for previous chain */
 +              if (nch > 0)
 +              {
 +                  pdb_ch[nch-1].natom=i-pdb_ch[nch-1].start;
 +              }
 +              if (bWat)
 +              {
 +                  nwaterchain++;
 +                  ri->chainid = ' ';
 +              }
 +              /* check if chain identifier was used before */
 +              for (j=0; (j<nch); j++) 
 +              {
 +                  if (pdb_ch[j].chainid != ' ' && pdb_ch[j].chainid == ri->chainid) 
 +                  {
 +                      printf("WARNING: Chain identifier '%c' is used in two non-sequential blocks.\n"
 +                             "They will be treated as separate chains unless you reorder your file.\n",
 +                             ri->chainid);
 +                  }
 +              }
 +              if (nch == maxch)
 +              {
 +                  maxch += 16;
 +                  srenew(pdb_ch,maxch);
 +              }
 +              pdb_ch[nch].chainid = ri->chainid;
 +              pdb_ch[nch].chainnum = ri->chainnum; 
 +              pdb_ch[nch].start=i;
 +              pdb_ch[nch].bAllWat=bWat;
 +              if (bWat)
 +                  pdb_ch[nch].nterpairs=0;
 +              else
 +                  pdb_ch[nch].nterpairs=1;
 +              snew(pdb_ch[nch].chainstart,pdb_ch[nch].nterpairs+1);
 +              /* modified [nch] to [0] below */
 +              pdb_ch[nch].chainstart[0]=0;
 +              nch++;
 +          }
 +      }
 +      bPrevWat=bWat;
 +  }
 +  pdb_ch[nch-1].natom=natom-pdb_ch[nch-1].start;
 +  
 +  /* set all the water blocks at the end of the chain */
 +  snew(swap_index,nch);
 +  j=0;
 +  for(i=0; i<nch; i++)
 +    if (!pdb_ch[i].bAllWat) {
 +      swap_index[j]=i;
 +      j++;
 +    }
 +  for(i=0; i<nch; i++)
 +    if (pdb_ch[i].bAllWat) {
 +      swap_index[j]=i;
 +      j++;
 +    }
 +  if (nwaterchain>1)
 +    printf("Moved all the water blocks to the end\n");
 +
 +  snew(chains,nch);
 +  /* copy pdb data and x for all chains */
 +  for (i=0; (i<nch); i++) {
 +    si=swap_index[i];
 +    chains[i].chainid = pdb_ch[si].chainid;
 +    chains[i].chainnum = pdb_ch[si].chainnum;
 +    chains[i].bAllWat = pdb_ch[si].bAllWat;
 +    chains[i].nterpairs = pdb_ch[si].nterpairs;
 +    chains[i].chainstart = pdb_ch[si].chainstart;
 +    snew(chains[i].ntdb,pdb_ch[si].nterpairs);
 +    snew(chains[i].ctdb,pdb_ch[si].nterpairs);
 +    snew(chains[i].r_start,pdb_ch[si].nterpairs);
 +    snew(chains[i].r_end,pdb_ch[si].nterpairs);
 +      
 +    snew(chains[i].pdba,1);
 +    init_t_atoms(chains[i].pdba,pdb_ch[si].natom,TRUE);
 +    snew(chains[i].x,chains[i].pdba->nr);
 +    for (j=0; j<chains[i].pdba->nr; j++) {
 +      chains[i].pdba->atom[j] = pdba_all.atom[pdb_ch[si].start+j];
 +      snew(chains[i].pdba->atomname[j],1);
 +      *chains[i].pdba->atomname[j] = 
 +      strdup(*pdba_all.atomname[pdb_ch[si].start+j]);
 +      chains[i].pdba->pdbinfo[j] = pdba_all.pdbinfo[pdb_ch[si].start+j];
 +      copy_rvec(pdbx[pdb_ch[si].start+j],chains[i].x[j]);
 +    }
 +    /* Re-index the residues assuming that the indices are continuous */
 +    k    = chains[i].pdba->atom[0].resind;
 +    nres = chains[i].pdba->atom[chains[i].pdba->nr-1].resind - k + 1;
 +    chains[i].pdba->nres = nres;
 +    for(j=0; j < chains[i].pdba->nr; j++) {
 +      chains[i].pdba->atom[j].resind -= k;
 +    }
 +    srenew(chains[i].pdba->resinfo,nres);
 +    for(j=0; j<nres; j++) {
 +      chains[i].pdba->resinfo[j] = pdba_all.resinfo[k+j];
 +      snew(chains[i].pdba->resinfo[j].name,1);
 +      *chains[i].pdba->resinfo[j].name = strdup(*pdba_all.resinfo[k+j].name);
 +      /* make all chain identifiers equal to that of the chain */
 +      chains[i].pdba->resinfo[j].chainid = pdb_ch[si].chainid;
 +    }
 +  }
 +
 +  if (nchainmerges>0)
 +    printf("\nMerged chains into joint molecule definitions at %d places.\n\n",
 +           nchainmerges);
 +
 +  printf("There are %d chains and %d blocks of water and "
 +       "%d residues with %d atoms\n",
 +       nch-nwaterchain,nwaterchain,
 +       pdba_all.resinfo[pdba_all.atom[natom-1].resind].nr,natom);
 +        
 +  printf("\n  %5s  %4s %6s\n","chain","#res","#atoms");
 +  for (i=0; (i<nch); i++)
 +    printf("  %d '%c' %5d %6d  %s\n",
 +         i+1, chains[i].chainid ? chains[i].chainid:'-',
 +         chains[i].pdba->nres, chains[i].pdba->nr,
 +         chains[i].bAllWat ? "(only water)":"");
 +  printf("\n");
 +  
 +  check_occupancy(&pdba_all,opt2fn("-f",NFILE,fnm),bVerbose);
 +  
 +  /* Read atomtypes... */
 +  atype = read_atype(ffdir,&symtab);
 +  
 +  /* read residue database */
 +  printf("Reading residue database... (%s)\n",forcefield);
 +  nrtpf = fflib_search_file_end(ffdir,".rtp",TRUE,&rtpf);
 +  nrtp  = 0;
 +  restp = NULL;
 +  for(i=0; i<nrtpf; i++) {
 +    read_resall(rtpf[i],&nrtp,&restp,atype,&symtab,FALSE);
 +    sfree(rtpf[i]);
 +  }
 +  sfree(rtpf);
 +  if (bNewRTP) {
 +    /* Not correct with multiple rtp input files with different bonded types */
 +    fp=gmx_fio_fopen("new.rtp","w");
 +    print_resall(fp,nrtp,restp,atype);
 +    gmx_fio_fclose(fp);
 +  }
 +    
 +  /* read hydrogen database */
 +  nah = read_h_db(ffdir,&ah);
 +  
 +  /* Read Termini database... */
 +  nNtdb=read_ter_db(ffdir,'n',&ntdb,atype);
 +  nCtdb=read_ter_db(ffdir,'c',&ctdb,atype);
 +  
 +  top_fn=ftp2fn(efTOP,NFILE,fnm);
 +  top_file=gmx_fio_fopen(top_fn,"w");
 +
 +  sprintf(generator,"%s - %s",ShortProgram(), GromacsVersion() );
 +
 +  print_top_header(top_file,top_fn,generator,FALSE,ffdir,mHmult);
 +
 +  nincl=0;
 +  nmol=0;
 +  incls=NULL;
 +  mols=NULL;
 +  nres=0;
 +  for(chain=0; (chain<nch); chain++) {
 +    cc = &(chains[chain]);
 +
 +    /* set pdba, natom and nres to the current chain */
 +    pdba =cc->pdba;
 +    x    =cc->x;
 +    natom=cc->pdba->nr;
 +    nres =cc->pdba->nres;
 +    
 +    if (cc->chainid && ( cc->chainid != ' ' ) )
 +      printf("Processing chain %d '%c' (%d atoms, %d residues)\n",
 +            chain+1,cc->chainid,natom,nres);
 +    else
 +      printf("Processing chain %d (%d atoms, %d residues)\n",
 +            chain+1,natom,nres);
 +      
 +    process_chain(pdba,x,bUnA,bUnA,bUnA,bLysMan,bAspMan,bGluMan,
 +                bHisMan,bArgMan,bGlnMan,angle,distance,&symtab,
 +                nrtprename,rtprename);
 +      
 +        cc->chainstart[cc->nterpairs] = pdba->nres;
 +        j = 0;
 +        for(i=0; i<cc->nterpairs; i++)
 +        {
 +            find_nc_ter(pdba,cc->chainstart[i],cc->chainstart[i+1],
 +                        &(cc->r_start[j]),&(cc->r_end[j]),rt);    
 +      
 +            if (cc->r_start[j] >= 0 && cc->r_end[j] >= 0)
 +            {
 +                j++;
 +            }
 +        }
 +        cc->nterpairs = j;
 +        if (cc->nterpairs == 0)
 +        {
 +            printf("Problem with chain definition, or missing terminal residues.\n"
 +                   "This chain does not appear to contain a recognized chain molecule.\n"
 +                   "If this is incorrect, you can edit residuetypes.dat to modify the behavior.\n");
 +        }
 +
 +    /* Check for disulfides and other special bonds */
 +    nssbonds = mk_specbonds(pdba,x,bCysMan,&ssbonds,bVerbose);
 +
 +    if (nrtprename > 0) {        
 +      rename_resrtp(pdba,cc->nterpairs,cc->r_start,cc->r_end,nrtprename,rtprename,
 +                  &symtab,bVerbose);
 +    }
 +    
 +    if (debug) {
 +      if (nch==1) {
 +      sprintf(fn,"chain.pdb");
 +      } else {
 +      sprintf(fn,"chain_%c%d.pdb",cc->chainid,cc->chainnum);
 +      }
 +      write_sto_conf(fn,title,pdba,x,NULL,ePBC,box);
 +    }
 +
 +      
 +    for(i=0; i<cc->nterpairs; i++) 
 +    {
 +        
 +        /* Set termini.
 +         * We first apply a filter so we only have the
 +         * termini that can be applied to the residue in question
 +         * (or a generic terminus if no-residue specific is available).
 +         */
 +        /* First the N terminus */
 +        if (nNtdb > 0) 
 +        {
 +            tdblist = filter_ter(nrtp,restp,nNtdb,ntdb,
 +                                 *pdba->resinfo[cc->r_start[i]].name,
 +                                 *pdba->resinfo[cc->r_start[i]].rtp,
 +                                 &ntdblist);
 +            if(ntdblist==0)
 +            {
 +                printf("No suitable end (N or 5') terminus found in database - assuming this residue\n"
 +                       "is already in a terminus-specific form and skipping terminus selection.\n");
 +                cc->ntdb[i]=NULL;
 +            }
 +            else 
 +            {
 +                if(bTerMan && ntdblist>1)
 +                {
 +                    sprintf(select,"Select start terminus type for %s-%d",
 +                            *pdba->resinfo[cc->r_start[i]].name,
 +                            pdba->resinfo[cc->r_start[i]].nr);
 +                    cc->ntdb[i] = choose_ter(ntdblist,tdblist,select);
 +                }
 +                else
 +                {
 +                    cc->ntdb[i] = tdblist[0];
 +                }
 +                
 +                printf("Start terminus %s-%d: %s\n",
 +                       *pdba->resinfo[cc->r_start[i]].name,
 +                       pdba->resinfo[cc->r_start[i]].nr,
 +                       (cc->ntdb[i])->name);
 +                sfree(tdblist);
 +            }
 +        }
 +        else 
 +        {
 +            cc->ntdb[i] = NULL;
 +        }
 +        
 +        /* And the C terminus */
 +        if (nCtdb > 0)
 +        {
 +            tdblist = filter_ter(nrtp,restp,nCtdb,ctdb,
 +                                 *pdba->resinfo[cc->r_end[i]].name,
 +                                 *pdba->resinfo[cc->r_end[i]].rtp,
 +                                 &ntdblist);
 +            if(ntdblist==0)
 +            {
 +                printf("No suitable end (C or 3') terminus found in database - assuming this residue\n"
 +                       "is already in a terminus-specific form and skipping terminus selection.\n");
 +                cc->ctdb[i] = NULL;
 +            }
 +            else 
 +            {
 +                if(bTerMan && ntdblist>1)
 +                {
 +                    sprintf(select,"Select end terminus type for %s-%d",
 +                            *pdba->resinfo[cc->r_end[i]].name,
 +                            pdba->resinfo[cc->r_end[i]].nr);
 +                    cc->ctdb[i] = choose_ter(ntdblist,tdblist,select);
 +                }
 +                else
 +                {
 +                    cc->ctdb[i] = tdblist[0];
 +                }
 +                printf("End terminus %s-%d: %s\n",
 +                       *pdba->resinfo[cc->r_end[i]].name,
 +                       pdba->resinfo[cc->r_end[i]].nr,
 +                       (cc->ctdb[i])->name);
 +                sfree(tdblist);
 +            }
 +        }
 +        else 
 +        {
 +            cc->ctdb[i] = NULL;
 +        }
 +    }
 +    /* lookup hackblocks and rtp for all residues */
 +    get_hackblocks_rtp(&hb_chain, &restp_chain,
 +                     nrtp, restp, pdba->nres, pdba->resinfo, 
 +                     cc->nterpairs, cc->ntdb, cc->ctdb, cc->r_start, cc->r_end);
 +    /* ideally, now we would not need the rtp itself anymore, but do 
 +     everything using the hb and restp arrays. Unfortunately, that 
 +     requires some re-thinking of code in gen_vsite.c, which I won't 
 +     do now :( AF 26-7-99 */
 +
 +    rename_atoms(NULL,ffdir,
 +               pdba,&symtab,restp_chain,FALSE,rt,FALSE,bVerbose);
 +
 +    match_atomnames_with_rtp(restp_chain,hb_chain,pdba,x,bVerbose);
 +
 +    if (bSort) {
 +      block = new_blocka();
 +      snew(gnames,1);
 +      sort_pdbatoms(pdba->nres,restp_chain,hb_chain,
 +                  natom,&pdba,&x,block,&gnames);
 +      natom = remove_duplicate_atoms(pdba,x,bVerbose);
 +      if (ftp2bSet(efNDX,NFILE,fnm)) {
 +      if (bRemoveH) {
 +        fprintf(stderr,"WARNING: with the -remh option the generated "
 +                "index file (%s) might be useless\n"
 +                "(the index file is generated before hydrogens are added)",
 +                ftp2fn(efNDX,NFILE,fnm));
 +      }
 +      write_index(ftp2fn(efNDX,NFILE,fnm),block,gnames);
 +      }
 +      for(i=0; i < block->nr; i++)
 +      sfree(gnames[i]);
 +      sfree(gnames);
 +      done_blocka(block);
 +    } else {
 +      fprintf(stderr,"WARNING: "
 +            "without sorting no check for duplicate atoms can be done\n");
 +    }
 +
 +    /* Generate Hydrogen atoms (and termini) in the sequence */
 +    printf("Generating any missing hydrogen atoms and/or adding termini.\n");
 +    natom=add_h(&pdba,&x,nah,ah,
 +              cc->nterpairs,cc->ntdb,cc->ctdb,cc->r_start,cc->r_end,bAllowMissing,
 +              NULL,NULL,TRUE,FALSE);
 +    printf("Now there are %d residues with %d atoms\n",
 +         pdba->nres,pdba->nr);
 +    if (debug) write_pdbfile(debug,title,pdba,x,ePBC,box,' ',0,NULL,TRUE);
 +
 +    if (debug)
 +      for(i=0; (i<natom); i++)
 +      fprintf(debug,"Res %s%d atom %d %s\n",
 +              *(pdba->resinfo[pdba->atom[i].resind].name),
 +              pdba->resinfo[pdba->atom[i].resind].nr,i+1,*pdba->atomname[i]);
 +    
 +    strcpy(posre_fn,ftp2fn(efITP,NFILE,fnm));
 +    
 +    /* make up molecule name(s) */
 +
 +      k = (cc->nterpairs>0 && cc->r_start[0]>=0) ? cc->r_start[0] : 0;
 +            
 +    gmx_residuetype_get_type(rt,*pdba->resinfo[k].name,&p_restype);
 +      
 +    suffix[0]='\0';
 +      
 +    if (cc->bAllWat) 
 +    {
 +        sprintf(molname,"Water");
 +    } 
 +    else
 +    {
 +        this_chainid = cc->chainid;
 +        
 +        /* Add the chain id if we have one */
 +        if(this_chainid != ' ')
 +        {
 +            sprintf(buf,"_chain_%c",this_chainid);
 +            strcat(suffix,buf);
 +        }
 +
 +        /* Check if there have been previous chains with the same id */
 +        nid_used = 0;
 +        for(k=0;k<chain;k++)
 +        {
 +            if(cc->chainid == chains[k].chainid)
 +            {
 +                nid_used++;
 +            }
 +        }
 +        /* Add the number for this chain identifier if there are multiple copies */
 +        if(nid_used>0)
 +        {
 +            
 +            sprintf(buf,"%d",nid_used+1);
 +            strcat(suffix,buf);
 +        }
 +
 +        if(strlen(suffix)>0)
 +        {
 +            sprintf(molname,"%s%s",p_restype,suffix);
 +        }
 +        else
 +        {
 +            strcpy(molname,p_restype);
 +        }
 +    }
 +      
 +    if ((nch-nwaterchain>1) && !cc->bAllWat) {
 +      bITP=TRUE;
 +      strcpy(itp_fn,top_fn);
 +      printf("Chain time...\n");
 +      c=strrchr(itp_fn,'.');
 +      sprintf(c,"_%s.itp",molname);
 +      c=strrchr(posre_fn,'.');
 +      sprintf(c,"_%s.itp",molname);
 +      if (strcmp(itp_fn,posre_fn) == 0) {
 +      strcpy(buf_fn,posre_fn);
 +      c  = strrchr(buf_fn,'.');
 +      *c = '\0';
 +      sprintf(posre_fn,"%s_pr.itp",buf_fn);
 +      }
 +      
 +      nincl++;
 +      srenew(incls,nincl);
 +      incls[nincl-1]=strdup(itp_fn);
 +      itp_file=gmx_fio_fopen(itp_fn,"w");
 +    } else
 +      bITP=FALSE;
 +
 +    srenew(mols,nmol+1);
 +    if (cc->bAllWat) {
 +      mols[nmol].name = strdup("SOL");
 +      mols[nmol].nr   = pdba->nres;
 +    } else {
 +      mols[nmol].name = strdup(molname);
 +      mols[nmol].nr   = 1;
 +    }
 +    nmol++;
 +
 +    if (bITP)
 +      print_top_comment(itp_file,itp_fn,generator,ffdir,TRUE);
 +
 +    if (cc->bAllWat)
 +      top_file2=NULL;
 +    else
 +      if (bITP)
 +      top_file2=itp_file;
 +      else
 +      top_file2=top_file;
 +
 +    pdb2top(top_file2,posre_fn,molname,pdba,&x,atype,&symtab,
 +          nrtp,restp,
 +          restp_chain,hb_chain,
 +          cc->nterpairs,cc->ntdb,cc->ctdb,bAllowMissing,
 +          bVsites,bVsiteAromatics,forcefield,ffdir,
 +          mHmult,nssbonds,ssbonds,
 +          long_bond_dist,short_bond_dist,bDeuterate,bChargeGroups,bCmap,
 +          bRenumRes,bRTPresname);
 +    
 +    if (!cc->bAllWat)
 +      write_posres(posre_fn,pdba,posre_fc);
 +
 +    if (bITP)
 +      gmx_fio_fclose(itp_file);
 +
 +    /* pdba and natom have been reassigned somewhere so: */
 +    cc->pdba = pdba;
 +    cc->x = x;
 +    
 +    if (debug) {
 +      if (cc->chainid == ' ')
 +      sprintf(fn,"chain.pdb");
 +      else
 +      sprintf(fn,"chain_%c.pdb",cc->chainid);
 +      cool_quote(quote,255,NULL);
 +      write_sto_conf(fn,quote,pdba,x,NULL,ePBC,box);
 +    }
 +  }
 +
 +  if (watermodel == NULL) {
 +    for(chain=0; chain<nch; chain++) {
 +      if (chains[chain].bAllWat) {
 +      gmx_fatal(FARGS,"You have chosen not to include a water model, but there is water in the input file. Select a water model or remove the water from your input file.");
 +      }
 +    }
 +  } else {
 +    sprintf(buf_fn,"%s%c%s.itp",ffdir,DIR_SEPARATOR,watermodel);
 +    if (!fflib_fexist(buf_fn)) {
 +      gmx_fatal(FARGS,"The topology file '%s' for the selected water model '%s' can not be found in the force field directory. Select a different water model.",
 +              buf_fn,watermodel);
 +    }
 +  }
 +
 +  print_top_mols(top_file,title,ffdir,watermodel,nincl,incls,nmol,mols);
 +  gmx_fio_fclose(top_file);
 +
 +  gmx_residuetype_destroy(rt);
 +    
 +  /* now merge all chains back together */
 +  natom=0;
 +  nres=0;
 +  for (i=0; (i<nch); i++) {
 +    natom+=chains[i].pdba->nr;
 +    nres+=chains[i].pdba->nres;
 +  }
 +  snew(atoms,1);
 +  init_t_atoms(atoms,natom,FALSE);
 +  for(i=0; i < atoms->nres; i++)
 +    sfree(atoms->resinfo[i].name);
 +  sfree(atoms->resinfo);
 +  atoms->nres=nres;
 +  snew(atoms->resinfo,nres);
 +  snew(x,natom);
 +  k=0;
 +  l=0;
 +  for (i=0; (i<nch); i++) {
 +    if (nch>1)
 +      printf("Including chain %d in system: %d atoms %d residues\n",
 +           i+1,chains[i].pdba->nr,chains[i].pdba->nres);
 +    for (j=0; (j<chains[i].pdba->nr); j++) {
 +      atoms->atom[k]=chains[i].pdba->atom[j];
 +      atoms->atom[k].resind += l; /* l is processed nr of residues */
 +      atoms->atomname[k]=chains[i].pdba->atomname[j];
 +      atoms->resinfo[atoms->atom[k].resind].chainid = chains[i].chainid;
 +      copy_rvec(chains[i].x[j],x[k]);
 +      k++;
 +    }
 +    for (j=0; (j<chains[i].pdba->nres); j++) {
 +      atoms->resinfo[l] = chains[i].pdba->resinfo[j];
 +      if (bRTPresname) {
 +      atoms->resinfo[l].name = atoms->resinfo[l].rtp;
 +      }
 +      l++;
 +    }
 +  }
 +  
 +  if (nch>1) {
 +    fprintf(stderr,"Now there are %d atoms and %d residues\n",k,l);
 +    print_sums(atoms, TRUE);
 +  }
 +  
 +  fprintf(stderr,"\nWriting coordinate file...\n");
 +  clear_rvec(box_space);
 +  if (box[0][0] == 0) 
 +    gen_box(0,atoms->nr,x,box,box_space,FALSE);
 +  write_sto_conf(ftp2fn(efSTO,NFILE,fnm),title,atoms,x,NULL,ePBC,box);
 +
 +  printf("\t\t--------- PLEASE NOTE ------------\n");
 +  printf("You have successfully generated a topology from: %s.\n",
 +       opt2fn("-f",NFILE,fnm));
 +  if (watermodel != NULL) {
 +    printf("The %s force field and the %s water model are used.\n",
 +         ffname,watermodel);
 +  } else {
 +    printf("The %s force field is used.\n",
 +         ffname);
 +  }
 +  printf("\t\t--------- ETON ESAELP ------------\n");
 +  
 +
 +  thanx(stdout);
 +  
 +  return 0;
 +}
index f0d02789b6101f752cf2ff1045d9afd154c4f965,0000000000000000000000000000000000000000..3803391dba28f8934e963ca49ccd1784207dcc53
mode 100644,000000..100644
--- /dev/null
@@@ -1,9 -1,0 +1,9 @@@
- file(GLOB TPBCONV_SOURCES tpbconv.c)
 +include_directories(${CMAKE_SOURCE_DIR}/src/gromacs/gmxpreprocess)
 +
++file(GLOB TPBCONV_SOURCES tpbconv.c ../main.cpp)
 +
 +add_executable(tpbconv ${TPBCONV_SOURCES})
 +gmx_add_man_page(tpbconv)
 +target_link_libraries(tpbconv ${GMX_EXTRA_LIBRARIES} libgromacs ${GMX_EXE_LINKER_FLAGS})
 +set_target_properties(tpbconv PROPERTIES OUTPUT_NAME "tpbconv${GMX_BINARY_SUFFIX}")
 +install(TARGETS tpbconv DESTINATION ${BIN_INSTALL_DIR} COMPONENT runtime)
Simple merge
index af0a67b4b709fa90cba7231e44be794399505eee,c5be93178bfd0191590cb2cd164c2e76969e164e..ab7e69cacdf7956d5d76e2fa95103e10140257f5
@@@ -27,9 -29,10 +27,10 @@@ add_library(gmxan
              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_options.c   gmx_dos.c
 +            gmx_pme_error.c gmx_options.c   gmx_dos.c
              gmx_hydorder.c  gmx_densorder.c powerspect.c    dens_filter.c
-             binsearch.c     gmx_dyecoupl.c
+             binsearch.c     gmx_dyecoupl.c  gmx_make_edi.c  gmx_sigeps.c
+             gmx_do_dssp.c   gmx_anadock.c   gmx_make_ndx.c  gmx_mk_angndx.c
              )
  
  
index 0000000000000000000000000000000000000000,0e50b9cbf5356de1a1bedf0add202611d93c68ed..3380b825d62fa85fa839d059f664c2b1073353cb
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,354 +1,355 @@@
 -      
+ /*
+  * 
+  *                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 "confio.h"
+ #include "copyrite.h"
+ #include "futil.h"
+ #include "gmx_fatal.h"
+ #include "smalloc.h"
+ #include "string2.h"
+ #include "vec.h"
+ #include "gmx_statistics.h"
+ #include "statutil.h"
+ #include "typedefs.h"
+ #include "xvgr.h"
++#include "macros.h"
++
+ static const char *etitles[] = { "E-docked", "Free Energy" };
+ typedef struct {
+   real    edocked,efree;
+   int     index,cluster_id;
+   t_atoms atoms;
+   rvec    *x;
+   int     ePBC;
+   matrix  box;
+ } t_pdbfile;
+ static t_pdbfile *read_pdbf(const char *fn)
+ {
+   t_pdbfile *pdbf;
+   double    e;
+   char      buf[256],*ptr;
+   int       natoms;
+   FILE      *fp;
+   
+   snew(pdbf,1);
+   get_stx_coordnum (fn,&natoms);
+   init_t_atoms(&(pdbf->atoms),natoms,FALSE);
+   snew(pdbf->x,natoms);
+   read_stx_conf(fn,buf,&pdbf->atoms,pdbf->x,NULL,&pdbf->ePBC,pdbf->box);
+   fp = ffopen(fn,"r");
+   do {
+     ptr = fgets2(buf,255,fp);
+     if (ptr) {
+       if (strstr(buf,"Intermolecular") != NULL) {
+       ptr = strchr(buf,'=');
+       sscanf(ptr+1,"%lf",&e);
+       pdbf->edocked = e;
+       }
+       else if (strstr(buf,"Estimated Free") != NULL) {
+       ptr = strchr(buf,'=');
+       sscanf(ptr+1,"%lf",&e);
+       pdbf->efree = e;
+       } 
+     }
+   } while (ptr != NULL);
+   ffclose(fp);
+   
+   return pdbf;
+ }
+ static t_pdbfile **read_em_all(const char *fn,int *npdbf)
+ {
+   t_pdbfile **pdbf=0;
+   int  i,maxpdbf;
+   char buf[256],name[256];
+   gmx_bool bExist;
+   
+   strcpy(buf,fn);
+   buf[strlen(buf)-4] = '\0';
+   maxpdbf = 100;
+   snew(pdbf,maxpdbf);
+   i=0;
+   do {
+     sprintf(name,"%s_%d.pdb",buf,i+1);
+     if ((bExist = gmx_fexist(name)) == TRUE) {
+       pdbf[i] = read_pdbf(name);
+       pdbf[i]->index = i+1;
+       i++;
+       if (i >= maxpdbf) {
+       maxpdbf += 100;
+       srenew(pdbf,maxpdbf);
+       }
+     }
+   } while (bExist);
+   
+   *npdbf = i;
+   printf("Found %d pdb files\n",i);
+     
+   return pdbf;
+ }
+ static gmx_bool bFreeSort=FALSE;
+ static int pdbf_comp(const void *a,const void *b)
+ {
+   t_pdbfile *pa,*pb;
+   real x;
+   int  dc;
+   
+   pa = *(t_pdbfile **)a;
+   pb = *(t_pdbfile **)b;
+   
+   dc = pa->cluster_id - pb->cluster_id;
+   
+   if (dc == 0) {
+     if (bFreeSort)
+       x = pa->efree   - pb->efree;
+     else
+       x = pa->edocked - pb->edocked;
+     
+     if (x < 0)
+       return -1;
+     else if (x > 0)
+       return 1;
+     else
+       return 0;
+   }
+   else 
+     return dc;
+ }
+ static void analyse_em_all(int npdb,t_pdbfile *pdbf[], const char *edocked,
+                            const char *efree, const output_env_t oenv)
+ {
+   FILE *fp;
+   int i;
+   
+   for(bFreeSort = FALSE; (bFreeSort <= TRUE); bFreeSort++) {
+     qsort(pdbf,npdb,sizeof(pdbf[0]),pdbf_comp);
+     fp = xvgropen(bFreeSort ? efree : edocked,
+                 etitles[bFreeSort],"()","E (kJ/mol)",oenv);
+     for(i=0; (i<npdb); i++)
+       fprintf(fp,"%12lf\n",bFreeSort ? pdbf[i]->efree : pdbf[i]->edocked);
+     ffclose(fp);
+   }
+ }
+ static void clust_stat(FILE *fp,int start,int end,t_pdbfile *pdbf[])
+ {
+   int i;
+   gmx_stats_t ed,ef;
+   real aver,sigma;
+   
+   ed = gmx_stats_init();
+   ef = gmx_stats_init();
+   for(i=start; (i<end); i++) {
+     gmx_stats_add_point(ed,i-start,pdbf[i]->edocked,0,0);
+     gmx_stats_add_point(ef,i-start,pdbf[i]->efree,0,0);
+   }
+   gmx_stats_get_ase(ed,&aver,&sigma,NULL);
+   fprintf(fp,"  <%12s> = %8.3f (+/- %6.3f)\n",etitles[FALSE],aver,sigma);
+   gmx_stats_get_ase(ef,&aver,&sigma,NULL);
+   fprintf(fp,"  <%12s> = %8.3f (+/- %6.3f)\n",etitles[TRUE],aver,sigma);
+   gmx_stats_done(ed);
+   gmx_stats_done(ef);
+   sfree(ed);
+   sfree(ef);
+ }
+ static real rmsd_dist(t_pdbfile *pa,t_pdbfile *pb,gmx_bool bRMSD)
+ {
+   int  i;
+   real rmsd,dist;
+   rvec acm,bcm,dx;
+   
+   if (bRMSD) {
+     rmsd = 0;
+     for(i=0; (i<pa->atoms.nr); i++) {
+       rvec_sub(pa->x[i],pb->x[i],dx);
+       rmsd += iprod(dx,dx);
+     }
+     rmsd = sqrt(rmsd/pa->atoms.nr);
+   }
+   else {
+     dist = 0;
+     clear_rvec(acm);
+     clear_rvec(bcm);
+     for(i=0; (i<pa->atoms.nr); i++) {
+       rvec_inc(acm,pa->x[i]);
+       rvec_inc(bcm,pb->x[i]);
+     }
+     rvec_sub(acm,bcm,dx);
+     for(i=0; (i<DIM); i++)
+       dx[i] /= pa->atoms.nr;
+     rmsd = norm(dx);
+   }
+   return rmsd;
+ }
+ static void line(FILE *fp)
+ {
+   fprintf(fp,"                   - - - - - - - - - -\n");
+ }
+ static void cluster_em_all(FILE *fp,int npdb,t_pdbfile *pdbf[],
+                          const char *pdbout,gmx_bool bFree,gmx_bool bRMSD,real cutoff)
+ {
+   int  i,j,k;
+   int  *cndx,ncluster;
+   real rmsd;
+   
+   bFreeSort = bFree;
+   qsort(pdbf,npdb,sizeof(pdbf[0]),pdbf_comp);
+   fprintf(fp,"Statistics over all structures:\n");
+   clust_stat(fp,0,npdb,pdbf);
+   line(fp);
+   
+   /* Index to first structure in a cluster */
+   snew(cndx,npdb);
+   ncluster=1;
+   
+   for(i=1; (i<npdb); i++) {
+     for(j=0; (j<ncluster); j++) {
+       rmsd = rmsd_dist(pdbf[cndx[j]],pdbf[i],bRMSD);
+       if (rmsd <= cutoff) {
+       /* Structure i is in cluster j */
+       pdbf[i]->cluster_id = pdbf[cndx[j]]->cluster_id;
+       break;
+       }
+     }
+     if (j == ncluster) {
+       /* New cluster! Cool! */
+       cndx[ncluster] = i;
+       pdbf[i]->cluster_id = ncluster;
+       ncluster++;
+     }
+   }
+   cndx[ncluster] = npdb;
+   qsort(pdbf,npdb,sizeof(pdbf[0]),pdbf_comp);
+   
+   j=0;
+   cndx[j++] = 0;
+   for(i=1; (i<npdb); i++) {
+     if (pdbf[i]->cluster_id != pdbf[i-1]->cluster_id) {
+       cndx[j++] = i;
+     }
+   }
+   cndx[j] = npdb;
+   if (j != ncluster) 
+     gmx_fatal(FARGS,"Consistency error: j = %d, ncluster = %d",j,ncluster);
+   
+   fprintf(fp,"I found %d clusters based on %s and %s with a %.3f nm cut-off\n",
+         ncluster,etitles[bFree],bRMSD ? "RMSD" : "distance",cutoff);
+   line(fp);
+   for(j=0; (j<ncluster); j++) {
+     fprintf(fp,"Cluster: %3d  %s: %10.5f kJ/mol %3d elements\n",
+           j,etitles[bFree],
+           bFree ? pdbf[cndx[j]]->efree : pdbf[cndx[j]]->edocked,
+           cndx[j+1]-cndx[j]);
+     clust_stat(fp,cndx[j],cndx[j+1],pdbf);
+     for(k=cndx[j]; (k<cndx[j+1]); k++)
+       fprintf(fp,"  %3d",pdbf[k]->index);
+     fprintf(fp,"\n");
+     line(fp);
+   }
+   sfree(cndx);
+ }
+ int gmx_anadock(int argc,char *argv[])
+ {
+   const char *desc[] = {
+     "[TT]g_anadock[tt] analyses the results of an Autodock run and clusters the",
+     "structures together, based on distance or RMSD. The docked energy",
+     "and free energy estimates are analysed, and for each cluster the",
+     "energy statistics are printed.[PAR]",
+     "An alternative approach to this is to cluster the structures first",
+     "using [TT]g_cluster[tt] and then sort the clusters on either lowest",
+     "energy or average energy."
+   };
+   t_filenm fnm[] = {
+     { efPDB, "-f", NULL,       ffREAD  },
+     { efPDB, "-ox", "cluster", ffWRITE },
+     { efXVG, "-od", "edocked", ffWRITE },
+     { efXVG, "-of", "efree",   ffWRITE },
+     { efLOG, "-g",  "anadock", ffWRITE }
+   };
+   output_env_t oenv;
+ #define NFILE asize(fnm)
+   static gmx_bool bFree=FALSE,bRMS=TRUE;
+   static real cutoff = 0.2;
+   t_pargs pa[] = {
+     { "-free",   FALSE, etBOOL, {&bFree}, 
+       "Use Free energy estimate from autodock for sorting the classes" },
+     { "-rms",    FALSE, etBOOL, {&bRMS},
+       "Cluster on RMS or distance" },
+     { "-cutoff", FALSE, etREAL, {&cutoff},
+       "Maximum RMSD/distance for belonging to the same cluster" }
+   };
+ #define NPA asize(pa)
+   FILE      *fp;
+   t_pdbfile **pdbf=NULL;
+   int       npdbf;
+   
+   CopyRight(stderr,argv[0]);
+   parse_common_args(&argc,argv,0,NFILE,fnm,NPA,pa, asize(desc),desc,0,
+                     NULL,&oenv);
+   
+   fp = ffopen(opt2fn("-g",NFILE,fnm),"w");
+   please_cite(stdout,"Hetenyi2002b");
+   please_cite(fp,"Hetenyi2002b");
+   
+   pdbf = read_em_all(opt2fn("-f",NFILE,fnm),&npdbf);
+   
+   analyse_em_all(npdbf,pdbf,opt2fn("-od",NFILE,fnm),opt2fn("-of",NFILE,fnm),
+                  oenv);
+   
+   cluster_em_all(fp,npdbf,pdbf,opt2fn("-ox",NFILE,fnm),
+                bFree,bRMS,cutoff);
+   
+   thanx(fp);
+   ffclose(fp);
+   
+   thanx(stdout);
+   
+   return 0;
+ }
index 0000000000000000000000000000000000000000,3142dc16de5a6f0aba1f2619953c4d9b18967da0..3e1c71df6d416dafbac448b8578c512613b0009a
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,850 +1,844 @@@
 -#include "gmx_header_config.h"
+ /*
+  *
+  *                This source code is part of
+  *
+  *                 G   R   O   M   A   C   S
+  *
+  *          GROningen MAchine for Chemical Simulations
+  *
+  *                        VERSION 3.2.0
+  *
+  * The make_edi program was generously contributed by Oliver Lange, based
+  * on the code from g_anaeig. You can reach him as olange@gwdg.de.
+  *
+  * This program is free software; you can redistribute 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 One Microsecond At Cannonball Speeds
+  */
+ #ifdef HAVE_CONFIG_H
+ #include <config.h>
+ #endif
 -
 -/* Suppress Cygwin compiler warnings from using newlib version of
 - * ctype.h */
 -#ifdef GMX_CYGWIN
 -#undef isdigit
 -#endif
+ #include <math.h>
+ #include <stdlib.h>
+ #include <ctype.h>
+ #include <string.h>
+ #include "readinp.h"
+ #include "statutil.h"
+ #include "sysstuff.h"
+ #include "typedefs.h"
+ #include "smalloc.h"
+ #include "macros.h"
+ #include "gmx_fatal.h"
+ #include "vec.h"
+ #include "pbc.h"
+ #include "copyrite.h"
+ #include "futil.h"
+ #include "statutil.h"
+ #include "pdbio.h"
+ #include "confio.h"
+ #include "tpxio.h"
+ #include "matio.h"
+ #include "mshift.h"
+ #include "xvgr.h"
+ #include "do_fit.h"
+ #include "rmpbc.h"
+ #include "txtdump.h"
+ #include "eigio.h"
+ #include "index.h"
++#include "string2.h"
+ typedef struct
+ {
+     real        deltaF0;
+     gmx_bool    bHarmonic;
+     gmx_bool    bConstForce;   /* Do constant force flooding instead of
+                                   evaluating a flooding potential             */
+     real        tau;
+     real        deltaF;
+     real        kT;
+     real        constEfl;
+     real        alpha2;
+ } t_edflood;
+ /* This type is for the average, reference, target, and origin structure   */
+ typedef struct edix
+ {
+     int         nr;             /* number of atoms this structure contains */
+     int         *anrs;          /* atom index numbers                      */
+     rvec        *x;             /* positions                               */
+     real        *sqrtm;         /* sqrt of the masses used for mass-
+                                  * weighting of analysis                   */
+ } t_edix;
+ typedef struct edipar
+ {
+     int         nini;           /* total Nr of atoms                    */
+     gmx_bool    fitmas;         /* true if trans fit with cm            */
+     gmx_bool    pcamas;         /* true if mass-weighted PCA            */
+     int         presteps;       /* number of steps to run without any
+                                  *    perturbations ... just monitoring */
+     int         outfrq;         /* freq (in steps) of writing to edo    */
+     int         maxedsteps;     /* max nr of steps per cycle            */
+     struct edix sref;           /* reference positions, to these fitting
+                                  * will be done                         */
+     struct edix sav;            /* average positions                    */
+     struct edix star;           /* target positions                     */
+     struct edix sori;           /* origin positions                     */
+     real        slope;          /* minimal slope in acceptance radexp   */
+     int         ned;            /* Nr of atoms in essdyn buffer         */
+     t_edflood   flood;          /* parameters especially for flooding   */
+ } t_edipar;
+ void make_t_edx(struct edix *edx, int natoms, rvec *pos, atom_id index[]) {
+   edx->nr=natoms;
+   edx->anrs=index;
+   edx->x=pos;
+ }
+ void write_t_edx(FILE *fp, struct edix edx, const char *comment) {
+  /*here we copy only the pointers into the t_edx struct
+   no data is copied and edx.box is ignored  */
+  int i;
+   fprintf(fp,"#%s \n %d \n",comment,edx.nr);
+   for (i=0;i<edx.nr;i++) {
+     fprintf(fp,"%d  %f  %f  %f\n",(edx.anrs)[i]+1,(edx.x)[i][XX],(edx.x)[i][YY],(edx.x)[i][ZZ]);
+   }
+ }
+ int sscan_list(int *list[], const char *str, const char *listname) {
+  /*this routine scans a string of the form 1,3-6,9 and returns the
+     selected numbers (in this case 1 3 4 5 6 9) in NULL-terminated array of integers.
+     memory for this list will be allocated  in this routine -- sscan_list expects *list to
+     be a NULL-Pointer
+     listname is a string used in the errormessage*/
+    int i,istep;
+    char c;
+    char *pos,*startpos,*step;
+    int n=strlen(str);
+    /*enums to define the different lexical stati */
+    enum { sBefore, sNumber, sMinus, sRange, sZero, sSmaller, sError, sSteppedRange };
+    int status=sBefore; /*status of the deterministic automat to scan str   */
+    int number=0;
+    int end_number=0;
+    char *start=NULL; /*holds the string of the number behind a ','*/
+    char *end=NULL; /*holds the string of the number behind a '-' */
+    int nvecs=0; /* counts the number of vectors in the list*/
+    step=NULL;
+    snew(pos,n+4);
+    startpos=pos;
+    strcpy(pos,str);
+    pos[n]=',';
+    pos[n+1]='1';
+    pos[n+2]='\0';
+    *list = NULL;
+    while ((c=*pos)!=0) {
+      switch(status) {
+         /* expect a number */
+         case sBefore: if (isdigit(c)) {
+               start=pos;
+               status=sNumber;
+               break;
+            } else status=sError; break;
+         /* have read a number, expect ',' or '-' */
+         case sNumber: if (c==',') {
+              /*store number*/
+              srenew(*list,nvecs+1);
+              (*list)[nvecs++]=number=strtol(start,NULL,10);
+              status=sBefore;
+              if (number==0)
+                  status=sZero;
+               break;
+              } else if (c=='-') { status=sMinus; break; }
+              else if (isdigit(c)) break;
+              else status=sError; break;
+         /* have read a '-' -> expect a number */
+      case sMinus:
+        if (isdigit(c)) {
+        end=pos;
+        status=sRange; break;
+        } else status=sError; break;
+      case sSteppedRange:
+        if (isdigit(c)) {
+        if (step) {
+          status=sError; break;
+        } else
+          step=pos;
+        status=sRange;
+        break;
+        } else status=sError; break;
+         /* have read the number after a minus, expect ',' or ':' */
+         case sRange:
+             if (c==',') {
+                /*store numbers*/
+                end_number=strtol(end,NULL,10);
+                number=strtol(start,NULL,10);
+                status=sBefore;
+                if (number==0) {
+                   status=sZero; break;
+                }
+                if (end_number<=number) {
+                   status=sSmaller; break;
+                }
+                srenew(*list,nvecs+end_number-number+1);
+              if (step) {
+                istep=strtol(step,NULL,10);
+                step=NULL;
+              } else istep=1;
+                for (i=number;i<=end_number;i+=istep)
+                     (*list)[nvecs++]=i;
+                break;
+             } else if (c==':') {
+             status = sSteppedRange;
+             break;
+           } else if (isdigit(c)) break; else status=sError;  break;
+        /* format error occured */
+        case sError:
+          gmx_fatal(FARGS,"Error in the list of eigenvectors for %s at pos %d with char %c",listname,pos-startpos,*(pos-1));
+          break;
+        /* logical error occured */
+        case sZero:
+                  gmx_fatal(FARGS,"Error in the list of eigenvectors for %s at pos %d: eigenvector 0 is not valid",listname,pos-startpos);
+                  break;
+        case sSmaller:
+                  gmx_fatal(FARGS,"Error in the list of eigenvectors for %s at pos %d: second index %d is not bigger than %d",listname,pos-startpos,end_number,number);
+                  break;
+      }
+    ++pos; /* read next character */
+    } /*scanner has finished */
+    /* append zero to list of eigenvectors */
+    srenew(*list,nvecs+1);
+    (*list)[nvecs]=0;
+    sfree(startpos);
+    return nvecs;
+ } /*sscan_list*/
+ void write_eigvec(FILE* fp, int natoms, int eig_list[], rvec** eigvecs,int nvec, const char *grouptitle,real steps[]) {
+ /* eig_list is a zero-terminated list of indices into the eigvecs array.
+    eigvecs are coordinates of eigenvectors
+    grouptitle to write in the comment line
+    steps  -- array with stepsizes for evLINFIX, evLINACC and evRADACC
+ */
+   int n=0,i; rvec x;
+   real sum;
+   while (eig_list[n++]);  /*count selected eigenvecs*/
+   fprintf(fp,"# NUMBER OF EIGENVECTORS + %s\n %d\n",grouptitle,n-1);
+   /* write list of eigenvector indicess */
+   for(n=0;eig_list[n];n++) {
+     if (steps)
+       fprintf(fp,"%8d   %g\n",eig_list[n],steps[n]);
+     else
+       fprintf(fp,"%8d   %g\n",eig_list[n],1.0);
+   }
+   n=0;
+   /* dump coordinates of the selected eigenvectors */
+   while (eig_list[n]) {
+     sum=0;
+     for (i=0; i<natoms; i++) {
+       if (eig_list[n]>nvec)
+       gmx_fatal(FARGS,"Selected eigenvector %d is higher than maximum number %d of available eigenvectors",eig_list[n],nvec);
+       copy_rvec(eigvecs[eig_list[n]-1][i],x);
+       sum+=norm2(x);
+       fprintf(fp,"%8.5f %8.5f %8.5f\n",x[XX],x[YY],x[ZZ]);
+     }
+     n++;
+   }
+ }
+ /*enum referring to the different lists of eigenvectors*/
+ enum { evLINFIX, evLINACC, evFLOOD, evRADFIX, evRADACC, evRADCON , evMON,  evNr };
+ #define oldMAGIC 666
+ #define MAGIC 670
+ void write_the_whole_thing(FILE* fp, t_edipar *edpars, rvec** eigvecs,
+                            int nvec, int *eig_listen[], real* evStepList[])
+ {
+ /* write edi-file */
+     /*Header*/
+     fprintf(fp,"#MAGIC\n %d \n#NINI\n %d\n#FITMAS\n %d\n#ANALYSIS_MAS\n %d\n",
+         MAGIC,edpars->nini,edpars->fitmas,edpars->pcamas);
+     fprintf(fp,"#OUTFRQ\n %d\n#MAXLEN\n %d\n#SLOPECRIT\n %f\n",
+         edpars->outfrq,edpars->maxedsteps,edpars->slope);
+     fprintf(fp,"#PRESTEPS\n %d\n#DELTA_F0\n %f\n#INIT_DELTA_F\n %f\n#TAU\n %f\n#EFL_NULL\n %f\n#ALPHA2\n %f\n#KT\n %f\n#HARMONIC\n %d\n#CONST_FORCE_FLOODING\n %d\n",
+         edpars->presteps,edpars->flood.deltaF0,edpars->flood.deltaF,edpars->flood.tau,edpars->flood.constEfl,
+         edpars->flood.alpha2,edpars->flood.kT,edpars->flood.bHarmonic,edpars->flood.bConstForce);
+     /* Average and reference positions */
+     write_t_edx(fp,edpars->sref,"NREF, XREF");
+     write_t_edx(fp,edpars->sav,"NAV, XAV");
+     /*Eigenvectors */
+     write_eigvec(fp, edpars->ned, eig_listen[evMON],eigvecs,nvec,"COMPONENTS GROUP 1",NULL);
+     write_eigvec(fp, edpars->ned, eig_listen[evLINFIX],eigvecs,nvec,"COMPONENTS GROUP 2",evStepList[evLINFIX]);
+     write_eigvec(fp, edpars->ned, eig_listen[evLINACC],eigvecs,nvec,"COMPONENTS GROUP 3",evStepList[evLINACC]);
+     write_eigvec(fp, edpars->ned, eig_listen[evRADFIX],eigvecs,nvec,"COMPONENTS GROUP 4",evStepList[evRADFIX]);
+     write_eigvec(fp, edpars->ned, eig_listen[evRADACC],eigvecs,nvec,"COMPONENTS GROUP 5",NULL);
+     write_eigvec(fp, edpars->ned, eig_listen[evRADCON],eigvecs,nvec,"COMPONENTS GROUP 6",NULL);
+     write_eigvec(fp, edpars->ned, eig_listen[evFLOOD],eigvecs,nvec,"COMPONENTS GROUP 7",evStepList[evFLOOD]);
+     /*Target and Origin positions */
+     write_t_edx(fp,edpars->star,"NTARGET, XTARGET");
+     write_t_edx(fp,edpars->sori,"NORIGIN, XORIGIN");
+ }
+ int read_conffile(const char *confin,char *title,rvec *x[])
+ {
+ /* read coordinates out of STX file  */
+   int natoms;
+   t_atoms  confat;
+   matrix box;
+   printf("read coordnumber from file %s\n",confin);
+   get_stx_coordnum(confin,&natoms);
+   printf("number of coordinates in file %d\n",natoms);
+ /*  if (natoms != ncoords)
+      gmx_fatal(FARGS,"number of coordinates in coordinate file (%s, %d)\n"
+            "             does not match topology (= %d)",
+            confin,natoms,ncoords);
+   else {*/
+     /* make space for coordinates and velocities */
+     init_t_atoms(&confat,natoms,FALSE);
+     snew(*x,natoms);
+     read_stx_conf(confin,title,&confat,*x,NULL,NULL,box);
+     return natoms;
+ }
+ void read_eigenvalues(int vecs[],const char *eigfile, real values[],
+                       gmx_bool bHesse, real kT)
+ {
+   int  neig,nrow,i;
+   double **eigval;
+   neig = read_xvg(eigfile,&eigval,&nrow);
+   fprintf(stderr,"Read %d eigenvalues\n",neig);
+   for(i=bHesse ? 6 : 0 ; i<neig; i++) {
+     if (eigval[1][i] < -0.001 && bHesse)
+       fprintf(stderr,
+             "WARNING: The Hessian Matrix has negative eigenvalue %f, we set it to zero (no flooding in this direction)\n\n",eigval[1][i]);
+     if (eigval[1][i] < 0)
+       eigval[1][i] = 0;
+   }
+   if (bHesse)
+     for (i=0; vecs[i]; i++) {
+       if (vecs[i]<7)
+       gmx_fatal(FARGS,"ERROR: You have chosen one of the first 6 eigenvectors of the HESSE Matrix. That does not make sense, since they correspond to the 6 rotational and translational degrees of freedom.\n\n");
+       values[i]=eigval[1][vecs[i]-1]/kT;
+     }
+   else
+     for (i=0; vecs[i]; i++) {
+       if (vecs[i]>(neig-6))
+       gmx_fatal(FARGS,"ERROR: You have chosen one of the last 6 eigenvectors of the COVARIANCE Matrix. That does not make sense, since they correspond to the 6 rotational and translational degrees of freedom.\n\n");
+       values[i]=1/eigval[1][vecs[i]-1];
+     }
+   /* free memory */
+   for (i=0; i<nrow; i++)
+     sfree(eigval[i]);
+   sfree(eigval);
+ }
+ static real *scan_vecparams(const char *str,const char * par, int nvecs)
+ {
+   char   f0[256],f1[256];             /*format strings adapted every pass of the loop*/
+   double d,tcap=0;
+   int    i;
+   real   *vec_params;
+   snew(vec_params,nvecs);
+   if (str) {
+     f0[0] = '\0';
+     for(i=0; (i<nvecs); i++) {
+       strcpy(f1,f0);  /*f0 is the format string for the "to-be-ignored" numbers*/
+       strcat(f1,"%lf"); /*and f1 to read the actual number in this pass of the loop*/
+       if (sscanf(str,f1,&d) != 1)
+       gmx_fatal(FARGS,"Not enough elements for %s parameter (I need %d)",par,nvecs);
+       vec_params[i] = d;
+       tcap += d;
+       strcat(f0,"%*s");
+     }
+   }
+   return vec_params;
+ }
+ void init_edx(struct edix *edx) {
+   edx->nr=0;
+   snew(edx->x,1);
+   snew(edx->anrs,1);
+ }
+ void filter2edx(struct edix *edx,int nindex, atom_id index[],int ngro,
+                 atom_id igro[],rvec *x,const char* structure)
+ {
+ /* filter2edx copies coordinates from x to edx which are given in index
+ */
+    int pos,i;
+    int ix=edx->nr;
+    edx->nr+=nindex;
+    srenew(edx->x,edx->nr);
+    srenew(edx->anrs,edx->nr);
+    for (i=0;i<nindex;i++,ix++) {
+          for (pos=0; pos<ngro-1 && igro[pos]!=index[i] ; ++pos) {};  /*search element in igro*/
+          if (igro[pos]!=index[i])
+               gmx_fatal(FARGS,"Couldn't find atom with index %d in structure %s",index[i],structure);
+          edx->anrs[ix]=index[i];
+          copy_rvec(x[pos],edx->x[ix]);
+    }
+ }
+ void get_structure(t_atoms *atoms,const char *IndexFile,
+                    const char *StructureFile,struct edix *edx,int nfit,
+                    atom_id ifit[],int nav, atom_id index[])
+ {
+   atom_id *igro;  /*index corresponding to target or origin structure*/
+   int ngro;
+   int ntar;
+   rvec *xtar;
+   char  title[STRLEN];
+   char* grpname;
+   ntar=read_conffile(StructureFile,title,&xtar);
+   printf("Select an index group of %d elements that corresponds to the atoms in the structure file %s\n",
+             ntar,StructureFile);
+   get_index(atoms,IndexFile,1,&ngro,&igro,&grpname);
+   if (ngro!=ntar)
+      gmx_fatal(FARGS,"You selected an index group with %d elements instead of %d",ngro,ntar);
+   init_edx(edx);
+   filter2edx(edx,nfit,ifit,ngro,igro,xtar,StructureFile);
+   /* If average and reference/fitting structure differ, append the average structure as well */
+   if (ifit!=index) /*if fit structure is different append these coordinates, too -- don't mind duplicates*/
+      filter2edx(edx,nav,index,ngro,igro,xtar,StructureFile);
+ }
+ int gmx_make_edi(int argc,char *argv[])
+ {
+   static const char *desc[] = {
+       "[TT]make_edi[tt] generates an essential dynamics (ED) sampling input file to be used with [TT]mdrun[tt]",
+       "based on eigenvectors of a covariance matrix ([TT]g_covar[tt]) or from a",
+       "normal modes anaysis ([TT]g_nmeig[tt]).",
+       "ED sampling can be used to manipulate the position along collective coordinates",
+       "(eigenvectors) of (biological) macromolecules during a simulation. Particularly,",
+       "it may be used to enhance the sampling efficiency of MD simulations by stimulating",
+       "the system to explore new regions along these collective coordinates. A number",
+       "of different algorithms are implemented to drive the system along the eigenvectors",
+       "([TT]-linfix[tt], [TT]-linacc[tt], [TT]-radfix[tt], [TT]-radacc[tt], [TT]-radcon[tt]),",
+       "to keep the position along a certain (set of) coordinate(s) fixed ([TT]-linfix[tt]),",
+       "or to only monitor the projections of the positions onto",
+       "these coordinates ([TT]-mon[tt]).[PAR]",
+       "References:[BR]",
+       "A. Amadei, A.B.M. Linssen, B.L. de Groot, D.M.F. van Aalten and ",
+       "H.J.C. Berendsen; An efficient method for sampling the essential subspace ",
+       "of proteins., J. Biomol. Struct. Dyn. 13:615-626 (1996)[BR]",
+       "B.L. de Groot, A. Amadei, D.M.F. van Aalten and H.J.C. Berendsen; ",
+       "Towards an exhaustive sampling of the configurational spaces of the ",
+       "two forms of the peptide hormone guanylin,",
+       "J. Biomol. Struct. Dyn. 13 : 741-751 (1996)[BR]",
+       "B.L. de Groot, A.Amadei, R.M. Scheek, N.A.J. van Nuland and H.J.C. Berendsen; ",
+       "An extended sampling of the configurational space of HPr from E. coli",
+       "Proteins: Struct. Funct. Gen. 26: 314-322 (1996)",
+       "[PAR]You will be prompted for one or more index groups that correspond to the eigenvectors,",
+       "reference structure, target positions, etc.[PAR]",
+       "[TT]-mon[tt]: monitor projections of the coordinates onto selected eigenvectors.[PAR]",
+       "[TT]-linfix[tt]: perform fixed-step linear expansion along selected eigenvectors.[PAR]",
+       "[TT]-linacc[tt]: perform acceptance linear expansion along selected eigenvectors.",
+       "(steps in the desired directions will be accepted, others will be rejected).[PAR]",
+       "[TT]-radfix[tt]: perform fixed-step radius expansion along selected eigenvectors.[PAR]",
+       "[TT]-radacc[tt]: perform acceptance radius expansion along selected eigenvectors.",
+       "(steps in the desired direction will be accepted, others will be rejected).",
+       "[BB]Note:[bb] by default the starting MD structure will be taken as origin of the first",
+       "expansion cycle for radius expansion. If [TT]-ori[tt] is specified, you will be able",
+       "to read in a structure file that defines an external origin.[PAR]",
+       "[TT]-radcon[tt]: perform acceptance radius contraction along selected eigenvectors",
+       "towards a target structure specified with [TT]-tar[tt].[PAR]",
+       "NOTE: each eigenvector can be selected only once. [PAR]",
+       "[TT]-outfrq[tt]: frequency (in steps) of writing out projections etc. to [TT].edo[tt] file[PAR]",
+       "[TT]-slope[tt]: minimal slope in acceptance radius expansion. A new expansion",
+       "cycle will be started if the spontaneous increase of the radius (in nm/step)",
+       "is less than the value specified.[PAR]",
+       "[TT]-maxedsteps[tt]: maximum number of steps per cycle in radius expansion",
+       "before a new cycle is started.[PAR]",
+       "Note on the parallel implementation: since ED sampling is a 'global' thing",
+       "(collective coordinates etc.), at least on the 'protein' side, ED sampling",
+       "is not very parallel-friendly from an implentation point of view. Because",
+       "parallel ED requires some extra communication, expect the performance to be",
+       "lower as in a free MD simulation, especially on a large number of nodes. [PAR]",
+       "All output of [TT]mdrun[tt] (specify with [TT]-eo[tt]) is written to a .edo file. In the output",
+       "file, per OUTFRQ step the following information is present: [PAR]",
+       "[TT]*[tt] the step number[BR]",
+       "[TT]*[tt] the number of the ED dataset. ([BB]Note[bb] that you can impose multiple ED constraints in",
+       "a single simulation (on different molecules) if several [TT].edi[tt] files were concatenated",
+       "first. The constraints are applied in the order they appear in the [TT].edi[tt] file.) [BR]",
+       "[TT]*[tt] RMSD (for atoms involved in fitting prior to calculating the ED constraints)[BR]",
+       "* projections of the positions onto selected eigenvectors[BR]",
+       "[PAR][PAR]",
+       "FLOODING:[PAR]",
+       "with [TT]-flood[tt], you can specify which eigenvectors are used to compute a flooding potential,",
+       "which will lead to extra forces expelling the structure out of the region described",
+       "by the covariance matrix. If you switch -restrain the potential is inverted and the structure",
+       "is kept in that region.",
+       "[PAR]",
+       "The origin is normally the average structure stored in the [TT]eigvec.trr[tt] file.",
+       "It can be changed with [TT]-ori[tt] to an arbitrary position in configurational space.",
+       "With [TT]-tau[tt], [TT]-deltaF0[tt], and [TT]-Eflnull[tt] you control the flooding behaviour.",
+       "Efl is the flooding strength, it is updated according to the rule of adaptive flooding.",
+       "Tau is the time constant of adaptive flooding, high [GRK]tau[grk] means slow adaption (i.e. growth). ",
+       "DeltaF0 is the flooding strength you want to reach after tau ps of simulation.",
+       "To use constant Efl set [TT]-tau[tt] to zero.",
+       "[PAR]",
+       "[TT]-alpha[tt] is a fudge parameter to control the width of the flooding potential. A value of 2 has been found",
+       "to give good results for most standard cases in flooding of proteins.",
+       "[GRK]alpha[grk] basically accounts for incomplete sampling, if you sampled further the width of the ensemble would",
+       "increase, this is mimicked by [GRK]alpha[grk] > 1.",
+       "For restraining, [GRK]alpha[grk] < 1 can give you smaller width in the restraining potential.",
+       "[PAR]",
+       "RESTART and FLOODING:",
+       "If you want to restart a crashed flooding simulation please find the values deltaF and Efl in",
+       "the output file and manually put them into the [TT].edi[tt] file under DELTA_F0 and EFL_NULL."
+   };
+     /* Save all the params in this struct and then save it in an edi file.
+     * ignoring fields nmass,massnrs,mass,tmass,nfit,fitnrs,edo
+     */
+     static t_edipar edi_params;
+     enum  { evStepNr = evRADFIX + 1};
+     static const char* evSelections[evNr]= {NULL,NULL,NULL,NULL,NULL,NULL};
+     static const char* evOptions[evNr] = {"-linfix","-linacc","-flood","-radfix","-radacc","-radcon","-mon"};
+     static const char* evParams[evStepNr] ={NULL,NULL};
+     static const char* evStepOptions[evStepNr] = {"-linstep","-accdir","-not_used","-radstep"};
+     static const char* ConstForceStr;
+     static real* evStepList[evStepNr];
+     static real  radfix=0.0;
+     static real deltaF0=150;
+     static real deltaF=0;
+     static real tau=.1;
+     static real constEfl=0.0;
+     static real alpha=1;
+     static int eqSteps=0;
+     static int* listen[evNr];
+     static real T=300.0;
+     const real kB = 2.5 / 300.0; /* k_boltzmann in MD units */
+     static gmx_bool bRestrain = FALSE;
+     static gmx_bool bHesse=FALSE;
+     static gmx_bool bHarmonic=FALSE;
+     t_pargs pa[] = {
+     { "-mon", FALSE, etSTR, {&evSelections[evMON]},
+         "Indices of eigenvectors for projections of x (e.g. 1,2-5,9) or 1-100:10 means 1 11 21 31 ... 91" },
+     { "-linfix", FALSE, etSTR, {&evSelections[0]},
+         "Indices of eigenvectors for fixed increment linear sampling" },
+     { "-linacc", FALSE, etSTR, {&evSelections[1]},
+         "Indices of eigenvectors for acceptance linear sampling" },
+     { "-radfix", FALSE, etSTR, {&evSelections[3]},
+         "Indices of eigenvectors for fixed increment radius expansion" },
+     { "-radacc", FALSE, etSTR, {&evSelections[4]},
+         "Indices of eigenvectors for acceptance radius expansion" },
+     { "-radcon", FALSE, etSTR, {&evSelections[5]},
+         "Indices of eigenvectors for acceptance radius contraction" },
+     { "-flood",  FALSE, etSTR, {&evSelections[2]},
+         "Indices of eigenvectors for flooding"},
+     { "-outfrq", FALSE, etINT, {&edi_params.outfrq},
+         "Freqency (in steps) of writing output in [TT].edo[tt] file" },
+     { "-slope", FALSE, etREAL, { &edi_params.slope},
+         "Minimal slope in acceptance radius expansion"},
+     { "-linstep", FALSE, etSTR, {&evParams[0]},
+         "Stepsizes (nm/step) for fixed increment linear sampling (put in quotes! \"1.0 2.3 5.1 -3.1\")"},
+     { "-accdir", FALSE, etSTR, {&evParams[1]},
+         "Directions for acceptance linear sampling - only sign counts! (put in quotes! \"-1 +1 -1.1\")"},
+     { "-radstep", FALSE, etREAL, {&radfix},
+         "Stepsize (nm/step) for fixed increment radius expansion"},
+     { "-maxedsteps", FALSE, etINT, {&edi_params.maxedsteps},
+         "Maximum number of steps per cycle" },
+     { "-eqsteps", FALSE, etINT, {&eqSteps},
+         "Number of steps to run without any perturbations "},
+     { "-deltaF0", FALSE,etREAL, {&deltaF0},
+         "Target destabilization energy for flooding"},
+     { "-deltaF", FALSE, etREAL, {&deltaF},
+         "Start deltaF with this parameter - default 0, nonzero values only needed for restart"},
+     { "-tau", FALSE, etREAL, {&tau},
+         "Coupling constant for adaption of flooding strength according to deltaF0, 0 = infinity i.e. constant flooding strength"},
+     { "-Eflnull", FALSE, etREAL, {&constEfl},
+         "The starting value of the flooding strength. The flooding strength is updated "
+         "according to the adaptive flooding scheme. For a constant flooding strength use [TT]-tau[tt] 0. "},
+     { "-T", FALSE, etREAL, {&T},
+         "T is temperature, the value is needed if you want to do flooding "},
+     { "-alpha",FALSE,etREAL,{&alpha},
+         "Scale width of gaussian flooding potential with alpha^2 "},
+     { "-restrain",FALSE, etBOOL, {&bRestrain},
+         "Use the flooding potential with inverted sign -> effects as quasiharmonic restraining potential"},
+     { "-hessian",FALSE, etBOOL, {&bHesse},
+         "The eigenvectors and eigenvalues are from a Hessian matrix"},
+     { "-harmonic",FALSE, etBOOL, {&bHarmonic},
+         "The eigenvalues are interpreted as spring constant"},
+     { "-constF", FALSE, etSTR, {&ConstForceStr},
+         "Constant force flooding: manually set the forces for the eigenvectors selected with -flood "
+         "(put in quotes! \"1.0 2.3 5.1 -3.1\"). No other flooding parameters are needed when specifying the forces directly."}
+     };
+ #define NPA asize(pa)
+     rvec       *xref1;
+     int        nvec1,*eignr1=NULL;
+     rvec       *xav1,**eigvec1=NULL;
+     t_atoms    *atoms=NULL;
+     int        nav;  /* Number of atoms in the average structure */
+     char       *grpname;
+     const char *indexfile;
+     int        i;
+     atom_id    *index,*ifit;
+     int        nfit; /* Number of atoms in the reference/fit structure */
+     int ev_class; /* parameter _class i.e. evMON, evRADFIX etc. */
+     int nvecs;
+     real *eigval1=NULL; /* in V3.3 this is parameter of read_eigenvectors */
+     const char *EdiFile;
+     const char *TargetFile;
+     const char *OriginFile;
+     const char *EigvecFile;
+     output_env_t oenv;
+     /*to read topology file*/
+     t_topology top;
+     int        ePBC;
+     char       title[STRLEN];
+     matrix     topbox;
+     rvec       *xtop;
+     gmx_bool bTop, bFit1;
+     t_filenm fnm[] = {
+     { efTRN, "-f",    "eigenvec",    ffREAD  },
+     { efXVG, "-eig",  "eigenval",    ffOPTRD },
+     { efTPS, NULL,    NULL,          ffREAD },
+     { efNDX, NULL,    NULL,  ffOPTRD },
+     { efSTX, "-tar", "target", ffOPTRD},
+     { efSTX, "-ori", "origin", ffOPTRD},
+     { efEDI, "-o", "sam", ffWRITE }
+     };
+ #define NFILE asize(fnm)
+     edi_params.outfrq=100; edi_params.slope=0.0; edi_params.maxedsteps=0;
+     CopyRight(stderr,argv[0]);
+     parse_common_args(&argc,argv, 0 ,
+                       NFILE,fnm,NPA,pa,asize(desc),desc,0,NULL,&oenv);
+     indexfile=ftp2fn_null(efNDX,NFILE,fnm);
+     EdiFile=ftp2fn(efEDI,NFILE,fnm);
+     TargetFile      = opt2fn_null("-tar",NFILE,fnm);
+     OriginFile      = opt2fn_null("-ori",NFILE,fnm);
+     for (ev_class=0; ev_class<evNr; ++ev_class) {
+         if (opt2parg_bSet(evOptions[ev_class],NPA,pa)) {
+             /*get list of eigenvectors*/
+             nvecs=sscan_list(&(listen[ev_class]),opt2parg_str(evOptions[ev_class],NPA,pa),evOptions[ev_class]);
+             if (ev_class<evStepNr-2) {
+                 /*if apropriate get list of stepsizes for these eigenvectors*/
+                 if (opt2parg_bSet(evStepOptions[ev_class],NPA,pa))
+                     evStepList[ev_class]=
+                         scan_vecparams(opt2parg_str(evStepOptions[ev_class],NPA,pa),evStepOptions[ev_class],nvecs);
+                 else { /*if list is not given fill with zeros */
+                     snew(evStepList[ev_class],nvecs);
+                     for (i=0; i<nvecs; i++)
+                         evStepList[ev_class][i]=0.0;
+                 }
+             } else if (ev_class == evRADFIX && opt2parg_bSet(evStepOptions[ev_class],NPA,pa)) {
+                 snew(evStepList[ev_class],nvecs);
+                 for (i=0; i<nvecs; i++)
+                     evStepList[ev_class][i]=radfix;
+             } else if (ev_class == evFLOOD) {
+                 snew(evStepList[ev_class],nvecs);
+                 /* Are we doing constant force flooding? In that case, we read in
+                  * the fproj values from the command line */
+                 if (opt2parg_bSet("-constF", NPA, pa))
+                 {
+                     evStepList[ev_class] = scan_vecparams(opt2parg_str("-constF",NPA,pa),"-constF",nvecs);
+                 }
+             } else {}; /*to avoid ambiguity   */
+         } else { /* if there are no eigenvectors for this option set list to zero */
+             listen[ev_class]=NULL;
+             snew(listen[ev_class],1);
+             listen[ev_class][0]=0;
+         }
+     }
+     /* print the interpreted list of eigenvectors - to give some feedback*/
+     for (ev_class=0; ev_class<evNr; ++ev_class) {
+         printf("Eigenvector list %7s consists of the indices: ",evOptions[ev_class]);
+         i=0;
+         while(listen[ev_class][i])
+             printf("%d ",listen[ev_class][i++]);
+         printf("\n");
+     }
+     EigvecFile=NULL;
+     EigvecFile=opt2fn("-f",NFILE,fnm);
+     /*read eigenvectors from eigvec.trr*/
+     read_eigenvectors(EigvecFile,&nav,&bFit1,
+                       &xref1,&edi_params.fitmas,&xav1,&edi_params.pcamas,&nvec1,&eignr1,&eigvec1,&eigval1);
+     bTop=read_tps_conf(ftp2fn(efTPS,NFILE,fnm),
+                        title,&top,&ePBC,&xtop,NULL,topbox,0);
+     atoms=&top.atoms;
+     printf("\nSelect an index group of %d elements that corresponds to the eigenvectors\n",nav);
+     get_index(atoms,indexfile,1,&i,&index,&grpname); /*if indexfile != NULL parameter 'atoms' is ignored */
+     if (i!=nav) {
+         gmx_fatal(FARGS,"you selected a group with %d elements instead of %d",
+                   i,nav);
+     }
+     printf("\n");
+     if (xref1==NULL)
+     {
+         if (bFit1)
+         {
+             /* if g_covar used different coordinate groups to fit and to do the PCA */
+             printf("\nNote: the structure in %s should be the same\n"
+                      "      as the one used for the fit in g_covar\n",ftp2fn(efTPS,NFILE,fnm));
+             printf("\nSelect the index group that was used for the least squares fit in g_covar\n");
+         }
+         else
+         {
+             printf("\nNote: Apparently no fitting was done in g_covar.\n"
+                      "      However, you need to select a reference group for fitting in mdrun\n");
+         }
+         get_index(atoms,indexfile,1,&nfit,&ifit,&grpname);
+         snew(xref1,nfit);
+         for (i=0;i<nfit;i++)
+             copy_rvec(xtop[ifit[i]],xref1[i]);
+     }
+     else
+     {
+         nfit=nav;
+         ifit=index;
+     }
+     if (opt2parg_bSet("-constF", NPA, pa))
+     {
+         /* Constant force flooding is special: Most of the normal flooding
+          * options are not needed. */
+         edi_params.flood.bConstForce = TRUE;
+     }
+     else
+     {
+         /* For normal flooding read eigenvalues and store them in evSteplist[evFLOOD] */
+         if ( listen[evFLOOD][0]!=0)
+             read_eigenvalues(listen[evFLOOD],opt2fn("-eig",NFILE,fnm),evStepList[evFLOOD],bHesse,kB*T);
+         edi_params.flood.tau=tau;
+         edi_params.flood.deltaF0=deltaF0;
+         edi_params.flood.deltaF=deltaF;
+         edi_params.presteps=eqSteps;
+         edi_params.flood.kT=kB*T;
+         edi_params.flood.bHarmonic=bHarmonic;
+         if (bRestrain)
+         {
+             /* Trick: invert sign of Efl and alpha2 then this will give the same sign in the exponential and inverted sign outside */
+             edi_params.flood.constEfl=-constEfl;
+             edi_params.flood.alpha2=-sqr(alpha);
+         }
+         else
+         {
+             edi_params.flood.constEfl=constEfl;
+             edi_params.flood.alpha2=sqr(alpha);
+         }
+     }
+     edi_params.ned=nav;
+   /*number of system atoms  */
+   edi_params.nini=atoms->nr;
+   /*store reference and average structure in edi_params*/
+   make_t_edx(&edi_params.sref,nfit,xref1,ifit );
+   make_t_edx(&edi_params.sav ,nav ,xav1 ,index);
+   /* Store target positions in edi_params */
+   if (opt2bSet("-tar",NFILE,fnm))
+   {
+       if (0 != listen[evFLOOD][0])
+       {
+           fprintf(stderr, "\nNote: Providing a TARGET structure has no effect when using flooding.\n"
+                           "      You may want to use -ori to define the flooding potential center.\n\n");
+       }
+       get_structure(atoms,indexfile,TargetFile,&edi_params.star,nfit,ifit,nav,index);
+   }
+   else
+   {
+       make_t_edx(&edi_params.star,0,NULL,index);
+   }
+   /* Store origin positions */
+   if (opt2bSet("-ori",NFILE,fnm))
+   {
+       get_structure(atoms,indexfile,OriginFile,&edi_params.sori,nfit,ifit,nav,index);
+   }
+   else
+   {
+       make_t_edx(&edi_params.sori,0,NULL,index);
+   }
+   /* Write edi-file */
+   write_the_whole_thing(ffopen(EdiFile,"w"), &edi_params, eigvec1,nvec1, listen, evStepList);
+   thanx(stderr);
+   return 0;
+ }
Simple merge
Simple merge
index f478094d3f5372539076f111e505fb4a0028d1ab,0000000000000000000000000000000000000000..0ef0e5541d7d01731926fffba0292795325f6fb5
mode 100644,000000..100644
--- /dev/null
@@@ -1,3198 -1,0 +1,3198 @@@
-                     while ( (ibin+=nbins) < 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
 + */
 +
 +/*! \internal \file
 + *  \brief Implementation of the Weighted Histogram Analysis Method (WHAM)
 + *
 + *  \author Jochen Hub <jhub@gwdg.de>
 + */
 +
 +#ifdef HAVE_CONFIG_H
 +#include <config.h>
 +#endif
 +#include <stdio.h>
 +#include <stdlib.h>
 +#include <sstream>
 +
 +#include "statutil.h"
 +#include "typedefs.h"
 +#include "smalloc.h"
 +#include "vec.h"
 +#include "copyrite.h"
 +#include "statutil.h"
 +#include "tpxio.h"
 +#include "names.h"
 +#include "gmx_random.h"
 +#include "gmx_ana.h"
 +#include "macros.h"
 +
 +#include "string2.h"
 +#include "xvgr.h"
 +
 +//! longest file names allowed in input files
 +#define WHAM_MAXFILELEN 2048
 +
 +/*! \brief
 + * enum for energy units
 + */
 +enum { enSel, en_kJ, en_kCal, en_kT, enNr };
 +/*! \brief
 + * enum for type of input files (pdos, tpr, or pullf)
 + */
 +enum { whamin_unknown, whamin_tpr, whamin_pullxf, whamin_pdo };
 +
 +/*! \brief enum for bootstrapping method
 + *
 + * These bootstrap methods are supported:
 + *  - bootstrap complete histograms with continuous weights (Bayesian bootstrap)
 + *    (bsMethod_BayesianHist)
 + *  - bootstrap complete histograms (bsMethod_hist)
 + *  - bootstrap trajectories from given umbrella histograms. This generates new
 + *    "synthetic" histograms (bsMethod_traj)
 + *  - bootstrap trajectories from Gaussian with mu/sigma computed from
 + *    the respective histogram (bsMethod_trajGauss). This gives very similar
 + *    results compared to bsMethod_traj.
 + *
 + *  ********************************************************************
 + *  FOR MORE DETAILS ON THE BOOTSTRAP METHODS (INCLUDING EXAMPLES), SEE
 + *  JS Hub, BL de Groot, D van der Spoel
 + *  g_wham - A free weighted histogram analysis implementation including
 + *  robust error and autocorrelation estimates,
 + *  J Chem Theory Comput, 6(12), 3713-3720 (2010)
 + *  ********************************************************************
 + */
 +enum { bsMethod_unknown, bsMethod_BayesianHist, bsMethod_hist, 
 +       bsMethod_traj, bsMethod_trajGauss };
 +
 +
 +//! Parameters of the umbrella potentials
 +typedef struct
 +{
 +    /*!
 +     * \name Using umbrella pull code since gromacs 4.x
 +     */
 +    /*!\{*/
 +    int npullgrps;      //!< nr of pull groups in tpr file
 +    int pull_geometry;  //!< such as distance, position
 +    ivec pull_dim;      //!< pull dimension with geometry distance
 +    int  pull_ndim;     //!< nr of pull_dim != 0
 +    real *k;            //!< force constants in tpr file
 +    rvec *init_dist;    //!< reference displacements
 +    real *umbInitDist;  //!< reference displacement in umbrella direction
 +    /*!\}*/
 +    /*!
 +     * \name Using PDO files common until gromacs 3.x
 +     */
 +    /*!\{*/
 +    int nSkip;
 +    char Reference[256];
 +    int nPull;
 +    int nDim;
 +    ivec Dims;
 +    char PullName[4][256];
 +    double UmbPos[4][3];
 +    double UmbCons[4][3];
 +    /*!\}*/
 +} t_UmbrellaHeader;
 +
 +//! Data in the umbrella histograms
 +typedef struct
 +{
 +    int nPull;            //!< nr of pull groups in this pdo or pullf/x file
 +    double **Histo;       //!< nPull histograms
 +    double **cum;         //!< nPull cumulative distribution functions
 +    int nBin;             //!< nr of bins. identical to opt->bins
 +    double *k;            //!< force constants for the nPull groups
 +    double *pos;          //!< umbrella positions for the nPull groups
 +    double *z;            //!< z=(-Fi/kT) for the nPull groups. These values are iteratively computed during wham
 +    int *N;               //!< nr of data points in nPull histograms.
 +    int *Ntot;            //!< also nr of data points. N and Ntot only differ if bHistEq==TRUE
 +
 +    /*! \brief  g = 1 + 2*tau[int]/dt where tau is the integrated autocorrelation time. 
 +     *
 +     * Compare, e.g. Ferrenberg/Swendsen, PRL 63:1195 (1989),     
 +     * Kumar et al, J Comp Chem 13, 1011-1021 (1992), eq. 28
 +     */
 +    double *g;
 +    double *tau;         //!< intetrated autocorrelation time (IACT)
 +    double *tausmooth;   //!< smoothed IACT
 +
 +    double dt;           //!< timestep in the input data. Can be adapted with g_wham option -dt
 +
 +    /*! \brief TRUE, if any data point of the histogram is within min and max, otherwise FALSE */
 +    gmx_bool **bContrib;
 +    real **ztime;         //!< input data z(t) as a function of time. Required to compute ACTs
 +
 +    /*! \brief average force estimated from average displacement, fAv=dzAv*k
 +     *
 +     *  Used for integration to guess the potential.
 +     */
 +    real *forceAv;
 +    real *aver;           //!< average of histograms
 +    real *sigma;          //!< stddev of histograms
 +    double *bsWeight;     //!< for bootstrapping complete histograms with continuous weights
 +} t_UmbrellaWindow;
 +
 +//! Selection of pull groups to be used in WHAM (one structure for each tpr file)
 +typedef struct
 +{
 +    int n;               //!< total nr of pull groups in this tpr file
 +    int nUse;            //!< nr of pull groups used
 +    gmx_bool *bUse;      //!< boolean array of size n. =1 if used, =0 if not
 +} t_groupselection;
 +
 +//! Parameters of WHAM
 +typedef struct
 +{
 +    /*!
 +     * \name Input stuff
 +     */
 +    /*!\{*/
 +    const char *fnTpr,*fnPullf,*fnGroupsel;
 +    const char *fnPdo,*fnPullx;      //!< file names of input
 +    gmx_bool bTpr,bPullf,bPdo,bPullx;//!< input file types given?
 +    real tmin, tmax, dt;             //!< only read input within tmin and tmax with dt
 +
 +    gmx_bool bInitPotByIntegration;  //!< before WHAM, guess potential by force integration. Yields 1.5 to 2 times faster convergence
 +    int stepUpdateContrib;           //!< update contribution table every ... iterations. Accelerates WHAM.
 +    int nGroupsel;                   //!< if >0: use only certain group in WHAM, if ==0: use all groups
 +    t_groupselection *groupsel;      //!< for each tpr file: which pull groups to use in WHAM?
 +    /*!\}*/
 +    /*!
 +     * \name Basic WHAM options
 +     */
 +    /*!\{*/
 +    int bins;                        //!< nr of bins, min, max, and dz of profile
 +    real min,max,dz;
 +    real Temperature,Tolerance;      //!< temperature, converged when probability changes less than Tolerance
 +    gmx_bool bCycl;                  //!< generate cyclic (periodic) PMF
 +    /*!\}*/
 +    /*!
 +     * \name Output control
 +     */
 +    /*!\{*/
 +    gmx_bool bLog;                   //!< energy output (instead of probability) for profile
 +    int unit;                        //!< unit for PMF output kJ/mol or kT or kCal/mol
 +    gmx_bool bSym;                   //!< symmetrize PMF around z=0 after WHAM, useful for membranes etc.
 +    /*! \brief after wham, set prof to zero at this z-position.
 +     * When bootstrapping, set zProf0 to a "stable" reference position.
 +     */
 +    real zProf0;
 +    gmx_bool bProf0Set;              //!< setting profile to 0 at zProf0?
 +
 +    gmx_bool bBoundsOnly,bHistOnly;  //!< determine min and max, or write histograms and exit
 +    gmx_bool bAuto;                  //!< determine min and max automatically but do not exit
 +
 +    gmx_bool verbose;               //!< more noisy wham mode
 +    int stepchange;                 //!< print maximum change in prof after how many interations
 +    output_env_t oenv;              //!< xvgr options
 +    /*!\}*/
 +    /*!
 +     * \name Autocorrelation stuff
 +     */
 +    /*!\{*/
 +    gmx_bool bTauIntGiven,bCalcTauInt; //!< IACT given or should be calculated?
 +    real sigSmoothIact;                //!< sigma of Gaussian to smooth ACTs
 +    gmx_bool bAllowReduceIact;         //!< Allow to reduce ACTs during smoothing. Otherwise ACT are only increased during smoothing
 +    real acTrestart;                   //!< when computing ACT, time between restarting points
 +
 +    /* \brief Enforce the same weight for each umbella window, that is
 +     *  calculate with the same number of data points for
 +     *  each window. That can be reasonable, if the histograms
 +     *  have different length, but due to autocorrelation,
 +     *  a longer simulation should not have larger weightin wham.
 +     */
 +    gmx_bool bHistEq;
 +    /*!\}*/
 +
 +    /*!
 +     * \name Bootstrapping stuff
 +     */
 +    /*!\{*/
 +    int nBootStrap;              //!< nr of bootstraps (50 is usually enough)
 +
 +    /* \brief bootstrap method
 +     *
 +     * if == bsMethod_hist, consider complete histograms as independent
 +     * data points and, hence, only mix complete histograms.
 +     * if == bsMethod_BayesianHist, consider complete histograms
 +     * as independent data points, but assign random weights
 +     * to the histograms during the bootstrapping ("Bayesian bootstrap")
 +     * In case of long correlations (e.g., inside a channel), these
 +     * will yield a more realistic error.
 +     * if == bsMethod_traj(Gauss), generate synthetic histograms
 +     * for each given
 +     * histogram by generating an autocorrelated random sequence
 +     * that is distributed according to the respective given
 +     * histogram. With bsMethod_trajGauss, bootstrap from a Gaussian
 +     * (instead of from the umbrella histogram) to generate a new
 +     * histogram.
 +     */
 +    int bsMethod;
 +
 +    /* \brief  autocorrelation time (ACT) used to generate synthetic histograms. If ==0, use calculated ACF */
 +    real tauBootStrap;
 +
 +    /* \brief when mixing histograms, mix only histograms withing blocks
 +              long the reaction coordinate xi. Avoids gaps along xi. */
 +    int histBootStrapBlockLength;
 +
 +    int bsSeed;                    //!< random seed for bootstrapping
 +
 +    /* \brief Write cumulative distribution functions (CDFs) of histograms
 +              and write the generated histograms for each bootstrap */
 +    gmx_bool bs_verbose;
 +    /*!\}*/
 +    /*!
 +     * \name tabulated umbrella potential stuff
 +     */
 +    /*!\{*/
 +    gmx_bool bTab;
 +    double *tabX,*tabY,tabMin,tabMax,tabDz;
 +    int tabNbins;
 +    /*!\}*/
 +    gmx_rng_t rng;                  //!< gromacs random number generator
 +} t_UmbrellaOptions;
 +
 +//! Make an umbrella window (may contain several histograms)
 +t_UmbrellaWindow * initUmbrellaWindows(int nwin)
 +{
 +    t_UmbrellaWindow *win;
 +    int i;
 +    snew(win,nwin);
 +    for (i=0; i<nwin; i++)
 +    {
 +        win[i].Histo = win[i].cum  = 0;
 +        win[i].k     = win[i].pos  = win[i].z =0;
 +        win[i].N     = win[i].Ntot = 0;
 +        win[i].g     = win[i].tau  = win[i].tausmooth = 0;
 +        win[i].bContrib=0;
 +        win[i].ztime=0;
 +        win[i].forceAv=0;
 +        win[i].aver = win[i].sigma = 0;
 +        win[i].bsWeight = 0;
 +    }
 +    return win;
 +}
 +
 +//! Delete an umbrella window (may contain several histograms)
 +void freeUmbrellaWindows(t_UmbrellaWindow *win, int nwin)
 +{
 +    int i,j;
 +    for (i=0; i<nwin; i++)
 +    {
 +        if (win[i].Histo)
 +            for (j=0;j<win[i].nPull;j++)
 +                sfree(win[i].Histo[j]);
 +        if (win[i].cum)
 +            for (j=0;j<win[i].nPull;j++)
 +                sfree(win[i].cum[j]);
 +        if (win[i].bContrib)
 +            for (j=0;j<win[i].nPull;j++)
 +                sfree(win[i].bContrib[j]);
 +        sfree(win[i].Histo);
 +        sfree(win[i].cum);
 +        sfree(win[i].k);
 +        sfree(win[i].pos);
 +        sfree(win[i].z);
 +        sfree(win[i].N);
 +        sfree(win[i].Ntot);
 +        sfree(win[i].g);
 +        sfree(win[i].tau);
 +        sfree(win[i].tausmooth);
 +        sfree(win[i].bContrib);
 +        sfree(win[i].ztime);
 +        sfree(win[i].forceAv);
 +        sfree(win[i].aver);
 +        sfree(win[i].sigma);
 +        sfree(win[i].bsWeight);
 +    }
 +    sfree(win);
 +}
 +
 +/*! \brief
 + * Read and setup tabulated umbrella potential
 + */
 +void setup_tab(const char *fn,t_UmbrellaOptions *opt)
 +{
 +    int i,ny,nl;
 +    double **y;
 +
 +    printf("Setting up tabulated potential from file %s\n",fn);
 +    nl=read_xvg(fn,&y,&ny);
 +    opt->tabNbins=nl;
 +    if (ny!=2)
 +        gmx_fatal(FARGS,"Found %d columns in %s. Expected 2.\n",ny,fn);
 +    opt->tabMin=y[0][0];
 +    opt->tabMax=y[0][nl-1];
 +    opt->tabDz=(opt->tabMax-opt->tabMin)/(nl-1);
 +    if (opt->tabDz<=0)
 +        gmx_fatal(FARGS,"The tabulated potential in %s must be provided in \n"
 +                  "ascending z-direction",fn);
 +    for (i=0;i<nl-1;i++)
 +        if  (fabs(y[0][i+1]-y[0][i]-opt->tabDz) > opt->tabDz/1e6)
 +            gmx_fatal(FARGS,"z-values in %s are not equally spaced.\n",ny,fn);
 +    snew(opt->tabY,nl);
 +    snew(opt->tabX,nl);
 +    for (i=0;i<nl;i++)
 +    {
 +        opt->tabX[i]=y[0][i];
 +        opt->tabY[i]=y[1][i];
 +    }
 +    printf("Found equally spaced tabulated potential from %g to %g, spacing %g\n",
 +           opt->tabMin,opt->tabMax,opt->tabDz);
 +}
 +
 +//! Read the header of an PDO file (position, force const, nr of groups)
 +void read_pdo_header(FILE * file,t_UmbrellaHeader * header, t_UmbrellaOptions *opt)
 +{
 +    char line[2048];
 +    char Buffer0[256], Buffer1[256], Buffer2[256], Buffer3[256], Buffer4[256];
 +    int i;
 +    std::istringstream ist;
 +
 +    /*  line 1 */
 +    if (fgets(line,2048,file) == NULL)
 +        gmx_fatal(FARGS,"Error reading header from pdo file\n");
 +    ist.str(line);
 +    ist >> Buffer0 >> Buffer1 >> Buffer2;
 +    if(strcmp(Buffer1,"UMBRELLA"))
 +        gmx_fatal(FARGS,"This does not appear to be a valid pdo file. Found %s, expected %s\n"
 +                  "(Found in first line: `%s')\n",
 +                  Buffer1, "UMBRELLA",line);
 +    if(strcmp(Buffer2,"3.0"))
 +        gmx_fatal(FARGS,"This does not appear to be a version 3.0 pdo file");
 +
 +    /*  line 2 */
 +    if (fgets(line,2048,file) == NULL)
 +        gmx_fatal(FARGS,"Error reading header from pdo file\n");
 +    ist.str(line);
 +    ist >> Buffer0 >> Buffer1 >> Buffer2 >> header->Dims[0] >> header->Dims[1] >> header->Dims[2];
 +    /* printf("%d %d %d\n", header->Dims[0],header->Dims[1],header->Dims[2]); */
 +
 +    header->nDim = header->Dims[0] + header->Dims[1] + header->Dims[2];
 +    if(header->nDim!=1)
 +        gmx_fatal(FARGS,"Currently only supports one dimension");
 +
 +    /* line3 */
 +    if (fgets(line,2048,file) == NULL)
 +        gmx_fatal(FARGS,"Error reading header from pdo file\n");
 +    ist.str(line);
 +    ist >> Buffer0 >> Buffer1 >> header->nSkip;
 +
 +    /* line 4 */ 
 +    if (fgets(line,2048,file) == NULL)
 +        gmx_fatal(FARGS,"Error reading header from pdo file\n");
 +    ist.str(line);
 +    ist >> Buffer0 >> Buffer1 >> Buffer2 >> header->Reference;
 +
 +    /* line 5 */
 +    if (fgets(line,2048,file) == NULL)
 +        gmx_fatal(FARGS,"Error reading header from pdo file\n");
 +    ist.str(line);
 +    ist >> Buffer0 >> Buffer1 >> Buffer2 >> Buffer3 >> Buffer4 >> header->nPull;
 +
 +    if (opt->verbose)
 +        printf("\tFound nPull=%d , nSkip=%d, ref=%s\n",header->nPull,header->nSkip,
 +               header->Reference);
 +
 +    for(i=0;i<header->nPull;++i)
 +    {
 +        if (fgets(line,2048,file) == NULL)
 +            gmx_fatal(FARGS,"Error reading header from pdo file\n");
 +        ist.str(line);
 +        ist >> Buffer0 >> Buffer1 >> Buffer2 >> header->PullName[i];
 +        ist >> Buffer0 >> Buffer1 >> header->UmbPos[i][0];
 +        ist >> Buffer0 >> Buffer1 >> header->UmbCons[i][0];
 +
 +        if (opt->verbose)
 +            printf("\tpullgroup %d, pullname = %s, UmbPos = %g, UmbConst = %g\n",
 +                   i,header->PullName[i],header->UmbPos[i][0],header->UmbCons[i][0]);
 +    }
 +
 +    if (fgets(line,2048,file) == NULL)
 +        gmx_fatal(FARGS,"Cannot read from file\n");
 +    ist.str(line);
 +    ist >> Buffer3;
 +    if (strcmp(Buffer3,"#####") != 0)
 +        gmx_fatal(FARGS,"Expected '#####', found %s. Hick.\n",Buffer3);
 +}
 +
 +//! smarter fgets
 +static char *fgets3(FILE *fp,char ptr[],int *len)
 +{
 +    char *p;
 +    int  slen;
 +    
 +    if (fgets(ptr,*len-1,fp) == NULL)
 +        return NULL;
 +    p = ptr;
 +    while ((strchr(ptr,'\n') == NULL) && (!feof(fp))) 
 +    {
 +        /* This line is longer than len characters, let's increase len! */
 +        *len += STRLEN;
 +        p    += STRLEN;
 +        srenew(ptr,*len);
 +        if (fgets(p-1,STRLEN,fp) == NULL)
 +            break;
 +    }
 +    slen = strlen(ptr);
 +    if (ptr[slen-1] == '\n')
 +        ptr[slen-1] = '\0';
 +    
 +    return ptr;
 +}
 +
 +/*! \brief Read the data columns of and PDO file.
 + *
 + *  TO DO: Get rid of the scanf function to avoid the clang warning.
 + *         At the moment, this warning is avoided by hiding the format string
 + *         the variable fmtlf.
 + */
 +void read_pdo_data(FILE * file, t_UmbrellaHeader * header,
 +                   int fileno, t_UmbrellaWindow * win,
 +                   t_UmbrellaOptions *opt,
 +                   gmx_bool bGetMinMax,real *mintmp,real *maxtmp)
 +{
 +    int i,inttemp,bins,count,ntot;
 +    real min,max,minfound=1e20,maxfound=-1e20;
 +    double temp,time,time0=0,dt;
 +    char *ptr=0;
 +    t_UmbrellaWindow * window=0;
 +    gmx_bool timeok,dt_ok=1;
 +    char  *tmpbuf=0,fmt[256],fmtign[256],fmtlf[5]="%lf";
 +    int    len=STRLEN,dstep=1;
 +    const int blocklen=4096;
 +    int *lennow=0;
 +    
 +    if (!bGetMinMax)
 +    {
 +        bins=opt->bins;
 +        min=opt->min;
 +        max=opt->max;
 +        
 +        window=win+fileno;
 +        /* Need to alocate memory and set up structure */
 +        window->nPull=header->nPull;
 +        window->nBin=bins;
 +        
 +        snew(window->Histo,window->nPull);
 +        snew(window->z,window->nPull);
 +        snew(window->k,window->nPull);
 +        snew(window->pos,window->nPull);
 +        snew(window->N, window->nPull);
 +        snew(window->Ntot, window->nPull);
 +        snew(window->g, window->nPull);
 +        snew(window->bsWeight, window->nPull);
 +        
 +        window->bContrib=0;
 +        
 +        if (opt->bCalcTauInt)
 +            snew(window->ztime, window->nPull);
 +        else
 +            window->ztime=0;
 +        snew(lennow,window->nPull);
 +        
 +        for(i=0;i<window->nPull;++i) 
 +        {
 +            window->z[i]=1;
 +            window->bsWeight[i]=1.;
 +            snew(window->Histo[i],bins);
 +            window->k[i]=header->UmbCons[i][0];
 +            window->pos[i]=header->UmbPos[i][0];
 +            window->N[i]=0;
 +            window->Ntot[i]=0;
 +            window->g[i]=1.;
 +            if (opt->bCalcTauInt)
 +                window->ztime[i]=0;      
 +        }
 +        
 +        /* Done with setup */
 +    }
 +    else
 +    {
 +        minfound=1e20;
 +        maxfound=-1e20;
 +        min=max=bins=0; /* Get rid of warnings */
 +    }
 +    
 +    count=0;
 +    snew(tmpbuf,len);
 +    while ( (ptr=fgets3(file,tmpbuf,&len)) != NULL)
 +    {
 +        trim(ptr);
 +        
 +        if (ptr[0] == '#' || strlen(ptr)<2)
 +            continue;
 +        
 +        /* Initiate format string */
 +        fmtign[0] = '\0';
 +        strcat(fmtign,"%*s");
 +        
 +        sscanf(ptr,fmtlf,&time); /* printf("Time %f\n",time); */
 +        /* Round time to fs */
 +        time=1.0/1000*( static_cast<int> (time*1000+0.5) );
 +        
 +        /* get time step of pdo file */
 +        if (count==0)
 +            time0=time;
 +        else if (count==1)
 +        {
 +            dt=time-time0;
 +            if (opt->dt>0.0)
 +            {
 +                dstep=static_cast<int>(opt->dt/dt+0.5);
 +                if (dstep==0)
 +                    dstep=1;
 +            }
 +            if (!bGetMinMax)
 +                window->dt=dt*dstep;
 +        }
 +        count++;
 +        
 +        dt_ok=((count-1)%dstep == 0);
 +        timeok=(dt_ok && time >= opt->tmin && time <= opt->tmax);
 +        /* if (opt->verbose)
 +           printf(" time = %f, (tmin,tmax)=(%e,%e), dt_ok=%d timeok=%d\n", 
 +           time,opt->tmin, opt->tmax, dt_ok,timeok); */
 +        
 +        if (timeok)
 +        {
 +            for(i=0;i<header->nPull;++i) 
 +            {
 +                strcpy(fmt,fmtign);
 +                strcat(fmt,"%lf");      /* Creating a format stings such as "%*s...%*s%lf" */
 +                strcat(fmtign,"%*s");   /* ignoring one more entry in the next loop */
 +                if(sscanf(ptr,fmt,&temp)) 
 +                {
 +                    temp+=header->UmbPos[i][0];
 +                    if (bGetMinMax)
 +                    {
 +                        if (temp<minfound)
 +                            minfound=temp;
 +                        if (temp>maxfound)
 +                            maxfound=temp;
 +                    }
 +                    else{
 +                        if (opt->bCalcTauInt)
 +                        {
 +                            /* save time series for autocorrelation analysis */
 +                            ntot=window->Ntot[i];
 +                            if (ntot>=lennow[i])
 +                            {
 +                                lennow[i]+=blocklen;
 +                                srenew(window->ztime[i],lennow[i]);
 +                            }
 +                            window->ztime[i][ntot]=temp;
 +                        }
 +                        
 +                        temp-=min;
 +                        temp/=(max-min);
 +                        temp*=bins;
 +                        temp=floor(temp);
 +                        
 +                        inttemp = static_cast<int> (temp);
 +                        if (opt->bCycl)
 +                        {
 +                            if (inttemp < 0)
 +                                inttemp+=bins;
 +                            else if (inttemp >= bins)
 +                                inttemp-=bins;
 +                        }
 +                        
 +                        if(inttemp >= 0 && inttemp < bins) 
 +                        {
 +                            window->Histo[i][inttemp]+=1.;
 +                            window->N[i]++;
 +                        }
 +                        window->Ntot[i]++;
 +                    }
 +                }       
 +            }
 +        }
 +        if (time>opt->tmax)
 +        {
 +            if (opt->verbose)
 +                printf("time %f larger than tmax %f, stop reading pdo file\n",time,opt->tmax);
 +            break;
 +        }
 +    }
 +    
 +    if (bGetMinMax)
 +    {
 +        *mintmp=minfound;
 +        *maxtmp=maxfound;
 +    }
 +    
 +    sfree(lennow);
 +    sfree(tmpbuf);
 +}
 +
 +/*! \brief Set identical weights for all histograms
 + *
 + * Normally, the weight is given by the number data points in each
 + * histogram, together with the autocorrelation time. This can be overwritten
 + * by this routine (not recommended). Since we now support autocorrelations, it is better to set
 + * an appropriate autocorrelation times instead of using this function.
 + */
 +void enforceEqualWeights(t_UmbrellaWindow * window,int nWindows)
 +{
 +    int i,k,j,NEnforced;
 +    double ratio;
 +    
 +    NEnforced=window[0].Ntot[0];
 +    printf("\nFound -hist-eq. Enforcing equal weights for all histograms, \ni.e. doing a "
 +           "non-weighted histogram analysis method. Ndata = %d\n",NEnforced);
 +    /* enforce all histograms to have the same weight as the very first histogram */
 +    
 +    for(j=0;j<nWindows;++j)
 +    {
 +        for(k=0;k<window[j].nPull;++k) 
 +        {
 +            ratio=1.0*NEnforced/window[j].Ntot[k];
 +            for(i=0;i<window[0].nBin;++i)
 +            {
 +                window[j].Histo[k][i]*=ratio;
 +            }
 +            window[j].N[k]=static_cast<int>(ratio*window[j].N[k] + 0.5);
 +        }
 +    }
 +}
 +
 +/*! \brief Simple linear interpolation between two given tabulated points 
 + */
 +double tabulated_pot(double dist, t_UmbrellaOptions *opt)
 +{
 +    int jl,ju;
 +    double pl,pu,dz,dp;
 +
 +    jl=static_cast<int> (floor((dist-opt->tabMin)/opt->tabDz));
 +    ju=jl+1;
 +    if (jl<0 || ju>=opt->tabNbins)
 +    {
 +        gmx_fatal(FARGS,"Distance %f out of bounds of tabulated potential (jl=%d, ju=%d).\n"
 +                  "Provide an extended table.",dist,jl,ju);
 +    }
 +    pl=opt->tabY[jl];
 +    pu=opt->tabY[ju];
 +    dz=dist-opt->tabX[jl];
 +    dp=(pu-pl)*dz/opt->tabDz;
 +    return pl+dp;
 +}
 +
 +
 +/*! \brief
 + * Check which bins substiantially contribute (accelerates WHAM)
 + *
 + * Don't worry, that routine does not mean we compute the PMF in limited precision.
 + * After rapid convergence (using only substiantal contributions), we always switch to
 + * full precision. 
 + */
 +void setup_acc_wham(double *profile,t_UmbrellaWindow * window,int nWindows, 
 +                    t_UmbrellaOptions *opt)
 +{
 +    int i,j,k,nGrptot=0,nContrib=0,nTot=0;
 +    double U,min=opt->min,dz=opt->dz,temp,ztot_half,distance,ztot,contrib1,contrib2;
 +    gmx_bool bAnyContrib;
 +    static int bFirst=1;
 +    static double wham_contrib_lim;
 +    
 +    if (bFirst)
 +    {
 +        for(i=0;i<nWindows;++i)
 +        {
 +            nGrptot+=window[i].nPull;
 +        }
 +        wham_contrib_lim=opt->Tolerance/nGrptot;
 +    }
 +    
 +    ztot=opt->max-opt->min;
 +    ztot_half=ztot/2;
 +      
 +    for(i=0;i<nWindows;++i) 
 +    {
 +        if ( ! window[i].bContrib)
 +        {
 +            snew(window[i].bContrib,window[i].nPull);
 +        }
 +        for(j=0;j<window[i].nPull;++j) 
 +        {
 +            if ( ! window[i].bContrib[j])
 +                snew(window[i].bContrib[j],opt->bins);
 +            bAnyContrib=FALSE;
 +            for(k=0;k<opt->bins;++k) 
 +            {
 +                temp=(1.0*k+0.5)*dz+min;
 +                distance = temp - window[i].pos[j];   /* distance to umbrella center */
 +                if (opt->bCycl)
 +                {                                     /* in cyclic wham:             */
 +                    if (distance > ztot_half)           /*    |distance| < ztot_half   */
 +                        distance-=ztot;
 +                    else if (distance < -ztot_half)
 +                        distance+=ztot;
 +                }
 +                /* Note: there are two contributions to bin k in the wham equations:
 +                   i)  N[j]*exp(- U/(8.314e-3*opt->Temperature) + window[i].z[j])
 +                   ii) exp(- U/(8.314e-3*opt->Temperature))
 +                   where U is the umbrella potential
 +                   If any of these number is larger wham_contrib_lim, I set contrib=TRUE
 +                */
 +                
 +                if (!opt->bTab)
 +                    U=0.5*window[i].k[j]*sqr(distance);       /* harmonic potential assumed. */
 +                else
 +                    U=tabulated_pot(distance,opt);            /* Use tabulated potential     */
 +                
 +                contrib1=profile[k]*exp(- U/(8.314e-3*opt->Temperature));
 +                contrib2=window[i].N[j]*exp(- U/(8.314e-3*opt->Temperature) + window[i].z[j]);
 +                window[i].bContrib[j][k] = (contrib1 > wham_contrib_lim || contrib2 > wham_contrib_lim);
 +                bAnyContrib = (bAnyContrib | window[i].bContrib[j][k]);
 +                if (window[i].bContrib[j][k])
 +                    nContrib++;
 +                nTot++;
 +            }
 +            /* If this histo is far outside min and max all bContrib may be FALSE,
 +               causing a floating point exception later on. To avoid that, switch 
 +               them all to true.*/
 +            if (!bAnyContrib)
 +                for(k=0;k<opt->bins;++k)
 +                    window[i].bContrib[j][k]=TRUE;
 +        }
 +    }
 +    if (bFirst)
 +        printf("Initialized rapid wham stuff (contrib tolerance %g)\n"
 +               "Evaluating only %d of %d expressions.\n\n",wham_contrib_lim,nContrib, nTot);
 +    
 +    if (opt->verbose)
 +        printf("Updated rapid wham stuff. (evaluating only %d of %d contributions)\n",
 +               nContrib,nTot);
 +    bFirst=0;    
 +}
 +
 +//! Compute the PMF (one of the two main WHAM routines)
 +void calc_profile(double *profile,t_UmbrellaWindow * window, int nWindows, 
 +                  t_UmbrellaOptions *opt, gmx_bool bExact)
 +{
 +    int i,k,j;
 +    double num,ztot_half,ztot,distance,min=opt->min,dz=opt->dz;
 +    double denom,U=0,temp=0,invg;
 +    
 +    ztot=opt->max-opt->min;
 +    ztot_half=ztot/2;   
 +    
 +    for(i=0;i<opt->bins;++i) 
 +    {
 +        num=denom=0.;
 +        for(j=0;j<nWindows;++j) 
 +        {
 +            for(k=0;k<window[j].nPull;++k) 
 +            {
 +                invg = 1.0/window[j].g[k] * window[j].bsWeight[k];
 +                temp = (1.0*i+0.5)*dz+min;
 +                num += invg*window[j].Histo[k][i];
 +                
 +                if (! (bExact || window[j].bContrib[k][i]))
 +                    continue;
 +                distance = temp - window[j].pos[k];   /* distance to umbrella center */
 +                if (opt->bCycl)
 +                {                                     /* in cyclic wham:             */
 +                    if (distance > ztot_half)           /*    |distance| < ztot_half   */
 +                        distance-=ztot;
 +                    else if (distance < -ztot_half)
 +                        distance+=ztot;
 +                }
 +                
 +                if (!opt->bTab)
 +                    U=0.5*window[j].k[k]*sqr(distance);       /* harmonic potential assumed. */
 +                else
 +                    U=tabulated_pot(distance,opt);            /* Use tabulated potential     */
 +                denom+=invg*window[j].N[k]*exp(- U/(8.314e-3*opt->Temperature) + window[j].z[k]);
 +            }
 +        }
 +        profile[i]=num/denom;
 +    }
 +}
 +
 +//! Compute the free energy offsets z (one of the two main WHAM routines)
 +double calc_z(double * profile,t_UmbrellaWindow * window, int nWindows, 
 +              t_UmbrellaOptions *opt, gmx_bool bExact)
 +{
 +    int i,j,k;
 +    double U=0,min=opt->min,dz=opt->dz,temp,ztot_half,distance,ztot;
 +    double MAX=-1e20, total=0;
 +    
 +    ztot=opt->max-opt->min;
 +    ztot_half=ztot/2;
 +      
 +    for(i=0;i<nWindows;++i) 
 +    {
 +        for(j=0;j<window[i].nPull;++j) 
 +        {
 +            total=0;
 +            for(k=0;k<window[i].nBin;++k) 
 +            {
 +                if (! (bExact || window[i].bContrib[j][k]))
 +                    continue;
 +                temp=(1.0*k+0.5)*dz+min;
 +                distance = temp - window[i].pos[j];   /* distance to umbrella center */
 +                if (opt->bCycl)
 +                {                                     /* in cyclic wham:             */
 +                    if (distance > ztot_half)           /*    |distance| < ztot_half   */
 +                        distance-=ztot;
 +                    else if (distance < -ztot_half)
 +                        distance+=ztot;
 +                }
 +                
 +                if (!opt->bTab)
 +                    U=0.5*window[i].k[j]*sqr(distance);       /* harmonic potential assumed. */
 +                else
 +                    U=tabulated_pot(distance,opt);            /* Use tabulated potential     */
 +                
 +                total+=profile[k]*exp(-U/(8.314e-3*opt->Temperature));
 +            }
 +            /* Avoid floating point exception if window is far outside min and max */
 +            if (total != 0.0)
 +                total = -log(total);
 +            else
 +                total = 1000.0;
 +            temp = fabs(total - window[i].z[j]);
 +            if(temp > MAX){
 +                MAX=temp;
 +            }
 +            window[i].z[j] = total;
 +        }
 +    }
 +    return MAX;
 +}
 +
 +//! Make PMF symmetric around 0 (useful e.g. for membranes)
 +void symmetrizeProfile(double* profile,t_UmbrellaOptions *opt)
 +{
 +    int i,j,bins=opt->bins;
 +    double *prof2,min=opt->min,max=opt->max,dz=opt->dz,zsym,deltaz,profsym;
 +    double z,z1;
 +    
 +    if (min>0. || max<0.)
 +        gmx_fatal(FARGS,"Cannot symmetrize profile around z=0 with min=%f and max=%f\n",
 +                  opt->min,opt->max);
 +    
 +    snew(prof2,bins);
 +    
 +    for (i=0;i<bins;i++)
 +    {
 +        z=min+(i+0.5)*dz;
 +        zsym=-z;
 +        /* bin left of zsym */
 +        j=static_cast<int> (floor((zsym-min)/dz-0.5));
 +        if (j>=0 && (j+1)<bins)
 +        {
 +            /* interpolate profile linearly between bins j and j+1 */
 +            z1=min+(j+0.5)*dz;
 +            deltaz=zsym-z1;
 +            profsym=profile[j] + (profile[j+1]-profile[j])/dz*deltaz;
 +            /* average between left and right */
 +            prof2[i]=0.5*(profsym+profile[i]);
 +        }
 +        else
 +        {
 +            prof2[i]=profile[i];
 +        }
 +    }
 +    
 +    memcpy(profile,prof2,bins*sizeof(double));
 +    sfree(prof2);
 +}
 +
 +//! Set energy unit (kJ/mol,kT,kCal/mol) and set it to zero at opt->zProf0
 +void prof_normalization_and_unit(double * profile, t_UmbrellaOptions *opt)
 +{
 +    int i,bins,imin;
 +    double unit_factor=1., R_MolarGasConst, diff;
 +    
 +    R_MolarGasConst=8.314472e-3; /* in kJ/(mol*K) */
 +    bins=opt->bins;
 +    
 +    /* Not log? Nothing to do! */
 +    if (!opt->bLog)
 +        return;
 +    
 +    /* Get profile in units of kT, kJ/mol, or kCal/mol */
 +    if (opt->unit == en_kT)
 +        unit_factor=1.0;
 +    else if (opt->unit == en_kJ)
 +        unit_factor=R_MolarGasConst*opt->Temperature;
 +    else if (opt->unit == en_kCal)
 +        unit_factor=R_MolarGasConst*opt->Temperature/4.1868;
 +    else
 +        gmx_fatal(FARGS,"Sorry, I don't know this energy unit.");
 +    
 +    for (i=0;i<bins;i++)
 +        if (profile[i]>0.0)
 +            profile[i]=-log(profile[i])*unit_factor;
 +    
 +    /* shift to zero at z=opt->zProf0 */
 +    if (!opt->bProf0Set)
 +    {
 +        diff=profile[0];
 +    }
 +    else
 +    {
 +        /* Get bin with shortest distance to opt->zProf0 
 +           (-0.5 from bin position and +0.5 from rounding cancel) */
 +        imin=static_cast<int>((opt->zProf0-opt->min)/opt->dz);
 +        if (imin<0)
 +            imin=0;
 +        else if (imin>=bins)
 +            imin=bins-1;
 +        diff=profile[imin];
 +    }
 +  
 +    /* Shift to zero */
 +    for (i=0;i<bins;i++)
 +        profile[i]-=diff;
 +}
 +
 +//! Make an array of random integers (used for bootstrapping)
 +void getRandomIntArray(int nPull,int blockLength,int* randomArray,gmx_rng_t rng)
 +{
 +    int ipull,blockBase,nr,ipullRandom;
 +    
 +    if (blockLength==0)
 +        blockLength=nPull;
 +    
 +    for (ipull=0; ipull<nPull; ipull++)
 +    {
 +        blockBase=(ipull/blockLength)*blockLength;
 +        do
 +        {      /* make sure nothing bad happens in the last block */
 +            nr=static_cast<int>(gmx_rng_uniform_real(rng)*blockLength);
 +            ipullRandom = blockBase + nr;
 +        } while (ipullRandom >= nPull);
 +        if (ipullRandom<0 || ipullRandom>=nPull)
 +            gmx_fatal(FARGS,"Ups, random iWin = %d, nPull = %d, nr = %d, "
 +                      "blockLength = %d, blockBase = %d\n",
 +                      ipullRandom,nPull,nr,blockLength,blockBase);
 +        randomArray[ipull]=ipullRandom;
 +    }
 +    /*for (ipull=0; ipull<nPull; ipull++)
 +      printf("%d ",randomArray[ipull]); printf("\n"); */
 +}
 +
 +/*! \brief Set pull group information of a synthetic histogram 
 + *
 + * This is used when bootstapping new trajectories and thereby create new histogtrams, 
 + * but it is not required if we bootstrap complete histograms.
 + */
 +void copy_pullgrp_to_synthwindow(t_UmbrellaWindow *synthWindow,
 +                                 t_UmbrellaWindow *thisWindow,int pullid)
 +{
 +    synthWindow->N       [0]=thisWindow->N        [pullid];
 +    synthWindow->Histo   [0]=thisWindow->Histo    [pullid];
 +    synthWindow->pos     [0]=thisWindow->pos      [pullid];
 +    synthWindow->z       [0]=thisWindow->z        [pullid];
 +    synthWindow->k       [0]=thisWindow->k        [pullid];
 +    synthWindow->bContrib[0]=thisWindow->bContrib [pullid];
 +    synthWindow->g       [0]=thisWindow->g        [pullid];
 +    synthWindow->bsWeight[0]=thisWindow->bsWeight [pullid];
 +}
 +
 +/*! \brief Calculate cumulative distribution function of of all histograms.
 + *
 + * This allow to create random number sequences
 + * which are distributed according to the histograms. Required to generate
 + * the "synthetic" histograms for the Bootstrap method 
 + */
 +void calc_cumulatives(t_UmbrellaWindow *window,int nWindows,
 +                      t_UmbrellaOptions *opt,const char *fnhist)
 +{
 +    int i,j,k,nbin;
 +    double last;
 +    char *fn=0,*buf=0;
 +    FILE *fp=0;
 +    
 +    if (opt->bs_verbose)
 +    {
 +        snew(fn,strlen(fnhist)+10);
 +        snew(buf,strlen(fnhist)+10);
 +        sprintf(fn,"%s_cumul.xvg",strncpy(buf,fnhist,strlen(fnhist)-4));
 +        fp=xvgropen(fn,"CDFs of umbrella windows","z","CDF",opt->oenv);
 +    }
 +    
 +    nbin=opt->bins;
 +    for (i=0; i<nWindows; i++)
 +    {
 +        snew(window[i].cum,window[i].nPull);
 +        for (j=0; j<window[i].nPull; j++)
 +        {
 +            snew(window[i].cum[j],nbin+1);
 +            window[i].cum[j][0]=0.;
 +            for (k=1; k<=nbin; k++)
 +                window[i].cum[j][k] = window[i].cum[j][k-1]+window[i].Histo[j][k-1];
 +            
 +            /* normalize CDFs. Ensure cum[nbin]==1 */
 +            last = window[i].cum[j][nbin];
 +            for (k=0; k<=nbin; k++)
 +                window[i].cum[j][k] /= last;
 +        }
 +    }
 +    
 +    printf("Cumulative distriubtion functions of all histograms created.\n");
 +    if (opt->bs_verbose)
 +    {
 +        for (k=0; k<=nbin; k++)
 +        {
 +            fprintf(fp,"%g\t",opt->min+k*opt->dz);
 +            for (i=0; i<nWindows; i++)
 +                for (j=0; j<window[i].nPull; j++)
 +                    fprintf(fp,"%g\t",window[i].cum[j][k]);
 +            fprintf(fp,"\n");
 +        }
 +        printf("Wrote cumulative distribution functions to %s\n",fn);
 +        ffclose(fp);
 +        sfree(fn);
 +        sfree(buf);
 +    }
 +}
 +
 +
 +/*! \brief Return j such that xx[j] <= x < xx[j+1] 
 + *
 + *  This is used to generate a random sequence distributed according to a histogram
 + */
 +void searchCumulative(double xx[], int n, double x, int *j)
 +{
 +    int ju,jm,jl;
 +    
 +    jl=-1;
 +    ju=n;
 +    while (ju-jl > 1) 
 +    {
 +        jm=(ju+jl) >> 1;
 +        if (x >= xx[jm])
 +            jl=jm;
 +        else
 +            ju=jm;
 +    }
 +    if (x==xx[0])
 +        *j=0;
 +    else if (x==xx[n-1])
 +        *j=n-2;
 +    else
 +        *j=jl;
 +}
 +
 +//! Bootstrap new trajectories and thereby generate new (bootstrapped) histograms 
 +void create_synthetic_histo(t_UmbrellaWindow *synthWindow, t_UmbrellaWindow *thisWindow,
 +                            int pullid,t_UmbrellaOptions *opt)
 +{
 +    int N,i,nbins,r_index,ibin;
 +    double r,tausteps=0.0,a,ap,dt,x,invsqrt2,g,y,sig=0.,z,mu=0.;
 +    char errstr[1024];
 +    
 +    N=thisWindow->N[pullid];
 +    dt=thisWindow->dt;
 +    nbins=thisWindow->nBin;
 +    
 +    /* tau = autocorrelation time */
 +    if (opt->tauBootStrap>0.0)
 +        tausteps=opt->tauBootStrap/dt;
 +    else if (opt->bTauIntGiven || opt->bCalcTauInt)
 +    {
 +        /* calc tausteps from g=1+2tausteps */
 +        g=thisWindow->g[pullid];
 +        tausteps=(g-1)/2;
 +    }
 +    else
 +    {
 +        sprintf(errstr,
 +                "When generating hypothetical trajctories from given umbrella histograms,\n"
 +                "autocorrelation times (ACTs) are required. Otherwise the statistical error\n"
 +                "cannot be predicted. You have 3 options:\n"
 +                "1) Make g_wham estimate the ACTs (options -ac and -acsig).\n"
 +                "2) Calculate the ACTs by yourself (e.g. with g_analyze) and provide them\n");
 +        strcat(errstr,
 +               "   with option -iiact for all umbrella windows.\n"
 +               "3) If all ACTs are identical and know, you can define them with -bs-tau.\n"
 +               "   Use option (3) only if you are sure what you're doing, you may severely\n"
 +               "   underestimate the error if a too small ACT is given.\n");
 +        gmx_fatal(FARGS,errstr);
 +    }
 +
 +    synthWindow->N       [0]=N;
 +    synthWindow->pos     [0]=thisWindow->pos[pullid];
 +    synthWindow->z       [0]=thisWindow->z[pullid];
 +    synthWindow->k       [0]=thisWindow->k[pullid];
 +    synthWindow->bContrib[0]=thisWindow->bContrib[pullid];
 +    synthWindow->g       [0]=thisWindow->g       [pullid];
 +    synthWindow->bsWeight[0]=thisWindow->bsWeight[pullid];
 +    
 +    for (i=0;i<nbins;i++)
 +        synthWindow->Histo[0][i]=0.;
 +    
 +    if (opt->bsMethod==bsMethod_trajGauss)
 +    {
 +        sig = thisWindow->sigma [pullid];
 +        mu  = thisWindow->aver  [pullid];
 +    }
 +    
 +    /* Genrate autocorrelated Gaussian random variable with autocorrelation time tau 
 +       Use the following:
 +       If x and y are random numbers from N(0,1) (Gaussian with average 0 and sigma=1),
 +       then
 +       z = a*x + sqrt(1-a^2)*y
 +       is also from N(0,1), and cov(z,x) = a. Thus, by gerenating a sequence
 +       x' = a*x + sqrt(1-a^2)*y, the sequnce x(t) is from N(0,1) and has an autocorrelation 
 +       function
 +       C(t) = exp(-t/tau) with tau=-1/ln(a)
 +
 +       Then, use error function to turn the Gaussian random variable into a uniformly
 +       distributed one in [0,1]. Eventually, use cumulative distribution function of
 +       histogram to get random variables distributed according to histogram.
 +       Note: The ACT of the flat distribution and of the generated histogram is not
 +       100% exactly tau, but near tau (my test was 3.8 instead of 4).
 +    */
 +    a=exp(-1.0/tausteps);
 +    ap=sqrt(1-a*a);
 +    invsqrt2=1./sqrt(2.0);
 +    
 +    /* init random sequence */
 +    x=gmx_rng_gaussian_table(opt->rng); 
 +    
 +    if (opt->bsMethod==bsMethod_traj)
 +    {
 +        /* bootstrap points from the umbrella histograms */
 +        for (i=0;i<N;i++)
 +        {
 +            y=gmx_rng_gaussian_table(opt->rng);
 +            x=a*x+ap*y;
 +            /* get flat distribution in [0,1] using cumulative distribution function of Gauusian
 +               Note: CDF(Gaussian) = 0.5*{1+erf[x/sqrt(2)]}
 +            */           
 +            r=0.5*(1+gmx_erf(x*invsqrt2));
 +            searchCumulative(thisWindow->cum[pullid],nbins+1 ,r,&r_index);
 +            synthWindow->Histo[0][r_index]+=1.;    
 +        }
 +    }
 +    else if (opt->bsMethod==bsMethod_trajGauss)
 +    {
 +        /* bootstrap points from a Gaussian with the same average and sigma
 +           as the respective umbrella histogram. The idea was, that -given
 +           limited sampling- the bootstrapped histograms are otherwise biased 
 +           from the limited sampling of the US histos. However, bootstrapping from
 +           the Gaussian seems to yield a similar estimate. */
 +        i=0;
 +        while (i<N)
 +        {
 +            y=gmx_rng_gaussian_table(opt->rng);
 +            x=a*x+ap*y;
 +            z = x*sig+mu;
 +            ibin=static_cast<int> (floor((z-opt->min)/opt->dz));
 +            if (opt->bCycl)
 +            {
 +                if (ibin<0)
-                     while ( (ibin-=nbins) >= nbins);
++                    while ( (ibin+=nbins) < 0) ;
 +                else if (ibin>=nbins)
-                             while ( (ibin+=bins) < 0);
++                    while ( (ibin-=nbins) >= nbins) ;
 +            }
 +            
 +            if (ibin>=0 && ibin<nbins)
 +            {
 +                synthWindow->Histo[0][ibin]+=1.;
 +                i++;
 +            }
 +        }
 +    }
 +    else
 +    {
 +        gmx_fatal(FARGS,"Unknown bsMethod (id %d). That should not happen.\n",opt->bsMethod);
 +    }
 +}
 +
 +/*! \brief Write all histograms to a file
 + *
 + * If bs_index>=0, a number is added to the output file name to allow the ouput of all
 + * sets of bootstrapped histograms.
 + */
 +void print_histograms(const char *fnhist, t_UmbrellaWindow * window, int nWindows,
 +                      int bs_index,t_UmbrellaOptions *opt)
 +{
 +    char *fn=0,*buf=0,title[256];
 +    FILE *fp;
 +    int bins,l,i,j;
 +    
 +    if (bs_index>=0)
 +    {
 +        snew(fn,strlen(fnhist)+10);
 +        snew(buf,strlen(fnhist)+1);
 +        sprintf(fn,"%s_bs%d.xvg",strncpy(buf,fnhist,strlen(fnhist)-4),bs_index);
 +        sprintf(title,"Umbrella histograms. Bootstrap #%d",bs_index);
 +    }
 +    else
 +    {
 +        fn=strdup(fnhist);
 +        strcpy(title,"Umbrella histograms");
 +    }
 +
 +    fp=xvgropen(fn,title,"z","count",opt->oenv);
 +    bins=opt->bins;
 +    
 +    /* Write histograms */
 +    for(l=0;l<bins;++l) 
 +    {
 +        fprintf(fp,"%e\t",(double)(l+0.5)*opt->dz+opt->min);
 +        for(i=0;i<nWindows;++i) 
 +        {
 +            for(j=0;j<window[i].nPull;++j) 
 +            {
 +                fprintf(fp,"%e\t",window[i].Histo[j][l]);
 +            }
 +        }
 +        fprintf(fp,"\n");
 +    }
 +    
 +    ffclose(fp);
 +    printf("Wrote %s\n",fn);
 +    if (bs_index>=0)
 +    {
 +        sfree(buf);
 +    }
 +    sfree(fn);    
 +}
 +
 +//! Used for qsort to sort random numbers
 +int func_wham_is_larger(const void *a, const void *b)
 +{
 +    double *aa,*bb;
 +    aa=(double*)a;
 +    bb=(double*)b;
 +    if (*aa < *bb)
 +        return -1;
 +    else if (*aa > *bb)
 +        return 1;
 +    else
 +        return 0;
 +}
 +
 +//! Make random weights for histograms for the Bayesian bootstrap of complete histograms)
 +void setRandomBsWeights(t_UmbrellaWindow *synthwin,int nAllPull, t_UmbrellaOptions *opt)
 +{
 +    int i;
 +    double *r;
 +    
 +    snew(r,nAllPull);
 +    
 +    /* generate ordered random numbers between 0 and nAllPull  */
 +    for (i=0; i<nAllPull-1; i++)
 +    {
 +        r[i] = gmx_rng_uniform_real(opt->rng) * nAllPull;
 +    }
 +    qsort((void *)r,nAllPull-1, sizeof(double), &func_wham_is_larger);
 +    r[nAllPull-1]=1.0*nAllPull;
 +    
 +    synthwin[0].bsWeight[0]=r[0];
 +    for (i=1; i<nAllPull; i++)
 +    {
 +        synthwin[i].bsWeight[0]=r[i]-r[i-1];
 +    }
 +    
 +    /* avoid to have zero weight by adding a tiny value */
 +    for (i=0; i<nAllPull; i++)
 +        if (synthwin[i].bsWeight[0] < 1e-5)   
 +            synthwin[i].bsWeight[0] = 1e-5;
 +
 +    sfree(r);
 +}
 +
 +//! The main bootstrapping routine
 +void do_bootstrapping(const char *fnres, const char* fnprof, const char *fnhist,
 +                      char* ylabel, double *profile,
 +                      t_UmbrellaWindow * window, int nWindows, t_UmbrellaOptions *opt)
 +{
 +    t_UmbrellaWindow * synthWindow;
 +    double *bsProfile,*bsProfiles_av, *bsProfiles_av2,maxchange=1e20,tmp,stddev;
 +    int i,j,*randomArray=0,winid,pullid,ib;
 +    int iAllPull,nAllPull,*allPull_winId,*allPull_pullId;
 +    FILE *fp;
 +    gmx_bool bExact=FALSE;
 +    
 +    /* init random generator */
 +    if (opt->bsSeed==-1)
 +        opt->rng=gmx_rng_init(gmx_rng_make_seed());
 +    else
 +        opt->rng=gmx_rng_init(opt->bsSeed);
 +    
 +    snew(bsProfile,     opt->bins);
 +    snew(bsProfiles_av, opt->bins);
 +    snew(bsProfiles_av2,opt->bins);
 +    
 +    /* Create array of all pull groups. Note that different windows
 +       may have different nr of pull groups
 +       First: Get total nr of pull groups */
 +    nAllPull=0;
 +    for (i=0;i<nWindows;i++)
 +        nAllPull+=window[i].nPull;
 +    snew(allPull_winId,nAllPull);
 +    snew(allPull_pullId,nAllPull);
 +    iAllPull=0;
 +    /* Setup one array of all pull groups */
 +    for (i=0;i<nWindows;i++)
 +    {
 +        for (j=0;j<window[i].nPull;j++)
 +        {
 +            allPull_winId[iAllPull]=i;
 +            allPull_pullId[iAllPull]=j;
 +            iAllPull++;
 +        }
 +    }
 +    
 +    /* setup stuff for synthetic windows */
 +    snew(synthWindow,nAllPull);
 +    for (i=0;i<nAllPull;i++)
 +    {
 +        synthWindow[i].nPull=1;
 +        synthWindow[i].nBin=opt->bins;
 +        snew(synthWindow[i].Histo,1);
 +        if (opt->bsMethod == bsMethod_traj || opt->bsMethod == bsMethod_trajGauss)
 +            snew(synthWindow[i].Histo[0],opt->bins);
 +        snew(synthWindow[i].N,1);
 +        snew(synthWindow[i].pos,1);
 +        snew(synthWindow[i].z,1);
 +        snew(synthWindow[i].k,1);
 +        snew(synthWindow[i].bContrib,1);
 +        snew(synthWindow[i].g,1);
 +        snew(synthWindow[i].bsWeight,1);
 +    }
 +    
 +    switch(opt->bsMethod)
 +    {
 +    case bsMethod_hist:
 +        snew(randomArray,nAllPull);
 +        printf("\n\nWhen computing statistical errors by bootstrapping entire histograms:\n");
 +        please_cite(stdout,"Hub2006");
 +        break;
 +    case bsMethod_BayesianHist :
 +        /* just copy all histogams into synthWindow array */
 +        for (i=0;i<nAllPull;i++)
 +        {
 +            winid =allPull_winId [i];
 +            pullid=allPull_pullId[i];
 +            copy_pullgrp_to_synthwindow(synthWindow+i,window+winid,pullid);
 +        }
 +        break;
 +    case bsMethod_traj:
 +    case bsMethod_trajGauss:  
 +        calc_cumulatives(window,nWindows,opt,fnhist);
 +        break;
 +    default:
 +        gmx_fatal(FARGS,"Unknown bootstrap method. That should not have happened.\n");
 +    }
 +  
 +    /* do bootstrapping */
 +    fp=xvgropen(fnprof,"Boot strap profiles","z",ylabel,opt->oenv);
 +    for (ib=0;ib<opt->nBootStrap;ib++)
 +    {
 +        printf("  *******************************************\n"
 +               "  ******** Start bootstrap nr %d ************\n"
 +               "  *******************************************\n",ib+1);
 +        
 +        switch(opt->bsMethod)
 +        {
 +        case bsMethod_hist:  
 +            /* bootstrap complete histograms from given histograms */
 +            getRandomIntArray(nAllPull,opt->histBootStrapBlockLength,randomArray,opt->rng);
 +            for (i=0;i<nAllPull;i++){
 +                winid =allPull_winId [randomArray[i]];
 +                pullid=allPull_pullId[randomArray[i]];
 +                copy_pullgrp_to_synthwindow(synthWindow+i,window+winid,pullid);
 +            }
 +            break;
 +        case bsMethod_BayesianHist:  
 +            /* keep histos, but assign random weights ("Bayesian bootstrap") */
 +            setRandomBsWeights(synthWindow,nAllPull,opt);
 +            break;
 +        case bsMethod_traj:
 +        case bsMethod_trajGauss:      
 +            /* create new histos from given histos, that is generate new hypothetical
 +               trajectories */
 +            for (i=0;i<nAllPull;i++)
 +            {
 +                winid=allPull_winId[i];
 +                pullid=allPull_pullId[i];       
 +                create_synthetic_histo(synthWindow+i,window+winid,pullid,opt);
 +            }
 +            break;
 +        }
 +        
 +        /* write histos in case of verbose output */
 +        if (opt->bs_verbose)
 +            print_histograms(fnhist,synthWindow,nAllPull,ib,opt);
 +        
 +        /* do wham */
 +        i=0;
 +        bExact=FALSE;
 +        maxchange=1e20;
 +        memcpy(bsProfile,profile,opt->bins*sizeof(double)); /* use profile as guess */
 +        do 
 +        {
 +            if ( (i%opt->stepUpdateContrib) == 0)
 +                setup_acc_wham(bsProfile,synthWindow,nAllPull,opt);
 +            if (maxchange<opt->Tolerance)
 +                bExact=TRUE;
 +            if (((i%opt->stepchange) == 0 || i==1) && !i==0)
 +                printf("\t%4d) Maximum change %e\n",i,maxchange);
 +            calc_profile(bsProfile,synthWindow,nAllPull,opt,bExact);
 +            i++;
 +        } while( (maxchange=calc_z(bsProfile, synthWindow, nAllPull, opt,bExact)) > opt->Tolerance || !bExact);
 +        printf("\tConverged in %d iterations. Final maximum change %g\n",i,maxchange);
 +        
 +        if (opt->bLog)
 +            prof_normalization_and_unit(bsProfile,opt);
 +        
 +        /* symmetrize profile around z=0 */
 +        if (opt->bSym)
 +            symmetrizeProfile(bsProfile,opt);
 +        
 +        /* save stuff to get average and stddev */
 +        for (i=0;i<opt->bins;i++)
 +        {
 +            tmp=bsProfile[i];
 +            bsProfiles_av[i]+=tmp;
 +            bsProfiles_av2[i]+=tmp*tmp;
 +            fprintf(fp,"%e\t%e\n",(i+0.5)*opt->dz+opt->min,tmp);
 +        }
 +        fprintf(fp,"&\n");
 +    }
 +    ffclose(fp);
 +  
 +    /* write average and stddev */
 +    fp=xvgropen(fnres,"Average and stddev from bootstrapping","z",ylabel,opt->oenv);
 +    fprintf(fp,"@TYPE xydy\n");
 +    for (i=0;i<opt->bins;i++)
 +    {
 +        bsProfiles_av [i]/=opt->nBootStrap;
 +        bsProfiles_av2[i]/=opt->nBootStrap;
 +        tmp=bsProfiles_av2[i]-sqr(bsProfiles_av[i]);
 +        stddev=(tmp>=0.) ? sqrt(tmp) : 0.; /* Catch rouding errors */
 +        fprintf(fp,"%e\t%e\t%e\n",(i+0.5)*opt->dz+opt->min,bsProfiles_av [i],stddev);
 +    }
 +    ffclose(fp);
 +    printf("Wrote boot strap result to %s\n",fnres);
 +}
 +
 +//! Return type of input file based on file extension (xvg, pdo, or tpr)
 +int whaminFileType(char *fn)
 +{
 +    int len;
 +    len=strlen(fn);
 +    if (strcmp(fn+len-3,"tpr")==0)
 +        return whamin_tpr;
 +    else if (strcmp(fn+len-3,"xvg")==0 || strcmp(fn+len-6,"xvg.gz")==0)
 +        return whamin_pullxf;
 +    else if (strcmp(fn+len-3,"pdo")==0 || strcmp(fn+len-6,"pdo.gz")==0)
 +        return whamin_pdo;
 +    else
 +        gmx_fatal(FARGS,"Unknown file type of %s. Should be tpr, xvg, or pdo.\n",fn);
 +    return whamin_unknown;
 +}
 +
 +//! Read the files names in pdo-files.dat, pullf/x-files.dat, tpr-files.dat
 +void read_wham_in(const char *fn,char ***filenamesRet, int *nfilesRet,
 +                  t_UmbrellaOptions *opt)
 +{
 +    char **filename=0,tmp[WHAM_MAXFILELEN+2];
 +    int nread,sizenow,i,block=1;
 +    FILE *fp;
 +    
 +    fp=ffopen(fn,"r");
 +    nread=0;
 +    sizenow=0;
 +    while (fgets(tmp,sizeof(tmp),fp) != NULL)
 +    {
 +        if (strlen(tmp)>=WHAM_MAXFILELEN)
 +            gmx_fatal(FARGS,"Filename too long in %s. Only %d characters allowed.\n",fn,WHAM_MAXFILELEN);
 +        if (nread>=sizenow)
 +        {
 +            sizenow+=block;
 +            srenew(filename,sizenow);
 +            for (i=sizenow-block;i<sizenow;i++)
 +                snew(filename[i],WHAM_MAXFILELEN);
 +        }
 +        /* remove newline if there is one */
 +        if (tmp[strlen(tmp)-1] == '\n')
 +        {
 +            tmp[strlen(tmp)-1]='\0';
 +        }
 +        strcpy(filename[nread],tmp);
 +        if (opt->verbose)
 +            printf("Found file %s in %s\n",filename[nread],fn);
 +        nread++;
 +    }
 +    *filenamesRet=filename;
 +    *nfilesRet=nread;
 +}
 +
 +//! Open a file or a pipe to a gzipped file
 +FILE *open_pdo_pipe(const char *fn, t_UmbrellaOptions *opt,gmx_bool *bPipeOpen)
 +{
 +    char Buffer[1024],gunzip[1024],*Path=0;
 +    FILE *pipe=0;
 +    static gmx_bool bFirst=1;  
 +    
 +    /* gzipped pdo file? */
 +    if ((strcmp(fn+strlen(fn)-3,".gz")==0))
 +    {
 +        /* search gunzip executable */
 +        if(!(Path=getenv("GMX_PATH_GZIP")))
 +        {
 +            if (gmx_fexist("/bin/gunzip"))
 +                sprintf(gunzip,"%s","/bin/gunzip");
 +            else if (gmx_fexist("/usr/bin/gunzip"))
 +                sprintf(gunzip,"%s","/usr/bin/gunzip");
 +            else
 +                gmx_fatal(FARGS,"Cannot find executable gunzip in /bin or /usr/bin.\n"
 +                          "You may want to define the path to gunzip "
 +                          "with the environment variable GMX_PATH_GZIP.",gunzip);
 +        }
 +        else
 +        {
 +            sprintf(gunzip,"%s/gunzip",Path);
 +            if (!gmx_fexist(gunzip))
 +                gmx_fatal(FARGS,"Cannot find executable %s. Please define the path to gunzip"
 +                          " in the environmental varialbe GMX_PATH_GZIP.",gunzip);
 +        }    
 +        if (bFirst)
 +        {
 +            printf("Using gunzig executable %s\n",gunzip);
 +            bFirst=0;
 +        }
 +        if (!gmx_fexist(fn))
 +        {
 +            gmx_fatal(FARGS,"File %s does not exist.\n",fn);
 +        }
 +        sprintf(Buffer,"%s -c < %s",gunzip,fn);    
 +        if (opt->verbose)
 +            printf("Executing command '%s'\n",Buffer);
 +#ifdef HAVE_PIPES
 +        if((pipe=popen(Buffer,"r"))==NULL)
 +        {
 +            gmx_fatal(FARGS,"Unable to open pipe to `%s'\n",Buffer);
 +        }
 +#else
 +        gmx_fatal(FARGS,"Cannot open a compressed file on platform without pipe support");
 +#endif
 +        *bPipeOpen=TRUE;
 +    }
 +    else{
 +        pipe=ffopen(fn,"r");
 +        *bPipeOpen=FALSE;
 +    }
 +    
 +    return pipe;
 +}
 +
 +//! Close file or pipe
 +void pdo_close_file(FILE *fp)
 +{
 +#ifdef HAVE_PIPES
 +      pclose(fp);
 +#else
 +      ffclose(fp);
 +#endif
 +}
 +
 +//! Reading all pdo files
 +void read_pdo_files(char **fn, int nfiles, t_UmbrellaHeader* header,
 +                    t_UmbrellaWindow *window, t_UmbrellaOptions *opt)
 +{
 +    FILE  *file;
 +    real mintmp,maxtmp,done=0.;
 +    int i;
 +    gmx_bool bPipeOpen;
 +    /* char Buffer0[1000]; */
 +    
 +    if(nfiles<1)
 +        gmx_fatal(FARGS,"No files found. Hick.");
 +    
 +    /* if min and max are not given, get min and max from the input files */
 +    if (opt->bAuto)
 +    {
 +        printf("Automatic determination of boundaries from %d pdo files...\n",nfiles);
 +        opt->min=1e20;
 +        opt->max=-1e20;
 +        for(i=0;i<nfiles;++i) 
 +        {
 +            file=open_pdo_pipe(fn[i],opt,&bPipeOpen);
 +            /*fgets(Buffer0,999,file);
 +              fprintf(stderr,"First line '%s'\n",Buffer0); */
 +            done=100.0*(i+1)/nfiles;
 +            printf("\rOpening %s ... [%2.0f%%]",fn[i],done); fflush(stdout);
 +            if (opt->verbose)
 +                printf("\n");
 +            read_pdo_header(file,header,opt);
 +            /* here only determine min and max of this window */
 +            read_pdo_data(file,header,i,NULL,opt,TRUE,&mintmp,&maxtmp);
 +            if (maxtmp>opt->max)
 +                opt->max=maxtmp;
 +            if (mintmp<opt->min)
 +                opt->min=mintmp;
 +            if (bPipeOpen)
 +                pdo_close_file(file);
 +            else
 +                ffclose(file);
 +        }
 +        printf("\n");
 +        printf("\nDetermined boundaries to %f and %f\n\n",opt->min,opt->max);
 +        if (opt->bBoundsOnly)
 +        {
 +            printf("Found option -boundsonly, now exiting.\n");
 +            exit (0);
 +        }
 +    }
 +    /* store stepsize in profile */
 +    opt->dz=(opt->max-opt->min)/opt->bins;
 +    
 +    /* Having min and max, we read in all files */
 +    /* Loop over all files */
 +    for(i=0;i<nfiles;++i) 
 +    {
 +        done=100.0*(i+1)/nfiles;
 +        printf("\rOpening %s ... [%2.0f%%]",fn[i],done); fflush(stdout);
 +        if (opt->verbose)
 +            printf("\n");
 +        file=open_pdo_pipe(fn[i],opt,&bPipeOpen);
 +        read_pdo_header(file,header,opt);
 +        /* load data into window */
 +        read_pdo_data(file,header,i,window,opt,FALSE,NULL,NULL);
 +        if ((window+i)->Ntot[0] == 0)
 +            fprintf(stderr,"\nWARNING, no data points read from file %s (check -b option)\n", fn[i]);
 +        if (bPipeOpen)
 +            pdo_close_file(file);
 +        else
 +            ffclose(file);
 +    }
 +    printf("\n");
 +    for(i=0;i<nfiles;++i)
 +        sfree(fn[i]);
 +    sfree(fn);
 +}
 +
 +//! translate 0/1 to N/Y to write pull dimensions
 +#define int2YN(a) (((a)==0)?("N"):("Y"))
 +
 +//! Read pull groups from a tpr file (including position, force const, geometry, number of groups)
 +void read_tpr_header(const char *fn,t_UmbrellaHeader* header,t_UmbrellaOptions *opt)
 +{
 +    t_inputrec  ir;
 +    int i,ngrp,d;
 +    t_state     state;
 +    static int first=1;
 +    
 +    /* printf("Reading %s \n",fn); */
 +    read_tpx_state(fn,&ir,&state,NULL,NULL);
 +    
 +    if (ir.ePull != epullUMBRELLA)
 +        gmx_fatal(FARGS,"This is not a tpr of an umbrella simulation. Found pull type \"%s\" "
 +                  " (ir.ePull = %d)\n", epull_names[ir.ePull],ir.ePull);
 +    
 +    /* nr of pull groups */
 +    ngrp=ir.pull->ngrp;
 +    if (ngrp < 1)
 +        gmx_fatal(FARGS,"This is not a tpr of umbrella simulation. Found only %d pull groups\n",ngrp);
 +    
 +    header->npullgrps=ir.pull->ngrp;
 +    header->pull_geometry=ir.pull->eGeom;
 +    copy_ivec(ir.pull->dim,header->pull_dim);
 +    header->pull_ndim=header->pull_dim[0]+header->pull_dim[1]+header->pull_dim[2];
 +    if (header->pull_geometry==epullgPOS && header->pull_ndim>1)
 +    {
 +        gmx_fatal(FARGS,"Found pull geometry 'position' and more than 1 pull dimension (%d).\n"
 +                  "Hence, the pull potential does not correspond to a one-dimensional umbrella potential.\n"
 +                  "If you have some special umbrella setup you may want to write your own pdo files\n"
 +                  "and feed them into g_wham. Check g_wham -h !\n",header->pull_ndim);
 +    }
 +    snew(header->k,ngrp);
 +    snew(header->init_dist,ngrp);
 +    snew(header->umbInitDist,ngrp);
 +    
 +    /* only z-direction with epullgCYL? */
 +    if (header->pull_geometry == epullgCYL)
 +    {
 +        if (header->pull_dim[XX] || header->pull_dim[YY] || (!header->pull_dim[ZZ]))
 +            gmx_fatal(FARGS,"With pull geometry 'cylinder', expected pulling in Z direction only.\n"
 +                      "However, found dimensions [%s %s %s]\n",
 +                      int2YN(header->pull_dim[XX]),int2YN(header->pull_dim[YY]),
 +                      int2YN(header->pull_dim[ZZ]));
 +    }
 +
 +    for (i=0;i<ngrp;i++)
 +    {
 +        header->k[i]=ir.pull->grp[i+1].k;
 +        if (header->k[i]==0.0)
 +            gmx_fatal(FARGS,"Pull group %d has force constant of of 0.0 in %s.\n"
 +                      "That doesn't seem to be an Umbrella tpr.\n",
 +                      i,fn);
 +        copy_rvec(ir.pull->grp[i+1].init,header->init_dist[i]);
 +        
 +        /* initial distance to reference */
 +        switch(header->pull_geometry)
 +        {
 +        case epullgPOS:
 +            for (d=0;d<DIM;d++)
 +                if (header->pull_dim[d])
 +                    header->umbInitDist[i]=header->init_dist[i][d];
 +            break;
 +        case epullgCYL:
 +            /* umbrella distance stored in init_dist[i][0] for geometry cylinder (not in ...[i][ZZ]) */
 +        case epullgDIST:
 +        case epullgDIR:
 +        case epullgDIRPBC:
 +            header->umbInitDist[i]=header->init_dist[i][0];
 +            break;
 +        default:
 +            gmx_fatal(FARGS,"Pull geometry %s not supported\n",epullg_names[header->pull_geometry]);
 +        }
 +    }
 +    
 +    if (opt->verbose || first)
 +    {
 +        printf("File %s, %d groups, geometry \"%s\", dimensions [%s %s %s], (%d dimensions)\n",
 +               fn,header->npullgrps,epullg_names[header->pull_geometry],
 +               int2YN(header->pull_dim[0]),int2YN(header->pull_dim[1]),int2YN(header->pull_dim[2]),
 +               header->pull_ndim);
 +        for (i=0;i<ngrp;i++)
 +            printf("\tgrp %d) k = %-5g  position = %g\n",i,header->k[i],header->umbInitDist[i]);    
 +    }
 +    if (!opt->verbose && first)
 +        printf("\tUse option -v to see this output for all input tpr files\n");
 +    
 +    first=0;
 +}
 +
 +//! 2-norm in a ndim-dimensional space
 +double dist_ndim(double **dx,int ndim,int line)
 +{
 +    int i;
 +    double r2=0.;
 +    for (i=0;i<ndim;i++)
 +        r2+=sqr(dx[i][line]);
 +    return sqrt(r2);
 +}
 +
 +//! Read pullx.xvg or pullf.xvg
 +void read_pull_xf(const char *fn, const char *fntpr, t_UmbrellaHeader * header,
 +                  t_UmbrellaWindow * window,
 +                  t_UmbrellaOptions *opt,
 +                  gmx_bool bGetMinMax,real *mintmp,real *maxtmp,
 +                  t_groupselection *groupsel)
 +{
 +    double **y=0,pos=0.,t,force,time0=0.,dt;
 +    int ny,nt,bins,ibin,i,g,gUsed,dstep=1,nColPerGrp,nColRefOnce,nColRefEachGrp,nColExpect,ntot;
 +    real min,max,minfound=1e20,maxfound=-1e20;
 +    gmx_bool dt_ok,timeok,bHaveForce;
 +    const char *quantity;
 +    const int blocklen=4096;
 +    int *lennow=0;
 +    static gmx_bool bFirst=TRUE;
 +    
 +    /* 
 +       in force    output pullf.xvg: 
 +       No   reference, one  column  per pull group
 +       in position output pullx.xvg (not cylinder)
 +       ndim reference, ndim columns per pull group
 +       in position output pullx.xvg (in geometry cylinder): 
 +       ndim*2 columns per pull group (ndim for ref, ndim for group)
 +    */
 +
 +    nColPerGrp = opt->bPullx ? header->pull_ndim : 1;
 +    quantity   = opt->bPullx ? "position" : "force";
 +    
 +    if (opt->bPullx)
 +    {
 +        if (header->pull_geometry == epullgCYL)
 +        {
 +            /* Geometry cylinder -> reference group before each pull group */
 +            nColRefEachGrp=header->pull_ndim;
 +            nColRefOnce=0;
 +        }
 +        else
 +        {
 +            /* Geometry NOT cylinder -> reference group only once after time column */
 +            nColRefEachGrp=0;
 +            nColRefOnce=header->pull_ndim;
 +        }
 +    }
 +    else /* read forces, no reference groups */
 +    {
 +      nColRefEachGrp=0;
 +        nColRefOnce=0;
 +    }
 +    
 +    nColExpect = 1 + nColRefOnce + header->npullgrps*(nColRefEachGrp+nColPerGrp);
 +    bHaveForce = opt->bPullf;
 +    
 +    /* With geometry "distance" or "distance_periodic", only force reading is supported so far. 
 +       That avoids the somewhat tedious extraction of the right columns from the pullx files
 +       to compute the distances projection on the vector. Sorry for the laziness. */
 +    if  ( (header->pull_geometry==epullgDIR || header->pull_geometry==epullgDIRPBC) 
 +          && opt->bPullx)
 +    {
 +        gmx_fatal(FARGS,"With pull geometries \"direction\" and \"direction_periodic\", only pull force "
 +                  "reading \n(option -if) is supported at present, "
 +                  "not pull position reading (options -ix).\nMake sure mdrun writes the pull "
 +                  "forces (pullf.xvg files)\nand provide them to g_wham with option -if.", 
 +                  epullg_names[header->pull_geometry]);
 +    }
 +    
 +    nt=read_xvg(fn,&y,&ny);
 +
 +    /* Check consistency */
 +    if (nt<1)
 +    {
 +        gmx_fatal(FARGS,"Empty pull %s file %s\n",quantity,fn);
 +    }
 +    if (bFirst)
 +    {
 +        printf("Reading pull %s file with pull geometry %s and %d pull dimensions\n",
 +               bHaveForce ? "force" : "position", epullg_names[header->pull_geometry],
 +               header->pull_ndim);
 +        printf("Expecting these columns in pull file:\n"
 +               "\t%d reference columns for all pull groups together\n"
 +               "\t%d reference columns for each individual pull group\n"
 +               "\t%d data columns for each pull group\n", nColRefOnce, nColRefEachGrp, nColPerGrp);
 +        printf("With %d pull groups, expect %d columns (including the time column)\n",header->npullgrps,nColExpect);
 +        bFirst=FALSE;
 +    }
 +    if (ny != nColExpect)
 +    {
 +        gmx_fatal(FARGS,"Found %d pull groups in %s,\n but %d data columns in %s (expected %d)\n"
 +                  "\nMaybe you confused options -ix and -if ?\n",
 +                  header->npullgrps,fntpr,ny-1,fn,nColExpect-1);
 +    }
 +    
 +    if (opt->verbose)
 +        printf("Found %d times and %d %s sets %s\n",nt,(ny-1)/nColPerGrp,quantity,fn);
 +
 +    if (!bGetMinMax)
 +    {
 +        bins=opt->bins;
 +        min=opt->min;
 +        max=opt->max;
 +        if (nt>1)
 +        {
 +            window->dt=y[0][1]-y[0][0];
 +        }
 +        else if (opt->nBootStrap && opt->tauBootStrap!=0.0)
 +        {
 +            fprintf(stderr,"\n *** WARNING, Could not determine time step in %s\n",fn);
 +        }
 +        
 +        /* Need to alocate memory and set up structure */
 +
 +        if (groupsel)
 +        {
 +            /* Use only groups selected with option -is file */
 +            if (header->npullgrps != groupsel->n)
 +                gmx_fatal(FARGS,"tpr file contains %d pull groups, but expected %d from group selection file\n",
 +                          header->npullgrps,groupsel->n);
 +            window->nPull = groupsel->nUse;
 +        }
 +        else
 +        {
 +            window->nPull = header->npullgrps;
 +        }
 +
 +        window->nBin=bins;
 +        snew(window->Histo,window->nPull);
 +        snew(window->z,window->nPull);
 +        snew(window->k,window->nPull);
 +        snew(window->pos,window->nPull);
 +        snew(window->N, window->nPull);
 +        snew(window->Ntot, window->nPull);
 +        snew(window->g, window->nPull);
 +        snew(window->bsWeight, window->nPull);    
 +        window->bContrib=0;
 +
 +        if (opt->bCalcTauInt)
 +            snew(window->ztime,window->nPull);
 +        else
 +            window->ztime=NULL;
 +        snew(lennow,window->nPull);
 +
 +        for(g=0;g<window->nPull;++g) 
 +        {
 +            window->z[g]=1;
 +            window->bsWeight[g]=1.;
 +            snew(window->Histo[g],bins);
 +            window->N[g]=0;
 +            window->Ntot[g]=0;
 +            window->g[g]=1.;
 +            if (opt->bCalcTauInt)
 +                window->ztime[g]=NULL;
 +        }
 +
 +        /* Copying umbrella center and force const is more involved since not
 +           all pull groups from header (tpr file) may be used in window variable */
 +        for(g=0, gUsed=0 ;g<header->npullgrps; ++g)
 +        {
 +            if (groupsel && (groupsel->bUse[g] == FALSE))
 +                continue;
 +            window->k[gUsed]=header->k[g];
 +            window->pos[gUsed]=header->umbInitDist[g];
 +            gUsed++;
 +        }
 +    }
 +    else
 +    { /* only determine min and max */
 +        minfound=1e20;
 +        maxfound=-1e20;
 +        min=max=bins=0; /* Get rid of warnings */
 +    }
 +
 +
 +    for (i=0;i<nt;i++)
 +    {
 +        /* Do you want that time frame? */
 +        t=1.0/1000*( static_cast<int> ((y[0][i]*1000) + 0.5)); /* round time to fs */
 +        
 +        /* get time step of pdo file and get dstep from opt->dt */
 +        if (i==0)
 +        {
 +            time0=t;
 +        }
 +        else if (i==1)
 +        {
 +            dt=t-time0;
 +            if (opt->dt>0.0)
 +            {
 +                dstep=static_cast<int>(opt->dt/dt+0.5);
 +                if (dstep==0)
 +                    dstep=1;
 +            }
 +            if (!bGetMinMax)
 +                window->dt=dt*dstep;
 +        }
 +        
 +        dt_ok=(i%dstep == 0);
 +        timeok=(dt_ok && t >= opt->tmin && t <= opt->tmax);
 +        /*if (opt->verbose)
 +          printf(" time = %f, (tmin,tmax)=(%e,%e), dt_ok=%d timeok=%d\n", 
 +          t,opt->tmin, opt->tmax, dt_ok,timeok); */
 +        
 +        if (timeok)
 +        {
 +            /* Note: if groupsel == NULL:
 +             *          all groups in pullf/x file are stored in this window, and gUsed == g
 +             *       if groupsel != NULL:
 +             *          only groups with groupsel.bUse[g]==TRUE are stored. gUsed is not always equal g
 +             */
 +            gUsed=-1;
 +            for(g=0;g<header->npullgrps;++g) 
 +            {
 +                /* was this group selected for application in WHAM? */
 +                if (groupsel && (groupsel->bUse[g] == FALSE))
 +                {
 +                    continue;
 +                }
 +
 +                gUsed++;
 +
 +                if (bHaveForce)
 +                {
 +                    /* y has 1 time column y[0] and one column per force y[1],...,y[nGrps] */
 +                    force=y[g+1][i];
 +                    pos= -force/header->k[g] + header->umbInitDist[g];
 +                }
 +                else
 +                {
 +                    switch (header->pull_geometry)
 +                    {
 +                    case epullgDIST:
 +                        /* y has 1 time column y[0] and nColPerGrps columns per pull group; 
 +                           Distance to reference:                                           */
 +                        /* pos=dist_ndim(y+1+nColRef+g*nColPerGrp,header->pull_ndim,i); gmx 4.0 */
 +                        pos=dist_ndim(y + 1 + nColRefOnce + g*nColPerGrp,header->pull_ndim,i);
 +                        break;
 +                    case epullgPOS:
 +                        /* Columns
 +                           Time ref[ndim] group1[ndim] group2[ndim] ... */                         
 +                    case epullgCYL:
 +                        /* Columns
 +                           Time ref1[ndim] group1[ndim] ref2[ndim] group2[ndim] ... */
 +
 +                        /* * with geometry==position, we have the reference once (nColRefOnce==ndim), but
 +                           no extra reference group columns before each group (nColRefEachGrp==0)
 +
 +                           * with geometry==cylinder, we have no initial ref group column (nColRefOnce==0), 
 +                           but ndim ref group colums before every group (nColRefEachGrp==ndim)
 +                           Distance to reference: */
 +                        pos=y[1 + nColRefOnce + nColRefEachGrp + g*(nColRefEachGrp+nColPerGrp)][i];
 +                        break;
 +                    default:
 +                        gmx_fatal(FARGS,"Bad error, this error should have been catched before. Ups.\n");
 +                    }
 +                }
 +                
 +                /* printf("grp %d dpos %f poseq %f pos %f \n",g,dpos,poseq,pos); */
 +                if (bGetMinMax)
 +                {
 +                    if (pos<minfound)
 +                        minfound=pos;
 +                    if (pos>maxfound)
 +                        maxfound=pos;
 +                }
 +                else
 +                {
 +                    if (gUsed>=window->nPull)
 +                        gmx_fatal(FARGS,"gUsed too large (%d, nPull=%d). This error should have been catched before.\n",
 +                                  gUsed,window->nPull);
 +
 +                    if (opt->bCalcTauInt && !bGetMinMax)
 +                    {
 +                        /* save time series for autocorrelation analysis */
 +                        ntot=window->Ntot[gUsed];
 +                        /* printf("i %d, ntot %d, lennow[g] = %d\n",i,ntot,lennow[g]); */
 +                        if (ntot>=lennow[gUsed])
 +                        {
 +                            lennow[gUsed]+=blocklen;
 +                            srenew(window->ztime[gUsed],lennow[gUsed]);
 +                        }
 +                        window->ztime[gUsed][ntot]=pos;
 +                    }
 +                    
 +                    ibin=static_cast<int> (floor((pos-min)/(max-min)*bins));
 +                    if (opt->bCycl)
 +                    {
 +                        if (ibin<0)
-                             while ( (ibin-=bins) >= bins);
++                            while ( (ibin+=bins) < 0) ;
 +                        else if (ibin>=bins)
++                            while ( (ibin-=bins) >= bins) ;
 +                    }   
 +                    if(ibin >= 0 && ibin < bins) 
 +                    {
 +                        window->Histo[gUsed][ibin]+=1.;
 +                        window->N[gUsed]++;
 +                    }
 +                    window->Ntot[gUsed]++;
 +                }
 +            }
 +        }
 +        else if (t>opt->tmax)
 +        {
 +            if (opt->verbose)
 +                printf("time %f larger than tmax %f, stop reading this pullx/pullf file\n",t,opt->tmax);
 +            break;
 +        }
 +    }
 +  
 +    if (bGetMinMax)
 +    {
 +        *mintmp=minfound;
 +        *maxtmp=maxfound;
 +    }
 +    sfree(lennow);
 +    for (i=0;i<ny;i++)
 +        sfree(y[i]);
 +}
 +
 +//! read pullf-files.dat or pullx-files.dat and tpr-files.dat
 +void read_tpr_pullxf_files(char **fnTprs,char **fnPull,int nfiles,
 +                           t_UmbrellaHeader* header, 
 +                           t_UmbrellaWindow *window, t_UmbrellaOptions *opt)
 +{
 +    int i;
 +    real mintmp,maxtmp;
 +    
 +    printf("Reading %d tpr and pullf files\n",nfiles/2);
 +    
 +    /* min and max not given? */
 +    if (opt->bAuto)
 +    {
 +        printf("Automatic determination of boundaries...\n");
 +        opt->min=1e20;
 +        opt->max=-1e20;
 +        for (i=0;i<nfiles;  i++)
 +        {
 +            if (whaminFileType(fnTprs[i]) != whamin_tpr)
 +                gmx_fatal(FARGS,"Expected the %d'th file in input file to be a tpr file\n",i);
 +            read_tpr_header(fnTprs[i],header,opt);
 +            if (whaminFileType(fnPull[i]) != whamin_pullxf)
 +                gmx_fatal(FARGS,"Expected the %d'th file in input file to be a xvg (pullx/pullf) file\n",i);
 +            read_pull_xf(fnPull[i],fnTprs[i],header,NULL,opt,TRUE,&mintmp,&maxtmp,
 +                         (opt->nGroupsel>0) ? &opt->groupsel[i] : NULL);
 +            if (maxtmp>opt->max)
 +                opt->max=maxtmp;
 +            if (mintmp<opt->min)
 +                opt->min=mintmp;
 +        }
 +        printf("\nDetermined boundaries to %f and %f\n\n",opt->min,opt->max);
 +        if (opt->bBoundsOnly)
 +        {
 +            printf("Found option -boundsonly, now exiting.\n");
 +            exit (0);
 +        }
 +    }
 +    /* store stepsize in profile */
 +    opt->dz=(opt->max-opt->min)/opt->bins;
 +
 +    for (i=0;i<nfiles; i++)
 +    {
 +        if (whaminFileType(fnTprs[i]) != whamin_tpr)
 +            gmx_fatal(FARGS,"Expected the %d'th file in input file to be a tpr file\n",i);
 +        read_tpr_header(fnTprs[i],header,opt);
 +        if (whaminFileType(fnPull[i]) != whamin_pullxf)
 +            gmx_fatal(FARGS,"Expected the %d'th file in input file to be a xvg (pullx/pullf) file\n",i);
 +        read_pull_xf(fnPull[i],fnTprs[i],header,window+i,opt,FALSE,NULL,NULL,
 +                     (opt->nGroupsel>0) ? &opt->groupsel[i] : NULL);
 +        if (window[i].Ntot[0] == 0)
 +            fprintf(stderr,"\nWARNING, no data points read from file %s (check -b option)\n", fnPull[i]);
 +    }
 +
 +    for (i=0;i<nfiles; i++)
 +    {
 +        sfree(fnTprs[i]);
 +        sfree(fnPull[i]);
 +    }
 +    sfree(fnTprs);
 +    sfree(fnPull);
 +}
 +
 +/*! \brief Read integrated autocorrelation times from input file (option -iiact)
 + *
 + * Note: Here we consider tau[int] := int_0^inf ACF(t) as the integrated autocorrelation times.
 + * The factor `g := 1 + 2*tau[int]` subsequently enters the uncertainty.
 + */
 +void readIntegratedAutocorrelationTimes(t_UmbrellaWindow *window,int nwins,t_UmbrellaOptions *opt,
 +                                        const char* fn)
 +{
 +    int nlines,ny,i,ig;
 +    double **iact;
 +
 +    printf("Readging Integrated autocorrelation times from %s ...\n",fn);
 +    nlines=read_xvg(fn,&iact,&ny);
 +    if (nlines!=nwins)
 +        gmx_fatal(FARGS,"Found %d lines with integrated autocorrelation times in %s.\nExpected %d",
 +                  nlines,fn,nwins);
 +    for (i=0;i<nlines;i++){
 +        if (window[i].nPull != ny)
 +            gmx_fatal(FARGS,"You are providing autocorrelation times with option -iiact and the\n"
 +                      "number of pull groups is different in different simulations. That is not\n"
 +                      "supported yet. Sorry.\n");
 +        for (ig=0;ig<window[i].nPull;ig++){
 +            /* compare Kumar et al, J Comp Chem 13, 1011-1021 (1992) */
 +            window[i].g[ig]=1+2*iact[ig][i]/window[i].dt;  
 +      
 +            if (iact[ig][i] <= 0.0)
 +                fprintf(stderr,"\nWARNING, IACT = %f (window %d, group %d)\n", iact[ig][i],i,ig);
 +        }
 +    }
 +}
 +
 +
 +/*! \brief Smooth autocorreltion times along the reaction coordinate. 
 + *
 + * This is useful
 + * if the ACT is subject to high uncertainty in case if limited sampling. Note
 + * that -in case of limited sampling- the ACT may be severely underestimated.
 + * Note: the g=1+2tau are overwritten.
 + * If opt->bAllowReduceIact==FALSE, the ACTs are never reduced, only increased
 + * by the smoothing
 + */
 +void smoothIact(t_UmbrellaWindow *window,int nwins,t_UmbrellaOptions *opt)
 +{
 +    int i,ig,j,jg;
 +    double pos,dpos2,siglim,siglim2,gaufact,invtwosig2,w,weight,tausm;
 +  
 +    /* only evaluate within +- 3sigma of the Gausian */
 +    siglim=3.0*opt->sigSmoothIact;
 +    siglim2=dsqr(siglim);
 +    /* pre-factor of Gaussian */
 +    gaufact=1.0/(sqrt(2*M_PI)*opt->sigSmoothIact);
 +    invtwosig2=0.5/dsqr(opt->sigSmoothIact);
 +  
 +    for (i=0;i<nwins;i++)
 +    {
 +        snew(window[i].tausmooth,window[i].nPull);
 +        for (ig=0;ig<window[i].nPull;ig++)
 +        {
 +            tausm=0.;
 +            weight=0;
 +            pos=window[i].pos[ig];
 +            for (j=0;j<nwins;j++)
 +            {
 +                for (jg=0;jg<window[j].nPull;jg++)
 +                {
 +                    dpos2=dsqr(window[j].pos[jg]-pos);          
 +                    if (dpos2<siglim2){
 +                        w=gaufact*exp(-dpos2*invtwosig2);
 +                        weight+=w;
 +                        tausm+=w*window[j].tau[jg];
 +                        /*printf("Weight %g dpos2=%g pos=%g gaufact=%g invtwosig2=%g\n",
 +                          w,dpos2,pos,gaufact,invtwosig2); */
 +                    }
 +                }
 +            }
 +            tausm/=weight;
 +            if (opt->bAllowReduceIact || tausm>window[i].tau[ig])
 +                window[i].tausmooth[ig]=tausm;
 +            else
 +                window[i].tausmooth[ig]=window[i].tau[ig];
 +            window[i].g[ig] = 1+2*tausm/window[i].dt;
 +        }
 +    }
 +}
 +
 +//! Stop integrating autoccorelation function when ACF drops under this value
 +#define WHAM_AC_ZERO_LIMIT 0.05
 +
 +/*! \brief Try to compute the autocorrelation time for each umbrealla window 
 + */
 +void calcIntegratedAutocorrelationTimes(t_UmbrellaWindow *window,int nwins,
 +                                        t_UmbrellaOptions *opt,       const char *fn)
 +{
 +    int i,ig,ncorr,ntot,j,k,*count,restart;
 +    real *corr,c0,dt,tmp;
 +    real *ztime,av,tausteps;
 +    FILE *fp,*fpcorr=0;
 +  
 +    if (opt->verbose)
 +        fpcorr=xvgropen("hist_autocorr.xvg","Autocorrelation functions of umbrella windows",
 +                        "time [ps]","autocorrelation function",opt->oenv);
 +  
 +    printf("\n");
 +    for (i=0;i<nwins;i++)
 +    {
 +        printf("\rEstimating integrated autocorreltion times ... [%2.0f%%] ...",100.*(i+1)/nwins);
 +        fflush(stdout);
 +        ntot=window[i].Ntot[0];
 +
 +        /* using half the maximum time as length of autocorrelation function */
 +        ncorr=ntot/2;
 +        if (ntot<10)
 +            gmx_fatal(FARGS,"Tryig to estimtate autocorrelation time from only %d"
 +                      " points. Provide more pull data!",ntot);
 +        snew(corr,ncorr);
 +        /* snew(corrSq,ncorr); */
 +        snew(count,ncorr);
 +        dt=window[i].dt;
 +        snew(window[i].tau,window[i].nPull);
 +        restart=static_cast<int>(opt->acTrestart/dt+0.5);
 +        if (restart==0)
 +            restart=1;
 +
 +        for (ig=0;ig<window[i].nPull;ig++)
 +        {            
 +            if (ntot != window[i].Ntot[ig])
 +                gmx_fatal(FARGS,"Encountered different nr of frames in different pull groups.\n"
 +                          "That should not happen. (%d and %d)\n", ntot,window[i].Ntot[ig]);
 +            ztime=window[i].ztime[ig];
 +            
 +            /* calc autocorrelation function C(t) = < [z(tau)-<z>]*[z(tau+t)-<z>]> */
 +            for(j=0, av=0; (j<ntot); j++)
 +                av+=ztime[j];
 +            av/=ntot;
 +            for(k=0; (k<ncorr); k++)
 +            {
 +                corr[k]=0.;
 +                count[k]=0;
 +            }
 +            for(j=0; (j<ntot); j+=restart) 
 +                for(k=0; (k<ncorr) && (j+k < ntot); k++)
 +                {
 +                    tmp=(ztime[j]-av)*(ztime[j+k]-av); 
 +                    corr  [k] += tmp;
 +                    /* corrSq[k] += tmp*tmp; */
 +                    count[k]++;
 +                }
 +            /* divide by nr of frames for each time displacement */
 +            for(k=0; (k<ncorr); k++) 
 +            {
 +                /* count probably = (ncorr-k+(restart-1))/restart; */
 +                corr[k] = corr[k]/count[k];
 +                /* variance of autocorrelation function */
 +                /* corrSq[k]=corrSq[k]/count[k]; */
 +            }
 +            /* normalize such that corr[0] == 0 */
 +            c0=1./corr[0];
 +            for(k=0; (k<ncorr); k++)
 +            {
 +                corr[k]*=c0;
 +                /* corrSq[k]*=c0*c0; */
 +            }
 +
 +            /* write ACFs in verbose mode */
 +            if (fpcorr)
 +            {
 +                for(k=0; (k<ncorr); k++)
 +                    fprintf(fpcorr,"%g  %g\n",k*dt,corr[k]);
 +                fprintf(fpcorr,"&\n");
 +            }
 +      
 +            /* esimate integrated correlation time, fitting is too unstable */
 +            tausteps = 0.5*corr[0];
 +            /* consider corr below WHAM_AC_ZERO_LIMIT as noise */
 +            for(j=1; (j<ncorr) && (corr[j]>WHAM_AC_ZERO_LIMIT); j++)
 +                tausteps += corr[j];
 +        
 +            /* g = 1+2*tau, see. Ferrenberg/Swendsen, PRL 63:1195 (1989) or
 +               Kumar et al, eq. 28 ff. */
 +            window[i].tau[ig] = tausteps*dt;
 +            window[i].g[ig] = 1+2*tausteps;
 +            /* printf("win %d, group %d, estimated correlation time = %g ps\n",i,ig,window[i].tau[ig]); */
 +        } /* ig loop */
 +        sfree(corr);
 +        sfree(count);
 +    }
 +    printf(" done\n");
 +    if (fpcorr)
 +        ffclose(fpcorr);
 +  
 +    /* plot IACT along reaction coordinate */
 +    fp=xvgropen(fn,"Integrated autocorrelation times","z","IACT [ps]",opt->oenv);
 +    fprintf(fp,"@    s0 symbol 1\n@    s0 symbol size 0.5\n@    s0 line linestyle 0\n");
 +    fprintf(fp,"#  WIN   tau(gr1)  tau(gr2) ...\n");
 +    for (i=0;i<nwins;i++)
 +    {
 +        fprintf(fp,"# %3d   ",i);
 +        for (ig=0;ig<window[i].nPull;ig++)
 +            fprintf(fp," %11g",window[i].tau[ig]);
 +        fprintf(fp,"\n");
 +    }
 +    for (i=0;i<nwins;i++)
 +        for (ig=0;ig<window[i].nPull;ig++)
 +            fprintf(fp,"%8g %8g\n",window[i].pos[ig],window[i].tau[ig]);
 +    if (opt->sigSmoothIact > 0.0)
 +    {
 +        printf("Smoothing autocorrelation times along reaction coordinate with Gaussian of sig = %g\n",
 +               opt->sigSmoothIact);
 +        /* smooth IACT along reaction coordinate and overwrite g=1+2tau */
 +        smoothIact(window,nwins,opt);
 +        fprintf(fp,"&\n@    s1 symbol 1\n@    s1 symbol size 0.5\n@    s1 line linestyle 0\n");
 +        fprintf(fp,"@    s1 symbol color 2\n");
 +        for (i=0;i<nwins;i++)
 +            for (ig=0;ig<window[i].nPull;ig++)
 +                fprintf(fp,"%8g %8g\n",window[i].pos[ig],window[i].tausmooth[ig]);
 +    }   
 +    ffclose(fp);
 +    printf("Wrote %s\n",fn);
 +}
 +
 +/*! \brief
 + * compute average and sigma of each umbrella histogram 
 + */
 +void averageSigma(t_UmbrellaWindow *window,int nwins,t_UmbrellaOptions *opt)
 +{
 +    int i,ig,ntot,k;
 +    real av,sum2,sig,diff,*ztime,nSamplesIndep;
 +
 +    for (i=0;i<nwins;i++)
 +    {
 +        snew(window[i].aver, window[i].nPull);
 +        snew(window[i].sigma,window[i].nPull);
 +
 +        ntot=window[i].Ntot[0];
 +        for (ig=0;ig<window[i].nPull;ig++)
 +        {
 +            ztime=window[i].ztime[ig];
 +            for (k=0, av=0.; k<ntot; k++)
 +                av+=ztime[k];
 +            av/=ntot;
 +            for (k=0, sum2=0.; k<ntot; k++)
 +            {
 +                diff=ztime[k]-av;
 +                sum2+=diff*diff;
 +            }
 +            sig=sqrt(sum2/ntot);
 +            window[i].aver[ig]=av;
 +
 +            /* Note: This estimate for sigma is biased from the limited sampling.
 +               Correct sigma by n/(n-1) where n = number of independent
 +               samples. Only possible if IACT is known.
 +            */
 +            if (window[i].tau)
 +            {
 +                nSamplesIndep=window[i].N[ig]/(window[i].tau[ig]/window[i].dt);
 +                window[i].sigma[ig]=sig * nSamplesIndep/(nSamplesIndep-1);
 +            }
 +            else
 +                window[i].sigma[ig]=sig;
 +            printf("win %d, aver = %f  sig = %f\n",i,av,window[i].sigma[ig]);
 +        }
 +    }      
 +}
 +
 +
 +/*! \brief 
 + * Use histograms to compute average force on pull group.
 + */
 +void computeAverageForce(t_UmbrellaWindow *window,int nWindows,t_UmbrellaOptions *opt)
 +{
 +    int i,j,bins=opt->bins,k;
 +    double dz,min=opt->min,max=opt->max,displAv,temp,distance,ztot,ztot_half,w,weight;
 +    double posmirrored;
 +
 +    dz=(max-min)/bins;
 +    ztot=opt->max-min;
 +    ztot_half=ztot/2;
 +
 +    /* Compute average displacement from histograms */
 +    for(j=0;j<nWindows;++j) 
 +    {
 +        snew(window[j].forceAv,window[j].nPull);
 +        for(k=0;k<window[j].nPull;++k) 
 +        {
 +            displAv = 0.0;
 +            weight  = 0.0;
 +            for(i=0;i<opt->bins;++i)
 +            {   
 +                temp=(1.0*i+0.5)*dz+min;
 +                distance = temp - window[j].pos[k];
 +                if (opt->bCycl)
 +                {                                       /* in cyclic wham:             */
 +                    if (distance > ztot_half)           /*    |distance| < ztot_half   */
 +                        distance-=ztot;
 +                    else if (distance < -ztot_half)
 +                        distance+=ztot;
 +                }
 +                w=window[j].Histo[k][i]/window[j].g[k];
 +                displAv  += w*distance;
 +                weight+=w;
 +                /* Are we near min or max? We are getting wrong forces from the histgrams since
 +                   the histograms are zero outside [min,max). Therefore, assume that the position
 +                   on the other side of the histomgram center is equally likely. */
 +                if (!opt->bCycl)
 +                {
 +                    posmirrored=window[j].pos[k]-distance;
 +                    if (posmirrored>=max || posmirrored<min)
 +                    {
 +                        displAv  += -w*distance;
 +                        weight+=w;
 +                    }
 +                }
 +            }
 +            displAv  /= weight;
 +
 +            /* average force from average displacement */
 +            window[j].forceAv[k] = displAv*window[j].k[k];
 +            /* sigma from average square displacement */
 +            /* window[j].sigma  [k] = sqrt(displAv2); */
 +            /* printf("Win %d, sigma = %f\n",j,sqrt(displAv2)); */
 +        }
 +    }
 +}
 +
 +/*! \brief
 + * Check if the complete reaction coordinate is covered by the histograms 
 + */
 +void  checkReactionCoordinateCovered(t_UmbrellaWindow *window,int nwins,
 +                                     t_UmbrellaOptions *opt)
 +{
 +    int i,ig,j,bins=opt->bins,bBoundary;
 +    real avcount=0,z,relcount,*count;
 +    snew(count,opt->bins);
 +
 +    for(j=0;j<opt->bins;++j) 
 +    {        
 +        for (i=0;i<nwins;i++){
 +            for (ig=0;ig<window[i].nPull;ig++)
 +                count[j]+=window[i].Histo[ig][j];
 +        }
 +        avcount+=1.0*count[j];
 +    }
 +    avcount/=bins;
 +    for(j=0;j<bins;++j) 
 +    {
 +        relcount=count[j]/avcount;
 +        z=(j+0.5)*opt->dz+opt->min;
 +        bBoundary=( j<bins/20 || (bins-j)>bins/20 );
 +        /* check for bins with no data */
 +        if (count[j] == 0)
 +            fprintf(stderr, "\nWARNING, no data point in bin %d (z=%g) !\n"
 +                    "You may not get a reasonable profile. Check your histograms!\n",j,z);
 +        /* and check for poor sampling */
 +        else if (relcount<0.005 && !bBoundary)
 +            fprintf(stderr, "Warning, poor sampling bin %d (z=%g). Check your histograms!\n",j,z);
 +    }
 +    sfree(count);
 +}
 +
 +/*! \brief Compute initial potential by integrating the average force
 + *
 + * This speeds up the convergence by roughly a factor of 2
 + */
 +void guessPotByIntegration(t_UmbrellaWindow *window,int nWindows,t_UmbrellaOptions *opt,
 +                           char *fn)
 +{
 +    int i,j,ig,bins=opt->bins,nHist,winmin,groupmin;
 +    double dz,min=opt->min,*pot,pos,hispos,dist,diff,fAv,distmin,*f;
 +    FILE *fp;
 +
 +    dz=(opt->max-min)/bins;
 +
 +    printf("Getting initial potential by integration.\n");
 +
 +    /* Compute average displacement from histograms */
 +    computeAverageForce(window,nWindows,opt);
 +
 +    /* Get force for each bin from all histograms in this bin, or, alternatively,
 +       if no histograms are inside this bin, from the closest histogram */
 +    snew(pot,bins);
 +    snew(f,bins);
 +    for(j=0;j<opt->bins;++j) 
 +    {
 +        pos=(1.0*j+0.5)*dz+min;
 +        nHist=0;
 +        fAv=0.;
 +        distmin=1e20;
 +        groupmin=winmin=0;
 +        for (i=0;i<nWindows;i++)
 +        {
 +            for (ig=0;ig<window[i].nPull;ig++)
 +            {
 +                hispos=window[i].pos[ig];
 +                dist=fabs(hispos-pos);
 +                /* average force within bin */
 +                if (dist < dz/2)
 +                {
 +                    nHist++;
 +                    fAv+=window[i].forceAv[ig];
 +                }
 +                /* at the same time, rememer closest histogram */
 +                if (dist<distmin){
 +                    winmin=i;
 +                    groupmin=ig;
 +                    distmin=dist;
 +                }
 +            }
 +        }
 +        /* if no histogram found in this bin, use closest histogram */
 +        if (nHist>0)
 +            fAv=fAv/nHist;
 +        else{
 +            fAv=window[winmin].forceAv[groupmin];
 +        }
 +        f[j]=fAv;
 +    }
 +    for(j=1;j<opt->bins;++j)
 +        pot[j] = pot[j-1] - 0.5*dz*(f[j-1]+f[j]);
 +
 +    /* cyclic wham: linearly correct possible offset */
 +    if (opt->bCycl)
 +    {
 +        diff=(pot[bins-1]-pot[0])/(bins-1);
 +        for(j=1;j<opt->bins;++j)
 +            pot[j]-=j*diff;
 +    }
 +    if (opt->verbose)
 +    {
 +        fp=xvgropen("pmfintegrated.xvg","PMF from force integration","z","PMF [kJ/mol]",opt->oenv);
 +        for(j=0;j<opt->bins;++j)
 +            fprintf(fp,"%g  %g\n",(j+0.5)*dz+opt->min,pot[j]);
 +        ffclose(fp);
 +        printf("verbose mode: wrote %s with PMF from interated forces\n","pmfintegrated.xvg");
 +    }
 +
 +    /* get initial z=exp(-F[i]/kT) from integrated potential, where F[i] denote the free
 +       energy offsets which are usually determined by wham 
 +       First: turn pot into probabilities:
 +    */
 +    for(j=0;j<opt->bins;++j)
 +        pot[j]=exp(-pot[j]/(8.314e-3*opt->Temperature));
 +    calc_z(pot,window,nWindows,opt,TRUE);
 +    
 +    sfree(pot);
 +    sfree(f);
 +}
 +
 +//! Count number of words in an line
 +static int wordcount(char *ptr)
 +{
 +  int i,n,is[2];
 +  int cur=0;
 +
 +  if (strlen(ptr) == 0)
 +    return 0;
 +  /* fprintf(stderr,"ptr='%s'\n",ptr); */
 +  n=1;
 +  for(i=0; (ptr[i] != '\0'); i++) {
 +    is[cur] = isspace(ptr[i]);
 +    if ((i > 0)  && (is[cur] && !is[1-cur]))
 +      n++;
 +    cur=1-cur;
 +  }
 +  return n;
 +}
 +
 +/*! \brief Read input file for pull group selection (option -is)
 + *
 + * TO DO: ptr=fgets(...) is never freed (small memory leak)
 + */
 +void readPullGroupSelection(t_UmbrellaOptions *opt, char **fnTpr, int nTpr)
 +{
 +    FILE *fp;
 +    int i,iline,n,len=STRLEN,temp;
 +    char *ptr=0,*tmpbuf=0;
 +    char fmt[1024],fmtign[1024];
 +    int block=1,sizenow;
 +
 +    fp=ffopen(opt->fnGroupsel,"r");
 +    opt->groupsel=NULL;
 +
 +    snew(tmpbuf,len);
 +    sizenow=0;
 +    iline=0;
 +    while ( (ptr=fgets3(fp,tmpbuf,&len)) !=NULL)
 +    {
 +        trim(ptr);
 +        n=wordcount(ptr);
 +
 +        if (iline >= sizenow)
 +        {
 +            sizenow+=block;
 +            srenew(opt->groupsel,sizenow);
 +        }
 +        opt->groupsel[iline].n = n;
 +        opt->groupsel[iline].nUse = 0;
 +        snew(opt->groupsel[iline].bUse,n);
 +
 +        fmtign[0] = '\0';
 +        for (i=0; i<n; i++)
 +        {
 +            strcpy(fmt,fmtign);
 +            strcat(fmt,"%d");
 +            if (sscanf(ptr,fmt,&temp))
 +            {
 +                opt->groupsel[iline].bUse[i] = (temp > 0);
 +                if ( opt->groupsel[iline].bUse[i])
 +                    opt->groupsel[iline].nUse++;
 +            }
 +            strcat(fmtign,"%*s");
 +        }
 +        iline++;
 +    }
 +    opt->nGroupsel=iline;
 +    if (nTpr != opt->nGroupsel)
 +        gmx_fatal(FARGS,"Found %d tpr files but %d lines in %s\n",nTpr,opt->nGroupsel,
 +                  opt->fnGroupsel);
 +
 +    printf("\nUse only these pull groups:\n");
 +    for (iline=0; iline<nTpr; iline++)
 +    {
 +        printf("%s (%d of %d groups):",fnTpr[iline], opt->groupsel[iline].nUse, opt->groupsel[iline].n);
 +        for (i=0; i < opt->groupsel[iline].n; i++)
 +            if (opt->groupsel[iline].bUse[i])
 +                printf(" %d",i+1);
 +        printf("\n");
 +    }
 +    printf("\n");
 +
 +    sfree(tmpbuf);
 +}
 +
 +//! Boolean XOR
 +#define WHAMBOOLXOR(a,b) ( ((!(a))&&(b)) || ((a)&&(!(b))))
 +
 +/*! Number of elements in fnm (used for command line parsing) */
 +#define NFILE asize(fnm)
 +
 +//! The main g_wham routine
 +int gmx_wham(int argc,char *argv[])
 +{
 +    const char *desc[] = {
 +        "This is an analysis program that implements the Weighted",
 +        "Histogram Analysis Method (WHAM). It is intended to analyze",
 +        "output files generated by umbrella sampling simulations to ",
 +        "compute a potential of mean force (PMF). [PAR] ",
 +        "At present, three input modes are supported.[BR]",
 +        "[TT]*[tt] With option [TT]-it[tt], the user provides a file which contains the",
 +        " file names of the umbrella simulation run-input files ([TT].tpr[tt] files),",
 +        " AND, with option [TT]-ix[tt], a file which contains file names of",
 +        " the pullx [TT]mdrun[tt] output files. The [TT].tpr[tt] and pullx files must",
 +        " be in corresponding order, i.e. the first [TT].tpr[tt] created the",
 +        " first pullx, etc.[BR]",
 +        "[TT]*[tt] Same as the previous input mode, except that the the user",
 +        " provides the pull force output file names ([TT]pullf.xvg[tt]) with option [TT]-if[tt].",
 +        " From the pull force the position in the umbrella potential is",
 +        " computed. This does not work with tabulated umbrella potentials.[BR]"
 +        "[TT]*[tt] With option [TT]-ip[tt], the user provides file names of (gzipped) [TT].pdo[tt] files, i.e.",
 +        " the GROMACS 3.3 umbrella output files. If you have some unusual"
 +        " reaction coordinate you may also generate your own [TT].pdo[tt] files and",
 +        " feed them with the [TT]-ip[tt] option into to [TT]g_wham[tt]. The [TT].pdo[tt] file header",
 +        " must be similar to the following:[PAR]",
 +        "[TT]# UMBRELLA      3.0[BR]",
 +        "# Component selection: 0 0 1[BR]",
 +        "# nSkip 1[BR]",
 +        "# Ref. Group 'TestAtom'[BR]",
 +        "# Nr. of pull groups 2[BR]",
 +        "# Group 1 'GR1'  Umb. Pos. 5.0 Umb. Cons. 1000.0[BR]",
 +        "# Group 2 'GR2'  Umb. Pos. 2.0 Umb. Cons. 500.0[BR]",
 +        "#####[tt][PAR]",
 +        "The number of pull groups, umbrella positions, force constants, and names ",
 +        "may (of course) differ. Following the header, a time column and ",
 +        "a data column for each pull group follows (i.e. the displacement",
 +        "with respect to the umbrella center). Up to four pull groups are possible ",
 +        "per [TT].pdo[tt] file at present.[PAR]",
 +        "By default, all pull groups found in all pullx/pullf files are used in WHAM. If only ",
 +        "some of the pull groups should be used, a pull group selection file (option [TT]-is[tt]) can ",
 +        "be provided. The selection file must contain one line for each tpr file in tpr-files.dat.",
 +        "Each of these lines must contain one digit (0 or 1) for each pull group in the tpr file. ",
 +        "Here, 1 indicates that the pull group is used in WHAM, and 0 means it is omitted. Example:",
 +        "If you have three tpr files, each containing 4 pull groups, but only pull group 1 and 2 should be ",
 +        "used, groupsel.dat looks like this:[BR]",
 +        "1 1 0 0[BR]",
 +        "1 1 0 0[BR]",
 +        "1 1 0 0[PAR]",
 +        "By default, the output files are[BR]",
 +        "  [TT]-o[tt]      PMF output file[BR]",
 +        "  [TT]-hist[tt]   Histograms output file[BR]",
 +        "Always check whether the histograms sufficiently overlap.[PAR]",
 +        "The umbrella potential is assumed to be harmonic and the force constants are ",
 +        "read from the [TT].tpr[tt] or [TT].pdo[tt] files. If a non-harmonic umbrella force was applied ",
 +        "a tabulated potential can be provided with [TT]-tab[tt].[PAR]",
 +        "WHAM OPTIONS[BR]------------[BR]",
 +        "  [TT]-bins[tt]   Number of bins used in analysis[BR]",
 +        "  [TT]-temp[tt]   Temperature in the simulations[BR]",
 +        "  [TT]-tol[tt]    Stop iteration if profile (probability) changed less than tolerance[BR]",
 +        "  [TT]-auto[tt]   Automatic determination of boundaries[BR]",
 +        "  [TT]-min,-max[tt]   Boundaries of the profile [BR]",
 +        "The data points that are used to compute the profile",
 +        "can be restricted with options [TT]-b[tt], [TT]-e[tt], and [TT]-dt[tt]. ",
 +        "Adjust [TT]-b[tt] to ensure sufficient equilibration in each ",
 +        "umbrella window.[PAR]",
 +        "With [TT]-log[tt] (default) the profile is written in energy units, otherwise ",
 +        "(with [TT]-nolog[tt]) as probability. The unit can be specified with [TT]-unit[tt]. ",
 +        "With energy output, the energy in the first bin is defined to be zero. ",
 +        "If you want the free energy at a different ",
 +        "position to be zero, set [TT]-zprof0[tt] (useful with bootstrapping, see below).[PAR]",
 +        "For cyclic or periodic reaction coordinates (dihedral angle, channel PMF",
 +        "without osmotic gradient), the option [TT]-cycl[tt] is useful. [TT]g_wham[tt] will make use of the ",
 +        "periodicity of the system and generate a periodic PMF. The first and the last bin of the",
 +        "reaction coordinate will assumed be be neighbors.[PAR]",
 +        "Option [TT]-sym[tt] symmetrizes the profile around z=0 before output, ",
 +        "which may be useful for, e.g. membranes.[PAR]",
 +        "AUTOCORRELATIONS[BR]----------------[BR]",
 +        "With [TT]-ac[tt], [TT]g_wham[tt] estimates the integrated autocorrelation ",
 +        "time (IACT) [GRK]tau[grk] for each umbrella window and weights the respective ",
 +        "window with 1/[1+2*[GRK]tau[grk]/dt]. The IACTs are written ",
 +        "to the file defined with [TT]-oiact[tt]. In verbose mode, all ",
 +        "autocorrelation functions (ACFs) are written to [TT]hist_autocorr.xvg[tt]. ",
 +        "Because the IACTs can be severely underestimated in case of limited ",
 +        "sampling, option [TT]-acsig[tt] allows one to smooth the IACTs along the ",
 +        "reaction coordinate with a Gaussian ([GRK]sigma[grk] provided with [TT]-acsig[tt], ",
 +        "see output in [TT]iact.xvg[tt]). Note that the IACTs are estimated by simple ",
 +        "integration of the ACFs while the ACFs are larger 0.05.",
 +        "If you prefer to compute the IACTs by a more sophisticated (but possibly ",
 +        "less robust) method such as fitting to a double exponential, you can ",
 +        "compute the IACTs with [TT]g_analyze[tt] and provide them to [TT]g_wham[tt] with the file ",
 +        "[TT]iact-in.dat[tt] (option [TT]-iiact[tt]), which should contain one line per ",
 +        "input file ([TT].pdo[tt] or pullx/f file) and one column per pull group in the respective file.[PAR]",
 +        "ERROR ANALYSIS[BR]--------------[BR]",
 +        "Statistical errors may be estimated with bootstrap analysis. Use it with care, ",
 +        "otherwise the statistical error may be substantially underestimated. ",
 +        "More background and examples for the bootstrap technique can be found in ",
 +        "Hub, de Groot and Van der Spoel, JCTC (2010) 6: 3713-3720.[BR]",
 +        "[TT]-nBootstrap[tt] defines the number of bootstraps (use, e.g., 100). ",
 +        "Four bootstrapping methods are supported and ",
 +        "selected with [TT]-bs-method[tt].[BR]",
 +        "  (1) [TT]b-hist[tt]   Default: complete histograms are considered as independent ",
 +        "data points, and the bootstrap is carried out by assigning random weights to the ",
 +        "histograms (\"Bayesian bootstrap\"). Note that each point along the reaction coordinate",
 +        "must be covered by multiple independent histograms (e.g. 10 histograms), otherwise the ",
 +        "statistical error is underestimated.[BR]",
 +        "  (2) [TT]hist[tt]    Complete histograms are considered as independent data points. ",
 +        "For each bootstrap, N histograms are randomly chosen from the N given histograms ",
 +        "(allowing duplication, i.e. sampling with replacement).",
 +        "To avoid gaps without data along the reaction coordinate blocks of histograms ",
 +        "([TT]-histbs-block[tt]) may be defined. In that case, the given histograms are ",
 +        "divided into blocks and only histograms within each block are mixed. Note that ",
 +        "the histograms within each block must be representative for all possible histograms, ",
 +        "otherwise the statistical error is underestimated.[BR]",
 +        "  (3) [TT]traj[tt]  The given histograms are used to generate new random trajectories,",
 +        "such that the generated data points are distributed according the given histograms ",
 +        "and properly autocorrelated. The autocorrelation time (ACT) for each window must be ",
 +        "known, so use [TT]-ac[tt] or provide the ACT with [TT]-iiact[tt]. If the ACT of all ",
 +        "windows are identical (and known), you can also provide them with [TT]-bs-tau[tt]. ",
 +        "Note that this method may severely underestimate the error in case of limited sampling, ",
 +        "that is if individual histograms do not represent the complete phase space at ",
 +        "the respective positions.[BR]",
 +        "  (4) [TT]traj-gauss[tt]  The same as method [TT]traj[tt], but the trajectories are ",
 +        "not bootstrapped from the umbrella histograms but from Gaussians with the average ",
 +        "and width of the umbrella histograms. That method yields similar error estimates ",
 +        "like method [TT]traj[tt].[PAR]"
 +        "Bootstrapping output:[BR]",
 +        "  [TT]-bsres[tt]   Average profile and standard deviations[BR]",
 +        "  [TT]-bsprof[tt]  All bootstrapping profiles[BR]",
 +        "With [TT]-vbs[tt] (verbose bootstrapping), the histograms of each bootstrap are written, ",
 +        "and, with bootstrap method [TT]traj[tt], the cumulative distribution functions of ",
 +        "the histograms."
 +    };
 +
 +    const char *en_unit[]={NULL,"kJ","kCal","kT",NULL};
 +    const char *en_unit_label[]={"","E (kJ mol\\S-1\\N)","E (kcal mol\\S-1\\N)","E (kT)",NULL};
 +    const char *en_bsMethod[]={ NULL,"b-hist", "hist", "traj", "traj-gauss", NULL };
 +  
 +    static t_UmbrellaOptions opt;
 +  
 +    t_pargs pa[] = {
 +        { "-min", FALSE, etREAL, {&opt.min},
 +          "Minimum coordinate in profile"},
 +        { "-max", FALSE, etREAL, {&opt.max},
 +          "Maximum coordinate in profile"},
 +        { "-auto", FALSE, etBOOL, {&opt.bAuto},
 +          "Determine min and max automatically"},
 +        { "-bins",FALSE, etINT, {&opt.bins},
 +          "Number of bins in profile"},
 +        { "-temp", FALSE, etREAL, {&opt.Temperature},
 +          "Temperature"},
 +        { "-tol", FALSE, etREAL, {&opt.Tolerance},
 +          "Tolerance"},
 +        { "-v", FALSE, etBOOL, {&opt.verbose},
 +          "Verbose mode"},
 +        { "-b", FALSE, etREAL, {&opt.tmin}, 
 +          "First time to analyse (ps)"},
 +        { "-e", FALSE, etREAL, {&opt.tmax}, 
 +          "Last time to analyse (ps)"},
 +        { "-dt", FALSE, etREAL, {&opt.dt},
 +          "Analyse only every dt ps"},
 +        { "-histonly", FALSE, etBOOL, {&opt.bHistOnly},
 +          "Write histograms and exit"},
 +        { "-boundsonly", FALSE, etBOOL, {&opt.bBoundsOnly},
 +          "Determine min and max and exit (with [TT]-auto[tt])"},
 +        { "-log", FALSE, etBOOL, {&opt.bLog},
 +          "Calculate the log of the profile before printing"},
 +        { "-unit", FALSE,  etENUM, {en_unit},
 +          "Energy unit in case of log output" },
 +        { "-zprof0", FALSE, etREAL, {&opt.zProf0},
 +          "Define profile to 0.0 at this position (with [TT]-log[tt])"},
 +        { "-cycl", FALSE, etBOOL, {&opt.bCycl},
 +          "Create cyclic/periodic profile. Assumes min and max are the same point."},
 +        { "-sym", FALSE, etBOOL, {&opt.bSym},
 +          "Symmetrize profile around z=0"},   
 +        { "-hist-eq", FALSE, etBOOL, {&opt.bHistEq},
 +          "HIDDENEnforce equal weight for all histograms. (Non-Weighed-HAM)"},
 +        { "-ac", FALSE, etBOOL, {&opt.bCalcTauInt},
 +          "Calculate integrated autocorrelation times and use in wham"},
 +        { "-acsig", FALSE, etREAL, {&opt.sigSmoothIact},
 +          "Smooth autocorrelation times along reaction coordinate with Gaussian of this [GRK]sigma[grk]"},
 +        { "-ac-trestart", FALSE, etREAL, {&opt.acTrestart},
 +          "When computing autocorrelation functions, restart computing every .. (ps)"},
 +        { "-acred", FALSE, etBOOL, {&opt.bAllowReduceIact},
 +          "HIDDENWhen smoothing the ACTs, allow to reduce ACTs. Otherwise, only increase ACTs "
 +          "during smoothing"},
 +        { "-nBootstrap", FALSE,  etINT, {&opt.nBootStrap},
 +          "nr of bootstraps to estimate statistical uncertainty (e.g., 200)" },
 +        { "-bs-method", FALSE,  etENUM, {en_bsMethod},
 +          "Bootstrap method" },
 +        { "-bs-tau", FALSE, etREAL, {&opt.tauBootStrap},
 +          "Autocorrelation time (ACT) assumed for all histograms. Use option [TT]-ac[tt] if ACT is unknown."},
 +        { "-bs-seed", FALSE, etINT, {&opt.bsSeed},
 +          "Seed for bootstrapping. (-1 = use time)"},
 +        { "-histbs-block", FALSE, etINT, {&opt.histBootStrapBlockLength},
 +          "When mixing histograms only mix within blocks of [TT]-histbs-block[tt]."},
 +        { "-vbs", FALSE, etBOOL, {&opt.bs_verbose},
 +          "Verbose bootstrapping. Print the CDFs and a histogram file for each bootstrap."},
 +        { "-stepout", FALSE, etINT, {&opt.stepchange},
 +          "HIDDENWrite maximum change every ... (set to 1 with [TT]-v[tt])"},
 +        { "-updateContr", FALSE, etINT, {&opt.stepUpdateContrib},
 +          "HIDDENUpdate table with significan contributions to WHAM every ... iterations"},
 +    };
 +  
 +    t_filenm fnm[] = {
 +        { efDAT, "-ix","pullx-files",ffOPTRD},  /* wham input: pullf.xvg's and tprs           */
 +        { efDAT, "-if","pullf-files",ffOPTRD},  /* wham input: pullf.xvg's and tprs           */
 +        { efDAT, "-it","tpr-files",ffOPTRD},    /* wham input: tprs                           */
 +        { efDAT, "-ip","pdo-files",ffOPTRD},    /* wham input: pdo files (gmx3 style)         */
 +        { efDAT, "-is","groupsel",ffOPTRD},     /* input: select pull groups to use           */
 +        { efXVG, "-o", "profile", ffWRITE },    /* output file for profile                     */
 +        { efXVG, "-hist","histo", ffWRITE},       /* output file for histograms                  */
 +        { efXVG, "-oiact","iact",ffOPTWR},      /* writing integrated autocorrelation times    */
 +        { efDAT, "-iiact","iact-in",ffOPTRD},   /* reading integrated autocorrelation times   */    
 +        { efXVG, "-bsres","bsResult", ffOPTWR}, /* average and errors of bootstrap analysis    */
 +        { efXVG, "-bsprof","bsProfs", ffOPTWR}, /* output file for bootstrap profiles          */
 +        { efDAT, "-tab","umb-pot",ffOPTRD},     /* Tabulated umbrella potential (if not harmonic) */    
 +    };
 +  
 +    int i,j,l,nfiles,nwins,nfiles2;
 +    t_UmbrellaHeader header;
 +    t_UmbrellaWindow * window=NULL;
 +    double *profile,maxchange=1e20;
 +    gmx_bool bMinSet,bMaxSet,bAutoSet,bExact=FALSE;
 +    char **fninTpr,**fninPull,**fninPdo;
 +    const char *fnPull;
 +    FILE *histout,*profout;
 +    char ylabel[256],title[256];  
 +
 +    CopyRight(stderr,argv[0]);
 +
 +    opt.bins=200;
 +    opt.verbose=FALSE;
 +    opt.bHistOnly=FALSE;
 +    opt.bCycl=FALSE;
 +    opt.tmin=50;
 +    opt.tmax=1e20;
 +    opt.dt=0.0;
 +    opt.min=0;
 +    opt.max=0;
 +    opt.bAuto=TRUE;
 +    opt.nGroupsel=0;
 +
 +    /* bootstrapping stuff */
 +    opt.nBootStrap=0;
 +    opt.bsMethod=bsMethod_hist;
 +    opt.tauBootStrap=0.0;
 +    opt.bsSeed=-1;
 +    opt.histBootStrapBlockLength=8;
 +    opt.bs_verbose=FALSE;
 +
 +    opt.bLog=TRUE;
 +    opt.unit=en_kJ;
 +    opt.zProf0=0.;
 +    opt.Temperature=298;
 +    opt.Tolerance=1e-6;
 +    opt.bBoundsOnly=FALSE;
 +    opt.bSym=FALSE;
 +    opt.bCalcTauInt=FALSE;
 +    opt.sigSmoothIact=0.0;
 +    opt.bAllowReduceIact=TRUE;
 +    opt.bInitPotByIntegration=TRUE;
 +    opt.acTrestart=1.0;
 +    opt.stepchange=100;
 +    opt.stepUpdateContrib=100;
 +
 +    parse_common_args(&argc,argv,PCA_BE_NICE,
 +                      NFILE,fnm,asize(pa),pa,asize(desc),desc,0,NULL,&opt.oenv);
 +  
 +    opt.unit=nenum(en_unit);
 +    opt.bsMethod=nenum(en_bsMethod);
 +
 +    opt.bProf0Set=opt2parg_bSet("-zprof0",  asize(pa), pa);
 +  
 +    opt.bTab=opt2bSet("-tab",NFILE,fnm);
 +    opt.bPdo=opt2bSet("-ip",NFILE,fnm);
 +    opt.bTpr=opt2bSet("-it",NFILE,fnm);
 +    opt.bPullx=opt2bSet("-ix",NFILE,fnm);
 +    opt.bPullf=opt2bSet("-if",NFILE,fnm);
 +    opt.bTauIntGiven=opt2bSet("-iiact",NFILE,fnm);
 +    if  (opt.bTab && opt.bPullf)
 +        gmx_fatal(FARGS,"Force input does not work with tabulated potentials. "
 +                  "Provide pullx.xvg or pdo files!");
 +
 +    if (!opt.bPdo && !WHAMBOOLXOR(opt.bPullx,opt.bPullf))
 +        gmx_fatal(FARGS,"Give either pullx (-ix) OR pullf (-if) data. Not both.");
 +    if ( !opt.bPdo && !(opt.bTpr || opt.bPullf || opt.bPullx))
 +        gmx_fatal(FARGS,"g_wham supports three input modes, pullx, pullf, or pdo file input."
 +                  "\n\n Check g_wham -h !");
 +  
 +    opt.fnPdo=opt2fn("-ip",NFILE,fnm);
 +    opt.fnTpr=opt2fn("-it",NFILE,fnm);
 +    opt.fnPullf=opt2fn("-if",NFILE,fnm);
 +    opt.fnPullx=opt2fn("-ix",NFILE,fnm);
 +    opt.fnGroupsel=opt2fn_null("-is",NFILE,fnm);
 +
 +    bMinSet = opt2parg_bSet("-min",  asize(pa), pa);
 +    bMaxSet = opt2parg_bSet("-max",  asize(pa), pa);
 +    bAutoSet = opt2parg_bSet("-auto",  asize(pa), pa);
 +    if ( (bMinSet || bMaxSet) && bAutoSet)
 +        gmx_fatal(FARGS,"With -auto, do not give -min or -max\n");
 +
 +    if ( (bMinSet && !bMaxSet) || (!bMinSet && bMaxSet))
 +        gmx_fatal(FARGS,"When giving -min, you must give -max (and vice versa), too\n");
 +
 +    if (bMinSet && opt.bAuto)
 +    {
 +        printf("Note: min and max given, switching off -auto.\n");
 +        opt.bAuto=FALSE;
 +    }
 +
 +    if (opt.bTauIntGiven && opt.bCalcTauInt)
 +        gmx_fatal(FARGS,"Either read (option -iiact) or calculate (option -ac) the\n"
 +                  "the autocorrelation times. Not both.");
 +
 +    if (opt.tauBootStrap>0.0 && opt2parg_bSet("-ac",asize(pa), pa))
 +        gmx_fatal(FARGS,"Either compute autocorrelation times (ACTs) (option -ac) or "
 +                  "provide it with -bs-tau for bootstrapping. Not Both.\n");
 +    if (opt.tauBootStrap>0.0 && opt2bSet("-iiact",NFILE,fnm))
 +        gmx_fatal(FARGS,"Either provide autocorrelation times (ACTs) with file iact-in.dat "
 +                  "(option -iiact) or define all ACTs with -bs-tau for bootstrapping\n. Not Both.");
 +  
 +    /* Reading gmx4 pull output and tpr files */
 +    if (opt.bTpr || opt.bPullf || opt.bPullx)
 +    {
 +        read_wham_in(opt.fnTpr,&fninTpr,&nfiles,&opt);
 +    
 +        fnPull=opt.bPullf ? opt.fnPullf : opt.fnPullx;
 +        read_wham_in(fnPull,&fninPull,&nfiles2,&opt);
 +        printf("Found %d tpr and %d pull %s files in %s and %s, respectively\n",
 +               nfiles,nfiles2,opt.bPullf ? "force" : "position",opt.fnTpr,fnPull);
 +        if (nfiles!=nfiles2)
 +            gmx_fatal(FARGS,"Found %d file names in %s, but %d in %s\n",nfiles,
 +                      opt.fnTpr,nfiles2,fnPull);
 +
 +        /* Read file that selects the pull group to be used */
 +        if (opt.fnGroupsel != NULL)
 +            readPullGroupSelection(&opt,fninTpr,nfiles);
 +
 +        window=initUmbrellaWindows(nfiles);
 +        read_tpr_pullxf_files(fninTpr,fninPull,nfiles, &header, window, &opt);
 +    }
 +    else
 +    { /* reading pdo files */
 +        if  (opt.fnGroupsel != NULL)
 +            gmx_fatal(FARGS,"Reading a -is file is not supported with PDO input files.\n"
 +                      "Use awk or a similar tool to pick the required pull groups from your PDO files\n");
 +        read_wham_in(opt.fnPdo,&fninPdo,&nfiles,&opt);
 +        printf("Found %d pdo files in %s\n",nfiles,opt.fnPdo);
 +        window=initUmbrellaWindows(nfiles);
 +        read_pdo_files(fninPdo,nfiles, &header, window, &opt);
 +    }
 +    nwins=nfiles;  
 +
 +    /* enforce equal weight for all histograms? */
 +    if (opt.bHistEq)
 +        enforceEqualWeights(window,nwins);
 +
 +    /* write histograms */
 +    histout=xvgropen(opt2fn("-hist",NFILE,fnm),"Umbrella histograms",
 +                     "z","count",opt.oenv);
 +    for(l=0;l<opt.bins;++l) 
 +    {
 +        fprintf(histout,"%e\t",(double)(l+0.5)/opt.bins*(opt.max-opt.min)+opt.min);
 +        for(i=0;i<nwins;++i) 
 +        {      
 +            for(j=0;j<window[i].nPull;++j) 
 +            {
 +                fprintf(histout,"%e\t",window[i].Histo[j][l]);
 +            }
 +        }
 +        fprintf(histout,"\n");
 +    }
 +    ffclose(histout);
 +    printf("Wrote %s\n",opt2fn("-hist",NFILE,fnm));
 +    if (opt.bHistOnly)
 +    {
 +        printf("Wrote histograms to %s, now exiting.\n",opt2fn("-hist",NFILE,fnm));
 +        return 0;
 +    }
 +
 +    /* Using tabulated umbrella potential */
 +    if (opt.bTab)
 +        setup_tab(opt2fn("-tab",NFILE,fnm),&opt);
 +  
 +    /* Integrated autocorrelation times provided ? */
 +    if (opt.bTauIntGiven)
 +        readIntegratedAutocorrelationTimes(window,nwins,&opt,opt2fn("-iiact",NFILE,fnm));
 +
 +    /* Compute integrated autocorrelation times */
 +    if (opt.bCalcTauInt)
 +        calcIntegratedAutocorrelationTimes(window,nwins,&opt,opt2fn("-oiact",NFILE,fnm));
 +
 +    /* calc average and sigma for each histogram 
 +       (maybe required for bootstrapping. If not, this is fast anyhow) */
 +    if (opt.nBootStrap && opt.bsMethod==bsMethod_trajGauss)
 +        averageSigma(window,nwins,&opt);
 +  
 +    /* Get initial potential by simple integration */
 +    if (opt.bInitPotByIntegration)
 +        guessPotByIntegration(window,nwins,&opt,0);  
 +
 +    /* Check if complete reaction coordinate is covered */
 +    checkReactionCoordinateCovered(window,nwins,&opt);
 +
 +    /* Calculate profile */
 +    snew(profile,opt.bins);  
 +    if (opt.verbose)
 +        opt.stepchange=1;
 +    i=0;
 +    do 
 +    {
 +        if ( (i%opt.stepUpdateContrib) == 0)
 +            setup_acc_wham(profile,window,nwins,&opt);
 +        if (maxchange<opt.Tolerance)
 +        {
 +            bExact=TRUE;
 +            /* if (opt.verbose) */
 +            printf("Switched to exact iteration in iteration %d\n",i);
 +        }
 +        calc_profile(profile,window,nwins,&opt,bExact);
 +        if (((i%opt.stepchange) == 0 || i==1) && !i==0)
 +            printf("\t%4d) Maximum change %e\n",i,maxchange);
 +        i++;
 +    } while ( (maxchange=calc_z(profile, window, nwins, &opt,bExact)) > opt.Tolerance || !bExact);
 +    printf("Converged in %d iterations. Final maximum change %g\n",i,maxchange);
 +
 +    /* calc error from Kumar's formula */
 +    /* Unclear how the error propagates along reaction coordinate, therefore
 +       commented out  */
 +    /* calc_error_kumar(profile,window, nwins,&opt); */
 +
 +    /* Write profile in energy units? */
 +    if (opt.bLog)
 +    {
 +        prof_normalization_and_unit(profile,&opt);
 +        strcpy(ylabel,en_unit_label[opt.unit]);
 +        strcpy(title,"Umbrella potential");
 +    }
 +    else
 +    {
 +        strcpy(ylabel,"Density of states");
 +        strcpy(title,"Density of states");
 +    }
 +    
 +    /* symmetrize profile around z=0? */
 +    if (opt.bSym)
 +        symmetrizeProfile(profile,&opt);
 +
 +    /* write profile or density of states */
 +    profout=xvgropen(opt2fn("-o",NFILE,fnm),title,"z",ylabel,opt.oenv);
 +    for(i=0;i<opt.bins;++i)
 +        fprintf(profout,"%e\t%e\n",(double)(i+0.5)/opt.bins*(opt.max-opt.min)+opt.min,profile[i]);
 +    ffclose(profout);
 +    printf("Wrote %s\n",opt2fn("-o",NFILE,fnm));
 +  
 +    /* Bootstrap Method */
 +    if (opt.nBootStrap)
 +        do_bootstrapping(opt2fn("-bsres",NFILE,fnm),opt2fn("-bsprof",NFILE,fnm), 
 +                         opt2fn("-hist",NFILE,fnm),
 +                         ylabel, profile, window, nwins, &opt);
 +
 +    sfree(profile);
 +    freeUmbrellaWindows(window,nfiles);
 +
 +    printf("\nIn case you use results from g_wham for a publication, please cite:\n");
 +    please_cite(stdout,"Hub2010");
 +
 +    thanx(stderr);
 +    return 0;
 +}